summaryrefslogtreecommitdiff
path: root/Radio/HW/BladeRF/common
diff options
context:
space:
mode:
Diffstat (limited to 'Radio/HW/BladeRF/common')
-rw-r--r--Radio/HW/BladeRF/common/include/conversions.h409
-rw-r--r--Radio/HW/BladeRF/common/include/dc_calibration.h151
-rw-r--r--Radio/HW/BladeRF/common/include/devcfg.h151
-rw-r--r--Radio/HW/BladeRF/common/include/host_config.h333
-rw-r--r--Radio/HW/BladeRF/common/include/host_config.h.in333
-rw-r--r--Radio/HW/BladeRF/common/include/iterators.h59
-rw-r--r--Radio/HW/BladeRF/common/include/log.h144
-rw-r--r--Radio/HW/BladeRF/common/include/logger_id.h61
-rw-r--r--Radio/HW/BladeRF/common/include/minmax.h65
-rw-r--r--Radio/HW/BladeRF/common/include/osx/clock_gettime.h52
-rw-r--r--Radio/HW/BladeRF/common/include/parse.h112
-rw-r--r--Radio/HW/BladeRF/common/include/range.h54
-rw-r--r--Radio/HW/BladeRF/common/include/rel_assert.h14
-rw-r--r--Radio/HW/BladeRF/common/include/sha256.h61
-rw-r--r--Radio/HW/BladeRF/common/include/str_queue.h93
-rw-r--r--Radio/HW/BladeRF/common/include/thread.h74
-rw-r--r--Radio/HW/BladeRF/common/src/conversions.c730
-rw-r--r--Radio/HW/BladeRF/common/src/dc_calibration.c1745
-rw-r--r--Radio/HW/BladeRF/common/src/devcfg.c638
-rw-r--r--Radio/HW/BladeRF/common/src/log.c98
-rw-r--r--Radio/HW/BladeRF/common/src/osx/clock_gettime.c59
-rw-r--r--Radio/HW/BladeRF/common/src/parse.c455
-rw-r--r--Radio/HW/BladeRF/common/src/range.c74
-rw-r--r--Radio/HW/BladeRF/common/src/sha256.c343
-rw-r--r--Radio/HW/BladeRF/common/src/str_queue.c193
-rw-r--r--Radio/HW/BladeRF/common/src/windows/clock_gettime.c58
-rw-r--r--Radio/HW/BladeRF/common/src/windows/getopt_long.c326
-rw-r--r--Radio/HW/BladeRF/common/src/windows/gettimeofday.c49
-rw-r--r--Radio/HW/BladeRF/common/src/windows/mkdtemp.c250
-rw-r--r--Radio/HW/BladeRF/common/src/windows/nanosleep.c41
-rw-r--r--Radio/HW/BladeRF/common/src/windows/setenv.c50
-rw-r--r--Radio/HW/BladeRF/common/thirdparty/ad936x/ad9361.c7218
-rw-r--r--Radio/HW/BladeRF/common/thirdparty/ad936x/ad9361.h3521
-rw-r--r--Radio/HW/BladeRF/common/thirdparty/ad936x/ad9361_api.c2126
-rw-r--r--Radio/HW/BladeRF/common/thirdparty/ad936x/ad9361_api.h506
-rw-r--r--Radio/HW/BladeRF/common/thirdparty/ad936x/ad9361_conv.c751
-rw-r--r--Radio/HW/BladeRF/common/thirdparty/ad936x/common.h100
-rw-r--r--Radio/HW/BladeRF/common/thirdparty/ad936x/util.c347
-rw-r--r--Radio/HW/BladeRF/common/thirdparty/ad936x/util.h186
39 files changed, 22030 insertions, 0 deletions
diff --git a/Radio/HW/BladeRF/common/include/conversions.h b/Radio/HW/BladeRF/common/include/conversions.h
new file mode 100644
index 0000000..5555a29
--- /dev/null
+++ b/Radio/HW/BladeRF/common/include/conversions.h
@@ -0,0 +1,409 @@
+/*
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (C) 2014-2018 Nuand LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef CONVERSIONS_H_
+#define CONVERSIONS_H_
+
+#include <errno.h>
+#include <libbladeRF.h>
+#include <limits.h>
+#include <math.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "host_config.h"
+#include "rel_assert.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Convert a string to a bladerf_version
+ *
+ * Accepted inputs are in the form: X.Y.Z or X.Y.Z-<extra text>
+ *
+ * @param[in] string Version string to convert
+ * @param[out] version Version structure to populate. For a valid string,
+ * the describe member will point to the provided
+ * string argument. The contents of this structure
+ * are undefined when this function returns -1.
+ *
+ * @return 0 on success, -1 if provided string is invalid
+ */
+int str2version(const char *str, struct bladerf_version *version);
+
+/**
+ * Convert a bladerf_dev_speed to a string suitable for printing
+ *
+ * @note The caller should not attempt to modify or free() the returned string.
+ *
+ * @param speed Device speed
+ * @return Const string describing the provided speed
+ */
+const char *devspeed2str(bladerf_dev_speed speed);
+
+/**
+ * Convert a string to libbladeRF log verbosity level
+ *
+ * @param[in] str Input string
+ * @param[out] ok Value is updated to true if the input string was valid
+ *
+ * @return Log level if ok is true, undefined otherwise
+ */
+bladerf_log_level str2loglevel(const char *str, bool *ok);
+
+/**
+ * Convert a module enumeration to a string
+ *
+ * @note The caller should not attempt to modify or free() the returned string.
+ *
+ * @param module Module to convert to string
+ * @return String representation of module
+ */
+const char *module2str(bladerf_module m);
+
+/**
+ * Convert a string to a module enumeration value.
+ *
+ * This is case-insensitive.
+ *
+ * @param str Module as a string. Should be "rx" or "tx".
+ *
+ * @return BLADERF_MODULE_RX, BLADERF_MODULE_TX, or BLADERF_MODULE_INVALID
+ */
+bladerf_module str2module(const char *str);
+
+/**
+ * Convert a channel index to a string
+ *
+ * @note The caller should not attempt to modify or free() the returned string.
+ *
+ * @param ch Channel
+ * @return String representation of channel
+ */
+const char *channel2str(bladerf_channel ch);
+
+/**
+ * Convert a string to a channel index
+ *
+ * This is case-insensitive.
+ *
+ * @param str Channel as a string.
+ * @return BLADERF_CHANNEL_RX(n) or BLADERF_CHANNEL_TX(n),
+ * or BLADERF_CHANNEL_INVALID if not recognized
+ */
+bladerf_channel str2channel(char const *str);
+
+/**
+ * Convert a direction enumeration to a string
+ *
+ * @note The caller should not attempt to modify or free() the returned string.
+ *
+ * @param dir direction
+ * @return String representation of direction
+ */
+const char *direction2str(bladerf_direction dir);
+
+/**
+ * Convert a channel enumeration to a direction
+ *
+ * @param ch channel
+ * @return Direction of the channel
+ */
+bladerf_direction channel2direction(bladerf_channel ch);
+
+/**
+ * Convert a trigger signal enumeration value to a string
+ *
+ * @param trigger Trigger item
+ *
+ * @return String representation or "Unknown"
+ */
+const char *trigger2str(bladerf_trigger_signal trigger);
+
+/**
+ * Conver a string to a trigger signal enumeration value.
+ *
+ * This is case-insensitive.
+ *
+ * @param str Trigger as a string. Valid values include `Miniexp-1`,
+ * `J51-1`, `J71-4`, or `User-0` through `User-7`.
+ *
+ * @return valid bladerf_trigger_signal value, or BLADERF_TRIGGER_INVALID
+ */
+bladerf_trigger_signal str2trigger(const char *str);
+
+/**
+ * Convert a trigger role enumeration value to a string
+ *
+ * @param role Role value
+ *
+ * @return String representation or "Unknown"
+ */
+const char *triggerrole2str(bladerf_trigger_role role);
+
+/**
+ * Convert a string to a trigger role enumeration value
+ *
+ * @param role Role value
+ *
+ * @return String representation or "Unknown"
+ */
+bladerf_trigger_role str2triggerrole(const char *str);
+
+/**
+ * Convert a string to a loopback mode
+ *
+ * @param[in] str String to convert
+ * @param[out] loopback Corresponding loopback mode. Only valid when
+ * this function returns successfully
+ *
+ * @return 0 on success, -1 on invalid string
+ */
+int str2loopback(const char *str, bladerf_loopback *loopback);
+
+/**
+ * @brief Convert a loopback mode to a string const
+ *
+ * @param[in] loopback The loopback mode
+ *
+ * @return NUL-terminated string
+ */
+char const *loopback2str(bladerf_loopback loopback);
+
+/**
+ * Convert RX LNA gain strings to their associated enum values
+ *
+ * @param[in] str Gain string to convert
+ * @param[out] gain Associated LNA gain string. Set to
+ * BLADERF_LNA_GAIN_UNKNOWN on error.
+ *
+ * @return 0 on success, -1 on invalid string
+ */
+int str2lnagain(const char *str, bladerf_lna_gain *gain);
+
+/**
+ * @brief Convert a tuning mode to a string const
+ *
+ * @param[in] mode The tuning mode
+ *
+ * @return NUL-terminated string
+ */
+char const *tuningmode2str(bladerf_tuning_mode mode);
+
+/**
+ * Get a string description of the specified bladeRF backend
+ *
+ * @param b Backend to get a string for
+ *
+ * @return NUL-terminated string
+ */
+const char *backend_description(bladerf_backend b);
+
+/**
+ * Convert bladeRF SC16Q11 DAC/ADC samples to floats
+ *
+ * Note that the both the input and output buffers contain interleaved, where
+ * 1 sample is associated with two array elements:
+ * [I, Q, I, Q, ... I, Q]
+ *
+ * Therefore, the caller must ensure the output buffer large enough to contain
+ * 2*n floats (or 2*n*sizeof(float) bytes).
+ *
+ * @param[in] in Input buffer containing SC16Q11 samples
+ * @param[out] out Output buffer of float values
+ * @param[in] n Number of samples to convert
+ */
+void sc16q11_to_float(const int16_t *in, float *out, unsigned int n);
+
+/**
+ * Convert float samples to bladeRF SC16Q11 DAC/ADC format
+ *
+ * Note that the both the input and output buffers contain interleaved, where
+ * 1 sample is associated with two array elements:
+ * [I, Q, I, Q, ... I, Q]
+ *
+ * Therefore, the caller must ensure the output buffer large enough to contain
+ * 2*n int16_t's (or 2*n*sizeof(int16_t) bytes).
+ *
+ * @param[in] in Input buffer containing float samples
+ * @param[out] out Output buffer of int16_t values
+ * @param[in] n Number of samples to convert
+ */
+void float_to_sc16q11(const float *in, int16_t *out, unsigned int n);
+
+/**
+ * Convert a string to a bladerf_cal_module value
+ *
+ * @param[in] str String to convert
+ *
+ * @return A bladerf_cal_module value. This will be set to
+ * BLADERF_DC_CAL_INVALID if the provided string is invalid.
+ */
+bladerf_cal_module str_to_bladerf_cal_module(const char *str);
+
+/**
+ * Convert a bladerf_smb_mode enumeration value to a string
+ *
+ * @param[in] mode Mode enum value
+ *
+ * @return String representation of enumeration, or "Unknown" for an
+ * invalid value.
+ */
+const char *smb_mode_to_str(bladerf_smb_mode mode);
+
+/**
+ * Convert a string to bladerf_smb_mode value
+ *
+ * @param[in] str String to convert
+ *
+ * @return A BLADERF_SMB_MODE_* value. BLADERF_SMB_MODE_INVALID will
+ * returned for an invalid string.
+ */
+bladerf_smb_mode str_to_smb_mode(const char *str);
+
+/**
+ * Convert a string to bladerf_tuning_mode value
+ *
+ * @param[in] str String to convert
+ *
+ * @return A BLADERF_TUNING_MODE_* value. BLADERF_TUNING_MODE_INVALID will
+ * returned for an invalid string.
+ */
+bladerf_tuning_mode str_to_tuning_mode(const char *str);
+
+/**
+ * Convert an ASCII char string to an unsigned integer and check its bounds
+ *
+ * @param[in] str String to convert
+ * @param[in] min Value below this is bad
+ * @param[in] max Value above this is bad
+ * @param[out] ok True if conversion and bounds check did not fail
+ *
+ * @return An unsigned integer converted from an ASCII string
+ */
+unsigned int str2uint(const char *str,
+ unsigned int min,
+ unsigned int max,
+ bool *ok);
+
+/**
+ * Convert an ASCII char string to an integer and check its bounds
+ *
+ * @param[in] str String to convert
+ * @param[in] min Value below this is bad
+ * @param[in] max Value above this is bad
+ * @param[out] ok True if conversion and bounds check did not fail
+ *
+ * @return A signed integer converted from an ASCII string
+ */
+int str2int(const char *str, int min, int max, bool *ok);
+
+/**
+ * Convert an ASCII char string to a 64bit unsigned long long integer and check
+ * its bounds
+ *
+ * @param[in] str String to convert
+ * @param[in] min Value below this is bad
+ * @param[in] max Value above this is bad
+ * @param[out] ok True if conversion and bounds check did not fail
+ *
+ * @return An unsigned long long integer converted from an ASCII string
+ */
+uint64_t str2uint64(const char *str, uint64_t min, uint64_t max, bool *ok);
+
+/**
+ * Convert an ASCII char string to a double and check its bounds
+ *
+ * @param[in] str String to convert
+ * @param[in] min Value below this is bad
+ * @param[in] max Value above this is bad
+ * @param[out] ok True if conversion and bounds check did not fail
+ *
+ * @return A double converted from an ASCII string
+ */
+double str2double(const char *str, double min, double max, bool *ok);
+struct numeric_suffix {
+ const char *suffix;
+ uint64_t multiplier;
+};
+typedef struct numeric_suffix numeric_suffix;
+
+/**
+ * Convert an ASCII char string that has a suffix multipler to an unsigned
+ * integer and check its bounds
+ *
+ * @param[in] str String to convert
+ * @param[in] min Value below this is bad
+ * @param[in] max Value above this is bad
+ * @param[in] suffixes Array of numeric_suffix
+ * @param[in] num_suff Total number of numeric_suffix in suffixes array
+ * @param[out] ok True if conversion and bounds check did not fail
+ *
+ * @return An unsigned integer converted from an ASCII string
+ */
+unsigned int str2uint_suffix(const char *str,
+ unsigned int min,
+ unsigned int max,
+ const struct numeric_suffix *suffixes,
+ const size_t num_suff,
+ bool *ok);
+
+/**
+ * Convert an ASCII char string that has a suffix multipler to an unsigned
+ * integer and check its bounds
+ *
+ * @param[in] str String to convert
+ * @param[in] min Value below this is bad
+ * @param[in] max Value above this is bad
+ * @param[in] suffixes Array of numeric_suffix
+ * @param[in] num_suff Total number of numeric_suffix in suffixes array
+ * @param[out] ok True if conversion and bounds check did not fail
+ *
+ * @return An unsigned long long integer converted from an ASCII string
+ */
+uint64_t str2uint64_suffix(const char *str,
+ uint64_t min,
+ uint64_t max,
+ const struct numeric_suffix *suffixes,
+ const size_t num_suff,
+ bool *ok);
+
+/**
+ * Convert a string to a boolean
+ *
+ * @param[in] str String to convert
+ * @param[out] val Boolean value
+ *
+ * @return 0 on success, value from \ref RETCODES list on failure
+ */
+int str2bool(const char *str, bool *val);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/Radio/HW/BladeRF/common/include/dc_calibration.h b/Radio/HW/BladeRF/common/include/dc_calibration.h
new file mode 100644
index 0000000..7259292
--- /dev/null
+++ b/Radio/HW/BladeRF/common/include/dc_calibration.h
@@ -0,0 +1,151 @@
+/**
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (c) 2015 Nuand LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* This file provides DC calibration routines that utilize libbladeRF */
+
+#ifndef DC_CALIBRATION_H_
+#define DC_CALIBRATION_H_
+
+#include <libbladeRF.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct dc_calibration_params {
+ uint64_t frequency;
+ int16_t corr_i;
+ int16_t corr_q;
+ float error_i;
+ float error_q;
+
+ int16_t max_dc_i;
+ int16_t max_dc_q;
+ int16_t mid_dc_i;
+ int16_t mid_dc_q;
+ int16_t min_dc_i;
+ int16_t min_dc_q;
+};
+
+/**
+ * Calibrate the specified LMS6002D module.
+ *
+ * Generally, one should run all of these calibrations prior to executing the RX
+ * and TX auto calibration routines.
+ *
+ * Streams should not be running when attempting to call this function.
+ *
+ * Below are the case-insensitive options for the LMS6002D `module` string:
+ * - LPF Tuning: "lpf_tuning", "lpftuning", "tuning"
+ * - TX LPF: "tx_lpf", "txlpf"
+ * - RX LPF: "rx_lpf", "rxlpf"
+ * - RX VGA2 "rx_vga2", "rxvga2"
+ * - All of the above: "all"
+ *
+ * @param dev bladeRF device handle
+ * @param module LMS6002D module to calibrate. Passing NULL is synonymous
+ * with specifying "ALL".
+ *
+ * @return 0 on success or libbladeRF return value on failure.
+ * BLADERF_ERR_INVAL is returned if `module` is invalid.
+ */
+int dc_calibration_lms6(struct bladerf *dev, const char *module);
+
+/**
+ * Perform DC offset calbration of the RX path. Neither RX or TX should be
+ * used during this procedure, as the TX frequency may be adjusted to ensure
+ * good results are obtained.
+ *
+ * The RX input should be disconected from any input sources or antennas when
+ * performing this calibration.
+ *
+ * @pre dc_calibration_lms6() should have been called for all modules prior to
+ * using this function.
+ *
+ * @param[in] dev bladeRF device handle
+ *
+ * @param[inout] params DC calibration input and output parameters. This
+ * list should be populated to describe the
+ * frequencies over which to calibrate. The
+ * `corr_i` and `corr_q` fields will be filled in
+ * for each entry.
+ *
+ * @param[in] num_params Number of entries in the `params` list.
+ *
+ * @param[in] show_status Print status information to stdout
+ *
+ * @return 0 on success or libbladeRF return value on failure.
+ */
+int dc_calibration_rx(struct bladerf *dev,
+ struct dc_calibration_params *params,
+ size_t num_params, bool show_status);
+
+/**
+ * Perform DC offset calbration of the TX path.
+ *
+ * This requires use of both RX and TX modules in an internal loopback mode;
+ * neither should be in use when this function is called. It should not
+ * be neccessary to disconnect the RX and TX ports, but it is still recommended,
+ * just to err on the side of caution.
+ *
+ * @pre dc_calibration_lms6() should have been called for all modules prior to
+ * using this function.
+ *
+ * @param dev bladeRF device handle
+ *
+ * @return 0 on success or libbladeRF return value on failure.
+ */
+int dc_calibration_tx(struct bladerf *dev,
+ struct dc_calibration_params *params,
+ size_t num_params, bool show_status);
+
+/**
+ * Convenience wrapper around dc_cal_rx() and dc_cal_tx()
+ *
+ * @pre dc_calibration_lms6() should have been called for all modules prior to
+ * using this function.
+ *
+ * @param[in] dev Device handle
+ * @param[in] module BLADERF_MODULE_RX or BLADERF_MODULE_TX
+ * @param[inout] params DC calibration input and output parameters. This
+ * list should be populated to describe the
+ * frequencies over which to calibrate. The
+ * `corr_i` and `corr_q` fields will be filled in
+ * for each entry.
+ *
+ * @param[in] num_params Number of entries in the `params` list.
+ * @param[in] show_status Print status information to stdout
+ *
+ * @return 0 on success or libbladeRF return value on failure.
+ */
+int dc_calibration(struct bladerf *dev, bladerf_module module,
+ struct dc_calibration_params *params,
+ size_t num_params, bool show_status);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/Radio/HW/BladeRF/common/include/devcfg.h b/Radio/HW/BladeRF/common/include/devcfg.h
new file mode 100644
index 0000000..3ebf837
--- /dev/null
+++ b/Radio/HW/BladeRF/common/include/devcfg.h
@@ -0,0 +1,151 @@
+/*
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (C) 2014-2015 Nuand LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef DEVCFG_H_
+#define DEVCFG_H_
+
+#include <stdint.h>
+#include <libbladeRF.h>
+
+#include "rel_assert.h"
+#include "host_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DEVCFG_OPTIONS_BASE "hd:l:v:s:b:f:"
+
+/**
+ * Device configuration parameters
+ */
+struct devcfg {
+ char *device_specifier;
+
+ unsigned int tx_frequency;
+ unsigned int tx_bandwidth;
+ unsigned int tx_samplerate;
+ int txvga1;
+ int txvga2;
+
+ unsigned int rx_frequency;
+ unsigned int rx_bandwidth;
+ unsigned int rx_samplerate;
+ bladerf_lna_gain lnagain;
+ int rxvga1;
+ int rxvga2;
+
+ bladerf_loopback loopback;
+
+ bladerf_log_level verbosity;
+
+ bool enable_xb200;
+
+ unsigned int samples_per_buffer;
+ unsigned int num_buffers;
+ unsigned int num_transfers;
+ unsigned int stream_timeout_ms;
+ unsigned int sync_timeout_ms;
+};
+
+/**
+ * Initialize the specified device_config structure to default values
+ *
+ * @param c Configuration to initialize
+ */
+void devcfg_init(struct devcfg *c);
+
+/**
+ * Deinitialize any items allocated in the provided device configuration
+ *
+ * @param c Configuration to deinitialize
+ */
+void devcfg_deinit(struct devcfg *c);
+
+/**
+ * Creates an option array with the app-specific options appended to the common
+ * devcfg options. The app_options should be 0-terminated.
+ *
+ * The caller is responsible for freeing the resturned structure.
+ *
+ * @return Heap-allocated array on success, NULL on failure
+ */
+struct option *devcfg_get_long_options(const struct option *app_options);
+
+/**
+ * Handle command line arguments and update the specified device configuration
+ * accordingly.
+ *
+ * @param argc # of arguments in argv
+ * @param argv Array of arguments
+ *
+ * @param option_str Options string to pass to getopt_long(). This should
+ * include DEVCFG_OPTIONS_BASE, with any
+ * application-handled options appended.
+ *
+ * @param long_options List of long options created by caller
+ *
+ * @param c Device configuration to update. It should have
+ * already been initialized via devcfg_init()
+ *
+ * @return 0 on success, -1 on failure, 1 if help is requested
+ */
+int devcfg_handle_args(int argc, char **argv,
+ const char *options, const struct option *long_options,
+ struct devcfg *c);
+
+/**
+ * Wrapper around bladerf_sync_config, using parameters in the specified
+ * devcfg. Optionally, enable the associated module.
+ */
+int devcfg_perform_sync_config(struct bladerf *dev,
+ bladerf_module module,
+ bladerf_format format,
+ const struct devcfg *config,
+ bool enable_module);
+
+
+/**
+ * Apply the provided device_config to the specified device
+ *
+ * @param dev Device to configure
+ * @param c Configuration parameters
+ *
+ * @return 0 on succes, -1 on failure
+ */
+int devcfg_apply(struct bladerf *dev, const struct devcfg *c);
+
+/**
+ * Print help info about arguments handled by devcfg_handle_args()
+ *
+ * @param title Optional title to print before usage information
+ */
+void devcfg_print_common_help(const char *title);
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/Radio/HW/BladeRF/common/include/host_config.h b/Radio/HW/BladeRF/common/include/host_config.h
new file mode 100644
index 0000000..15dded3
--- /dev/null
+++ b/Radio/HW/BladeRF/common/include/host_config.h
@@ -0,0 +1,333 @@
+/**
+ * @file host_config.h.in
+ *
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (c) 2013-2018 Nuand LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef HOST_CONFIG_H__
+#define HOST_CONFIG_H__
+
+#define BLADERF_OS_LINUX 0
+#define BLADERF_OS_FREEBSD 0
+#define BLADERF_OS_OSX 1
+#define BLADERF_OS_WINDOWS 0
+#define BLADERF_BIG_ENDIAN 0
+
+#if !(BLADERF_OS_LINUX || BLADERF_OS_OSX || BLADERF_OS_WINDOWS || BLADERF_OS_FREEBSD)
+# error "Build not configured for any supported operating systems"
+#endif
+
+#if 1 < (BLADERF_OS_LINUX + BLADERF_OS_OSX + BLADERF_OS_WINDOWS + BLADERF_OS_FREEBSD)
+#error "Build configured for multiple operating systems"
+#endif
+
+#define HAVE_CLOCK_GETTIME 1
+
+/*******************************************************************************
+ * Endianness conversions
+ *
+ * HOST_TO_LE16 16-bit host endianness to little endian conversion
+ * LE16_TO_HOST 16-bit little endian to host endianness conversion
+ * HOST_TO_BE16 16-bit host endianness to big endian conversion
+ * BE16_TO_HOST 16-bit big endian to host endianness conversion
+ * HOST_TO_LE32 32-bit host endianness to little endian conversion
+ * LE32_TO_HOST 32-bit little endian to host endianness conversion
+ * HOST_TO_BE32 32-bit host endianness to big endian conversion
+ * BE32_TO_HOST 32-bit big endian to host endianness conversion
+ * HOST_TO_BE64 64-bit host endianness to big endian conversion
+ * BE64_TO_HOST 64-bit big endian to host endianness conversion
+ ******************************************************************************/
+
+/*-----------------------
+ * Linux
+ *---------------------*/
+#if BLADERF_OS_LINUX
+#include <endian.h>
+
+#define HOST_TO_LE16(val) htole16(val)
+#define LE16_TO_HOST(val) le16toh(val)
+#define HOST_TO_BE16(val) htobe16(val)
+#define BE16_TO_HOST(val) be16toh(val)
+
+#define HOST_TO_LE32(val) htole32(val)
+#define LE32_TO_HOST(val) le32toh(val)
+#define HOST_TO_BE32(val) htobe32(val)
+#define BE32_TO_HOST(val) be32toh(val)
+
+#define HOST_TO_LE64(val) htole64(val)
+#define LE64_TO_HOST(val) le64toh(val)
+#define HOST_TO_BE64(val) be64toh(val)
+#define BE64_TO_HOST(val) be64toh(val)
+
+/*-----------------------
+ * FREEBSD
+ *---------------------*/
+#elif BLADERF_OS_FREEBSD
+#include <sys/endian.h>
+
+#define HOST_TO_LE16(val) htole16(val)
+#define LE16_TO_HOST(val) le16toh(val)
+#define HOST_TO_BE16(val) htobe16(val)
+#define BE16_TO_HOST(val) be16toh(val)
+
+#define HOST_TO_LE32(val) htole32(val)
+#define LE32_TO_HOST(val) le32toh(val)
+#define HOST_TO_BE32(val) htobe32(val)
+#define BE32_TO_HOST(val) be32toh(val)
+
+#define HOST_TO_LE64(val) htole64(val)
+#define LE64_TO_HOST(val) le64toh(val)
+#define HOST_TO_BE64(val) be64toh(val)
+#define BE64_TO_HOST(val) be64toh(val)
+
+/*-----------------------
+ * Apple OSX
+ *---------------------*/
+#elif BLADERF_OS_OSX
+#include <libkern/OSByteOrder.h>
+
+#define HOST_TO_LE16(val) OSSwapHostToLittleInt16(val)
+#define LE16_TO_HOST(val) OSSwapLittleToHostInt16(val)
+#define HOST_TO_BE16(val) OSSwapHostToBigInt16(val)
+#define BE16_TO_HOST(val) OSSwapBigToHostInt16(val)
+
+#define HOST_TO_LE32(val) OSSwapHostToLittleInt32(val)
+#define LE32_TO_HOST(val) OSSwapLittleToHostInt32(val)
+#define HOST_TO_BE32(val) OSSwapHostToBigInt32(val)
+#define BE32_TO_HOST(val) OSSwapBigToHostInt32(val)
+
+#define HOST_TO_LE64(val) OSSwapHostToLittleInt64(val)
+#define LE64_TO_HOST(val) OSSwapLittleToHostInt64(val)
+#define HOST_TO_BE64(val) OSSwapHostToBigInt64(val)
+#define BE64_TO_HOST(val) OSSwapBigToHostInt64(val)
+
+/*-----------------------
+ * Windows
+ *---------------------*/
+#elif BLADERF_OS_WINDOWS
+#include <intrin.h>
+
+/* We'll assume little endian for Windows platforms:
+ * http://blogs.msdn.com/b/larryosterman/archive/2005/06/07/426334.aspx
+ */
+#define HOST_TO_LE16(val) (val)
+#define LE16_TO_HOST(val) (val)
+#define HOST_TO_BE16(val) _byteswap_ushort(val)
+#define BE16_TO_HOST(val) _byteswap_ushort(val)
+
+#define HOST_TO_LE32(val) (val)
+#define LE32_TO_HOST(val) (val)
+#define HOST_TO_BE32(val) _byteswap_ulong(val)
+#define BE32_TO_HOST(val) _byteswap_ulong(val)
+
+
+#define HOST_TO_LE64(val) (val)
+#define LE64_TO_HOST(val) (val)
+#define HOST_TO_BE64(val) _byteswap_uint64(val)
+#define BE64_TO_HOST(val) _byteswap_uint64(val)
+
+/*-----------------------
+ * Unsupported or bug
+ *---------------------*/
+#else
+#error "Encountered an OS that we do not have endian wrappers for?"
+#endif
+
+/*******************************************************************************
+ * Endianness conversions for constants
+ *
+ * We shouldn't be using the above items for assigning constants because the
+ * implementations may be functions [1].
+ *
+ * [1] https://sourceware.org/bugzilla/show_bug.cgi?id=17679#c7
+ ******************************************************************************/
+
+#define BLADERF_BYTESWAP16(x) ((((x) & 0xff00) >> 8) | (((x) & 0x00ff) << 8))
+
+#define BLADERF_BYTESWAP32(x) ((((x) & 0xff000000) >> 24) | \
+ (((x) & 0x00ff0000) >> 8) | \
+ (((x) & 0x0000ff00) << 8) | \
+ (((x) & 0x000000ff) << 24) )
+
+#define BLADERF_BYTESWAP64(x) ((((x) & 0xff00000000000000llu) >> 56) | \
+ (((x) & 0x00ff000000000000llu) >> 40) | \
+ (((x) & 0x0000ff0000000000llu) >> 24) | \
+ (((x) & 0x000000ff00000000llu) >> 8) | \
+ (((x) & 0x00000000ff000000llu) << 8) | \
+ (((x) & 0x0000000000ff0000llu) << 24) | \
+ (((x) & 0x000000000000ff00llu) << 40) | \
+ (((x) & 0x00000000000000ffllu) << 56) | \
+
+#if BLADERF_BIG_ENDIAN
+# define HOST_TO_LE16_CONST(x) (BLADERF_BYTESWAP16(x))
+# define LE16_TO_HOST_CONST(x) (BLADERF_BYTESWAP16(x))
+# define HOST_TO_BE16_CONST(x) (x)
+# define BE16_TO_HOST_CONST(x) (x)
+
+# define HOST_TO_LE32_CONST(x) (BLADERF_BYTESWAP32(x))
+# define LE32_TO_HOST_CONST(x) (BLADERF_BYTESWAP32(x))
+# define HOST_TO_BE32_CONST(x) (x)
+# define BE32_TO_HOST_CONST(x) (x)
+
+# define HOST_TO_LE64_CONST(x) (BLADERF_BYTESWAP64(x))
+# define LE64_TO_HOST_CONST(x) (BLADERF_BYTESWAP64(x))
+# define HOST_TO_BE64_CONST(x) (x)
+# define BE64_TO_HOST_CONST(x) (x)
+#else
+# define HOST_TO_LE16_CONST(x) (x)
+# define LE16_TO_HOST_CONST(x) (x)
+# define HOST_TO_BE16_CONST(x) (BLADERF_BYTESWAP16(x))
+# define BE16_TO_HOST_CONST(x) (BLADERF_BYTESWAP16(x))
+
+# define HOST_TO_LE32_CONST(x) (x)
+# define LE32_TO_HOST_CONST(x) (x)
+# define HOST_TO_BE32_CONST(x) (BLADERF_BYTESWAP32(x))
+# define BE32_TO_HOST_CONST(x) (BLADERF_BYTESWAP32(x))
+
+# define HOST_TO_LE64_CONST(x) (x)
+# define LE64_TO_HOST_CONST(x) (x)
+# define HOST_TO_BE64_CONST(x) (BLADERF_BYTESWAP64(x))
+# define BE64_TO_HOST_CONST(x) (BLADERF_BYTESWAP64(x))
+#endif
+
+/*******************************************************************************
+ * Miscellaneous Linux fixups
+ ******************************************************************************/
+#if BLADERF_OS_LINUX
+
+/* Added here just to keep this out of the other source files. We'll have
+ * a few Windows replacements for unistd.h items. */
+#include <unistd.h>
+#include <pwd.h>
+
+/*******************************************************************************
+ * Miscellaneous FREEBSD fixups
+ ******************************************************************************/
+#elif BLADERF_OS_FREEBSD
+
+#include <unistd.h>
+#include <pwd.h>
+#include <sys/sysctl.h>
+
+/*******************************************************************************
+ * Miscellaneous OSX fixups
+ ******************************************************************************/
+#elif BLADERF_OS_OSX
+
+#include <unistd.h>
+#include <pwd.h>
+
+/*******************************************************************************
+ * Miscellaneous Windows fixups
+ ******************************************************************************/
+#elif BLADERF_OS_WINDOWS
+
+/* Rename a few functions and types */
+#include <windows.h>
+#include <io.h>
+#include <direct.h>
+#define usleep(x) Sleep((x+999)/1000)
+
+/* Changes specific to Microsoft Visual Studio and its C89-compliant ways */
+#if _MSC_VER
+# define strtok_r strtok_s
+# define strtoull _strtoui64
+#if _MSC_VER < 1900
+# define snprintf _snprintf
+# define vsnprintf _vsnprintf
+#else
+#define STDC99
+#endif
+# define strcasecmp _stricmp
+# define strncasecmp _strnicmp
+# define fileno _fileno
+# define strdup _strdup
+# define access _access
+# define chdir _chdir
+# define getcwd _getcwd
+# define rmdir _rmdir
+# define unlink _unlink
+# define mkdir(n, m) _mkdir(n)
+
+/* ssize_t lives elsewhere */
+# include <BaseTsd.h>
+# define ssize_t SSIZE_T
+
+/* With msvc, inline is only available for C++. Otherwise we need to use __inline:
+ * http://msdn.microsoft.com/en-us/library/z8y1yy88.aspx */
+# if !defined(__cplusplus)
+# define inline __inline
+# endif
+
+/* Visual studio 2012 compiler (v17.00.XX) doesn't have round functions */
+# if _MSC_VER <= 1700
+# include <math.h>
+ static inline float roundf(float x)
+ {
+ return x >= 0.0f ? floorf(x + 0.5f) : ceilf(x - 0.5f);
+ }
+ static inline double round(double x)
+ {
+ return x >= 0.0 ? floor(x + 0.5) : ceil(x - 0.5);
+ }
+# endif
+
+#endif // _MSC_VER
+
+#endif
+
+/* Windows (msvc) does not support C99 designated initializers.
+ *
+ * Therefore, the following macro should be used. However, note that you'll
+ * need to be sure to keep your elements in order to avoid breaking Windows
+ * portability!
+ *
+ * http://stackoverflow.com/questions/5440611/how-to-rewrite-c-struct-designated-initializers-to-c89-resp-msvc-c-compiler
+ *
+ * Here's a sample regexep you could use in vim to clean these up in your code:
+ * @\(\s\+\)\(\.[a-zA-Z0-9_]\+\)\s*=\s*\([a-zA-Z0-9_]\+\)\(,\)\?@\1FIELD_INIT(\2,\3)\4@gc
+ */
+#if _MSC_VER
+# define FIELD_INIT(field, ...) __VA_ARGS__
+#else
+# define FIELD_INIT(field, ...) field = __VA_ARGS__
+#endif // _MSC_VER
+
+/*******************************************************************************
+ * Miscellaneous utility macros
+ ******************************************************************************/
+#define ARRAY_SIZE(n) (sizeof(n) / sizeof(n[0]))
+
+/**
+ * GCC 7+ warns on implicit fallthroughs in switch statements
+ * (-Wimplicit-fallthrough), which we use in a couple places for simplicity.
+ * The statement attribute syntax used to suppress this warning is not
+ * supported by anything else.
+ */
+#if __GNUC__ >= 7
+#define EXPLICIT_FALLTHROUGH __attribute__((fallthrough))
+#else
+#define EXPLICIT_FALLTHROUGH
+#endif // __GNUC__ >= 7
+
+#endif
diff --git a/Radio/HW/BladeRF/common/include/host_config.h.in b/Radio/HW/BladeRF/common/include/host_config.h.in
new file mode 100644
index 0000000..844946d
--- /dev/null
+++ b/Radio/HW/BladeRF/common/include/host_config.h.in
@@ -0,0 +1,333 @@
+/**
+ * @file host_config.h.in
+ *
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (c) 2013-2018 Nuand LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef HOST_CONFIG_H__
+#define HOST_CONFIG_H__
+
+#cmakedefine01 BLADERF_OS_LINUX
+#cmakedefine01 BLADERF_OS_FREEBSD
+#cmakedefine01 BLADERF_OS_OSX
+#cmakedefine01 BLADERF_OS_WINDOWS
+#cmakedefine01 BLADERF_BIG_ENDIAN
+
+#if !(BLADERF_OS_LINUX || BLADERF_OS_OSX || BLADERF_OS_WINDOWS || BLADERF_OS_FREEBSD)
+# error "Build not configured for any supported operating systems"
+#endif
+
+#if 1 < (BLADERF_OS_LINUX + BLADERF_OS_OSX + BLADERF_OS_WINDOWS + BLADERF_OS_FREEBSD)
+#error "Build configured for multiple operating systems"
+#endif
+
+#cmakedefine01 HAVE_CLOCK_GETTIME
+
+/*******************************************************************************
+ * Endianness conversions
+ *
+ * HOST_TO_LE16 16-bit host endianness to little endian conversion
+ * LE16_TO_HOST 16-bit little endian to host endianness conversion
+ * HOST_TO_BE16 16-bit host endianness to big endian conversion
+ * BE16_TO_HOST 16-bit big endian to host endianness conversion
+ * HOST_TO_LE32 32-bit host endianness to little endian conversion
+ * LE32_TO_HOST 32-bit little endian to host endianness conversion
+ * HOST_TO_BE32 32-bit host endianness to big endian conversion
+ * BE32_TO_HOST 32-bit big endian to host endianness conversion
+ * HOST_TO_BE64 64-bit host endianness to big endian conversion
+ * BE64_TO_HOST 64-bit big endian to host endianness conversion
+ ******************************************************************************/
+
+/*-----------------------
+ * Linux
+ *---------------------*/
+#if BLADERF_OS_LINUX
+#include <endian.h>
+
+#define HOST_TO_LE16(val) htole16(val)
+#define LE16_TO_HOST(val) le16toh(val)
+#define HOST_TO_BE16(val) htobe16(val)
+#define BE16_TO_HOST(val) be16toh(val)
+
+#define HOST_TO_LE32(val) htole32(val)
+#define LE32_TO_HOST(val) le32toh(val)
+#define HOST_TO_BE32(val) htobe32(val)
+#define BE32_TO_HOST(val) be32toh(val)
+
+#define HOST_TO_LE64(val) htole64(val)
+#define LE64_TO_HOST(val) le64toh(val)
+#define HOST_TO_BE64(val) be64toh(val)
+#define BE64_TO_HOST(val) be64toh(val)
+
+/*-----------------------
+ * FREEBSD
+ *---------------------*/
+#elif BLADERF_OS_FREEBSD
+#include <sys/endian.h>
+
+#define HOST_TO_LE16(val) htole16(val)
+#define LE16_TO_HOST(val) le16toh(val)
+#define HOST_TO_BE16(val) htobe16(val)
+#define BE16_TO_HOST(val) be16toh(val)
+
+#define HOST_TO_LE32(val) htole32(val)
+#define LE32_TO_HOST(val) le32toh(val)
+#define HOST_TO_BE32(val) htobe32(val)
+#define BE32_TO_HOST(val) be32toh(val)
+
+#define HOST_TO_LE64(val) htole64(val)
+#define LE64_TO_HOST(val) le64toh(val)
+#define HOST_TO_BE64(val) be64toh(val)
+#define BE64_TO_HOST(val) be64toh(val)
+
+/*-----------------------
+ * Apple OSX
+ *---------------------*/
+#elif BLADERF_OS_OSX
+#include <libkern/OSByteOrder.h>
+
+#define HOST_TO_LE16(val) OSSwapHostToLittleInt16(val)
+#define LE16_TO_HOST(val) OSSwapLittleToHostInt16(val)
+#define HOST_TO_BE16(val) OSSwapHostToBigInt16(val)
+#define BE16_TO_HOST(val) OSSwapBigToHostInt16(val)
+
+#define HOST_TO_LE32(val) OSSwapHostToLittleInt32(val)
+#define LE32_TO_HOST(val) OSSwapLittleToHostInt32(val)
+#define HOST_TO_BE32(val) OSSwapHostToBigInt32(val)
+#define BE32_TO_HOST(val) OSSwapBigToHostInt32(val)
+
+#define HOST_TO_LE64(val) OSSwapHostToLittleInt64(val)
+#define LE64_TO_HOST(val) OSSwapLittleToHostInt64(val)
+#define HOST_TO_BE64(val) OSSwapHostToBigInt64(val)
+#define BE64_TO_HOST(val) OSSwapBigToHostInt64(val)
+
+/*-----------------------
+ * Windows
+ *---------------------*/
+#elif BLADERF_OS_WINDOWS
+#include <intrin.h>
+
+/* We'll assume little endian for Windows platforms:
+ * http://blogs.msdn.com/b/larryosterman/archive/2005/06/07/426334.aspx
+ */
+#define HOST_TO_LE16(val) (val)
+#define LE16_TO_HOST(val) (val)
+#define HOST_TO_BE16(val) _byteswap_ushort(val)
+#define BE16_TO_HOST(val) _byteswap_ushort(val)
+
+#define HOST_TO_LE32(val) (val)
+#define LE32_TO_HOST(val) (val)
+#define HOST_TO_BE32(val) _byteswap_ulong(val)
+#define BE32_TO_HOST(val) _byteswap_ulong(val)
+
+
+#define HOST_TO_LE64(val) (val)
+#define LE64_TO_HOST(val) (val)
+#define HOST_TO_BE64(val) _byteswap_uint64(val)
+#define BE64_TO_HOST(val) _byteswap_uint64(val)
+
+/*-----------------------
+ * Unsupported or bug
+ *---------------------*/
+#else
+#error "Encountered an OS that we do not have endian wrappers for?"
+#endif
+
+/*******************************************************************************
+ * Endianness conversions for constants
+ *
+ * We shouldn't be using the above items for assigning constants because the
+ * implementations may be functions [1].
+ *
+ * [1] https://sourceware.org/bugzilla/show_bug.cgi?id=17679#c7
+ ******************************************************************************/
+
+#define BLADERF_BYTESWAP16(x) ((((x) & 0xff00) >> 8) | (((x) & 0x00ff) << 8))
+
+#define BLADERF_BYTESWAP32(x) ((((x) & 0xff000000) >> 24) | \
+ (((x) & 0x00ff0000) >> 8) | \
+ (((x) & 0x0000ff00) << 8) | \
+ (((x) & 0x000000ff) << 24) )
+
+#define BLADERF_BYTESWAP64(x) ((((x) & 0xff00000000000000llu) >> 56) | \
+ (((x) & 0x00ff000000000000llu) >> 40) | \
+ (((x) & 0x0000ff0000000000llu) >> 24) | \
+ (((x) & 0x000000ff00000000llu) >> 8) | \
+ (((x) & 0x00000000ff000000llu) << 8) | \
+ (((x) & 0x0000000000ff0000llu) << 24) | \
+ (((x) & 0x000000000000ff00llu) << 40) | \
+ (((x) & 0x00000000000000ffllu) << 56) | \
+
+#if BLADERF_BIG_ENDIAN
+# define HOST_TO_LE16_CONST(x) (BLADERF_BYTESWAP16(x))
+# define LE16_TO_HOST_CONST(x) (BLADERF_BYTESWAP16(x))
+# define HOST_TO_BE16_CONST(x) (x)
+# define BE16_TO_HOST_CONST(x) (x)
+
+# define HOST_TO_LE32_CONST(x) (BLADERF_BYTESWAP32(x))
+# define LE32_TO_HOST_CONST(x) (BLADERF_BYTESWAP32(x))
+# define HOST_TO_BE32_CONST(x) (x)
+# define BE32_TO_HOST_CONST(x) (x)
+
+# define HOST_TO_LE64_CONST(x) (BLADERF_BYTESWAP64(x))
+# define LE64_TO_HOST_CONST(x) (BLADERF_BYTESWAP64(x))
+# define HOST_TO_BE64_CONST(x) (x)
+# define BE64_TO_HOST_CONST(x) (x)
+#else
+# define HOST_TO_LE16_CONST(x) (x)
+# define LE16_TO_HOST_CONST(x) (x)
+# define HOST_TO_BE16_CONST(x) (BLADERF_BYTESWAP16(x))
+# define BE16_TO_HOST_CONST(x) (BLADERF_BYTESWAP16(x))
+
+# define HOST_TO_LE32_CONST(x) (x)
+# define LE32_TO_HOST_CONST(x) (x)
+# define HOST_TO_BE32_CONST(x) (BLADERF_BYTESWAP32(x))
+# define BE32_TO_HOST_CONST(x) (BLADERF_BYTESWAP32(x))
+
+# define HOST_TO_LE64_CONST(x) (x)
+# define LE64_TO_HOST_CONST(x) (x)
+# define HOST_TO_BE64_CONST(x) (BLADERF_BYTESWAP64(x))
+# define BE64_TO_HOST_CONST(x) (BLADERF_BYTESWAP64(x))
+#endif
+
+/*******************************************************************************
+ * Miscellaneous Linux fixups
+ ******************************************************************************/
+#if BLADERF_OS_LINUX
+
+/* Added here just to keep this out of the other source files. We'll have
+ * a few Windows replacements for unistd.h items. */
+#include <unistd.h>
+#include <pwd.h>
+
+/*******************************************************************************
+ * Miscellaneous FREEBSD fixups
+ ******************************************************************************/
+#elif BLADERF_OS_FREEBSD
+
+#include <unistd.h>
+#include <pwd.h>
+#include <sys/sysctl.h>
+
+/*******************************************************************************
+ * Miscellaneous OSX fixups
+ ******************************************************************************/
+#elif BLADERF_OS_OSX
+
+#include <unistd.h>
+#include <pwd.h>
+
+/*******************************************************************************
+ * Miscellaneous Windows fixups
+ ******************************************************************************/
+#elif BLADERF_OS_WINDOWS
+
+/* Rename a few functions and types */
+#include <windows.h>
+#include <io.h>
+#include <direct.h>
+#define usleep(x) Sleep((x+999)/1000)
+
+/* Changes specific to Microsoft Visual Studio and its C89-compliant ways */
+#if _MSC_VER
+# define strtok_r strtok_s
+# define strtoull _strtoui64
+#if _MSC_VER < 1900
+# define snprintf _snprintf
+# define vsnprintf _vsnprintf
+#else
+#define STDC99
+#endif
+# define strcasecmp _stricmp
+# define strncasecmp _strnicmp
+# define fileno _fileno
+# define strdup _strdup
+# define access _access
+# define chdir _chdir
+# define getcwd _getcwd
+# define rmdir _rmdir
+# define unlink _unlink
+# define mkdir(n, m) _mkdir(n)
+
+/* ssize_t lives elsewhere */
+# include <BaseTsd.h>
+# define ssize_t SSIZE_T
+
+/* With msvc, inline is only available for C++. Otherwise we need to use __inline:
+ * http://msdn.microsoft.com/en-us/library/z8y1yy88.aspx */
+# if !defined(__cplusplus)
+# define inline __inline
+# endif
+
+/* Visual studio 2012 compiler (v17.00.XX) doesn't have round functions */
+# if _MSC_VER <= 1700
+# include <math.h>
+ static inline float roundf(float x)
+ {
+ return x >= 0.0f ? floorf(x + 0.5f) : ceilf(x - 0.5f);
+ }
+ static inline double round(double x)
+ {
+ return x >= 0.0 ? floor(x + 0.5) : ceil(x - 0.5);
+ }
+# endif
+
+#endif // _MSC_VER
+
+#endif
+
+/* Windows (msvc) does not support C99 designated initializers.
+ *
+ * Therefore, the following macro should be used. However, note that you'll
+ * need to be sure to keep your elements in order to avoid breaking Windows
+ * portability!
+ *
+ * http://stackoverflow.com/questions/5440611/how-to-rewrite-c-struct-designated-initializers-to-c89-resp-msvc-c-compiler
+ *
+ * Here's a sample regexep you could use in vim to clean these up in your code:
+ * @\(\s\+\)\(\.[a-zA-Z0-9_]\+\)\s*=\s*\([a-zA-Z0-9_]\+\)\(,\)\?@\1FIELD_INIT(\2,\3)\4@gc
+ */
+#if _MSC_VER
+# define FIELD_INIT(field, ...) __VA_ARGS__
+#else
+# define FIELD_INIT(field, ...) field = __VA_ARGS__
+#endif // _MSC_VER
+
+/*******************************************************************************
+ * Miscellaneous utility macros
+ ******************************************************************************/
+#define ARRAY_SIZE(n) (sizeof(n) / sizeof(n[0]))
+
+/**
+ * GCC 7+ warns on implicit fallthroughs in switch statements
+ * (-Wimplicit-fallthrough), which we use in a couple places for simplicity.
+ * The statement attribute syntax used to suppress this warning is not
+ * supported by anything else.
+ */
+#if __GNUC__ >= 7
+#define EXPLICIT_FALLTHROUGH __attribute__((fallthrough))
+#else
+#define EXPLICIT_FALLTHROUGH
+#endif // __GNUC__ >= 7
+
+#endif
diff --git a/Radio/HW/BladeRF/common/include/iterators.h b/Radio/HW/BladeRF/common/include/iterators.h
new file mode 100644
index 0000000..65127a4
--- /dev/null
+++ b/Radio/HW/BladeRF/common/include/iterators.h
@@ -0,0 +1,59 @@
+/**
+ * @file iterators.h
+ *
+ * @brief Useful iterators for working with channels, etc
+ *
+ * Copyright (c) 2018 Nuand LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @brief Translate a bladerf_direction and channel number to a
+ * bladerf_channel
+ *
+ * @param _dir Direction
+ * @param _idx Channel number
+ *
+ * @return BLADERF_CHANNEL_TX(_idx) or BLADERF_CHANNEL_RX(_idx)
+ */
+#define CHANNEL_IDX(_dir, _idx) \
+ (BLADERF_TX == _dir) ? BLADERF_CHANNEL_TX(_idx) : BLADERF_CHANNEL_RX(_idx)
+
+/**
+ * @brief Iterate over all bladerf_directions
+ *
+ * @param _dir Direction
+ */
+#define FOR_EACH_DIRECTION(_dir) \
+ for (_dir = BLADERF_RX; _dir <= BLADERF_TX; ++_dir)
+
+/**
+ * @brief Iterate over all channels in a given direction
+ *
+ * @param _dir Direction
+ * @param _count Number of channels
+ * @param[out] _index Index variable (size_t)
+ * @param[out] _channel Channel variable (bladerf_channel)
+ *
+ * @return { description_of_the_return_value }
+ */
+#define FOR_EACH_CHANNEL(_dir, _count, _index, _channel) \
+ for (_index = 0, _channel = CHANNEL_IDX(_dir, _index); _index < _count; \
+ ++_index, _channel = CHANNEL_IDX(_dir, _index))
diff --git a/Radio/HW/BladeRF/common/include/log.h b/Radio/HW/BladeRF/common/include/log.h
new file mode 100644
index 0000000..0b635b5
--- /dev/null
+++ b/Radio/HW/BladeRF/common/include/log.h
@@ -0,0 +1,144 @@
+/**
+ * @file log.h
+ *
+ * @brief Simple log message
+ *
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (c) 2013 Nuand LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef LOG_H__
+#define LOG_H__
+
+#include <stdio.h>
+#include <inttypes.h>
+
+#include "libbladeRF.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef SHORT_FILE_
+# define THIS_FILE SHORT_FILE_
+#else
+#if 0
+# warning "SHORT_FILE_ was not defined. Using __FILE__ instead."
+#endif
+# define THIS_FILE __FILE__
+#endif
+
+#define LOG_STRINGIFY__(x) #x
+#define LOG_STRINGIFY_(x) LOG_STRINGIFY__(x)
+
+#define LOG_EXPAND__(x) #x
+#define LOG_EXPAND_(x) LOG_EXPAND__(x)
+
+/**
+ * @defgroup LOG_MACROS Logging macros
+ * @{
+ */
+
+/** Logs a verbose message. Does not include function/line information */
+#define log_verbose(...) \
+ LOG_WRITE(BLADERF_LOG_LEVEL_VERBOSE, "[VERBOSE", __VA_ARGS__)
+
+/** Logs a debug message. Does not include function/line information */
+#define log_debug(...) \
+ LOG_WRITE(BLADERF_LOG_LEVEL_DEBUG, "[DEBUG", __VA_ARGS__)
+
+/** Logs an info message. Does not include function/line information*/
+#define log_info(...) \
+ LOG_WRITE(BLADERF_LOG_LEVEL_INFO, "[INFO", __VA_ARGS__)
+
+/** Logs a warning message. Includes function/line information */
+#define log_warning(...) \
+ LOG_WRITE(BLADERF_LOG_LEVEL_WARNING, "[WARNING", __VA_ARGS__)
+
+/** Logs an error message. Includes function/line information */
+#define log_error(...) \
+ LOG_WRITE(BLADERF_LOG_LEVEL_ERROR, "[ERROR", __VA_ARGS__)
+
+/** Logs a critical error message. Includes function/line information */
+#define log_critical(...) \
+ LOG_WRITE(BLADERF_LOG_LEVEL_CRITICAL, "[CRITICAL", __VA_ARGS__)
+
+/** @} */
+
+#ifdef LOG_INCLUDE_FILE_INFO
+# define LOG_WRITE(LEVEL, LEVEL_STRING, ...) \
+ do { log_write(LEVEL, LEVEL_STRING \
+ " @ " LOG_EXPAND_(THIS_FILE) \
+ ":" LOG_STRINGIFY_(__LINE__) "] " \
+ __VA_ARGS__); \
+ } while (0)
+#else
+# define LOG_WRITE(LEVEL, LEVEL_STRING, ...) \
+ do { log_write(LEVEL, LEVEL_STRING "] " __VA_ARGS__); } while (0)
+#endif
+
+/**
+ * Writes a message to the logger with the specified log level. This function
+ * should only be invoked indirectly through one of the log_*
+ * convenience macros above to ensure consistent formatting of log messages.
+ *
+ * @param level The severity level of the message
+ * @param format The printf-style format string
+ * @param ... Optional values for format specifier substitution
+ */
+#ifdef LOGGING_ENABLED
+void log_write(bladerf_log_level level, const char *format, ...);
+#else
+#define log_write(level, format, ...) do {} while(0)
+#endif
+
+
+/**
+ * Sets the filter level for displayed log messages. Messages that are at
+ * or above the specified log level will be written to the log output, while
+ * messages with a lower log level will be suppressed. This function returns
+ * the previous log level.
+ *
+ * @param level The new log level filter value
+ */
+#ifdef LOGGING_ENABLED
+void log_set_verbosity(bladerf_log_level level);
+#else
+#define log_set_verbosity(level) do {} while (0)
+#endif
+
+/**
+ * @brief Gets the current filter level for displayed log messages.
+ *
+ * @return bladerf_log_level
+ */
+#ifdef LOGGING_ENABLED
+bladerf_log_level log_get_verbosity();
+#else
+#define log_get_verbosity(...) BLADERF_LOG_LEVEL_SILENT
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/Radio/HW/BladeRF/common/include/logger_id.h b/Radio/HW/BladeRF/common/include/logger_id.h
new file mode 100644
index 0000000..f37da81
--- /dev/null
+++ b/Radio/HW/BladeRF/common/include/logger_id.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2015 Nuand LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef LOGGER_ID_H_
+#define LOGGER_ID_H_
+
+#define LOGGER_ID_NONE 0
+#define LOGGER_ID_BLADERF_C 1
+#define LOGGER_ID_FLASH_C 2
+#define LOGGER_ID_FPGA_C 3
+#define LOGGER_ID_GPIF_C 4
+#define LOGGER_ID_LOGGER_C 5
+#define LOGGER_ID_RF_C 6
+#define LOGGER_ID_SPI_FLASH_LIB_C 7
+
+#ifdef LOGGER_ID_STRING
+static inline const char * logger_id_string(uint8_t file_id)
+{
+ switch (file_id) {
+ case LOGGER_ID_NONE:
+ return "<None>";
+ case LOGGER_ID_BLADERF_C:
+ return "bladeRF.c";
+ case LOGGER_ID_FLASH_C:
+ return "flash.c";
+ case LOGGER_ID_FPGA_C:
+ return "fpga.c";
+ case LOGGER_ID_GPIF_C:
+ return "gpif.c";
+ case LOGGER_ID_LOGGER_C:
+ return "logger.c";
+ case LOGGER_ID_RF_C:
+ return "rf.c";
+ case LOGGER_ID_SPI_FLASH_LIB_C:
+ return "spi_flash_lib.c";
+ default:
+ return "<Unknown>";
+ }
+}
+#endif
+
+#endif
diff --git a/Radio/HW/BladeRF/common/include/minmax.h b/Radio/HW/BladeRF/common/include/minmax.h
new file mode 100644
index 0000000..9195250
--- /dev/null
+++ b/Radio/HW/BladeRF/common/include/minmax.h
@@ -0,0 +1,65 @@
+/**
+ * @file minmax.h
+ *
+ * @brief These static inline routines are preferred over the use of macros,
+ * as they provide type safety.
+ */
+
+#ifndef MINMAX_H__
+#define MINMAX_H__
+
+#include <stdlib.h>
+#include <stdint.h>
+#include "host_config.h"
+
+static inline size_t min_sz(size_t x, size_t y)
+{
+ return x < y ? x : y;
+}
+
+static inline size_t max_sz(size_t x, size_t y)
+{
+ return x > y ? x : y;
+}
+
+static inline unsigned int uint_min(unsigned int x, unsigned int y)
+{
+ return x < y ? x : y;
+}
+
+static inline unsigned int uint_max(unsigned int x, unsigned int y)
+{
+ return x > y ? x : y;
+}
+
+static inline uint32_t u32_min(uint32_t x, uint32_t y)
+{
+ return x < y ? x : y;
+}
+
+static inline uint32_t u32_max(uint32_t x, uint32_t y)
+{
+ return x > y ? x : y;
+}
+
+static inline int64_t i64_min(int64_t x, int64_t y)
+{
+ return x < y ? x : y;
+}
+
+static inline uint64_t u64_min(uint64_t x, uint64_t y)
+{
+ return x < y ? x : y;
+}
+
+static inline int64_t i64_max(int64_t x, int64_t y)
+{
+ return x > y ? x : y;
+}
+
+static inline uint64_t u64_max(uint64_t x, uint64_t y)
+{
+ return x > y ? x : y;
+}
+
+#endif
diff --git a/Radio/HW/BladeRF/common/include/osx/clock_gettime.h b/Radio/HW/BladeRF/common/include/osx/clock_gettime.h
new file mode 100644
index 0000000..f2ee0ce
--- /dev/null
+++ b/Radio/HW/BladeRF/common/include/osx/clock_gettime.h
@@ -0,0 +1,52 @@
+/*
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (c) 2013-2017 Nuand LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef OSX_CLOCK_GETTIME_H_
+#define OSX_CLOCK_GETTIME_H_
+
+#include "host_config.h"
+#include <time.h>
+
+#if HAVE_CLOCK_GETTIME == 0
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#ifndef __MACH__
+# error "This file is intended for use with OSX systems only."
+#endif // __MACH__
+
+typedef int clockid_t;
+#define CLOCK_REALTIME 0
+
+int clock_gettime(clockid_t clk_id, struct timespec *tp);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif // __cplusplus
+
+#endif // !HAVE_CLOCK_GETTIME
+
+#endif // OSX_CLOCK_GETTIME_H
diff --git a/Radio/HW/BladeRF/common/include/parse.h b/Radio/HW/BladeRF/common/include/parse.h
new file mode 100644
index 0000000..a397e6c
--- /dev/null
+++ b/Radio/HW/BladeRF/common/include/parse.h
@@ -0,0 +1,112 @@
+/**
+ * @file parse.h
+ *
+ * @brief String and file parsing functions
+ *
+ * Copyright (c) 2017 Nuand LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef PARSE_H_
+#define PARSE_H_
+
+#include "libbladeRF.h"
+#include <stdio.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Convert ASCII string into arguments
+ *
+ * @param[in] line Command line string
+ * @param[in] comment_char Everything after this charater is discarded
+ * @param[out] argv A pointer to a double pointer of successfully
+ * extracted arguments
+ *
+ * @return -2 on unterminated quote, -1 on error, otherwise number of arguments
+ */
+int str2args(const char *line, char comment_char, char ***argv);
+
+/**
+ * Free arguments returned by str2args()
+ *
+ * @param[in] argc Number of arguments
+ * @param[in] argv Pointer to table of pointers to arguments
+ */
+void free_args(int argc, char **argv);
+
+struct config_options {
+ char *key;
+ char *value;
+ int lineno;
+};
+
+/**
+ * Convert a bladeRF options file to an array of strings
+ *
+ * @param[in] dev Pointer to bladerf device
+ * @param[in] buf String buffer containing entire file
+ * @param[in] buf_sz String buffer containing entire file
+ * @param[out] opts A pointer to an array of strings containing options for
+ * this device
+ *
+ * @return number of options on success, BLADERF_ERR_* values on other failures
+ */
+int str2options(struct bladerf *dev,
+ const char *buf,
+ size_t buf_sz,
+ struct config_options **opts);
+
+/**
+ * Free an array of previously returned options
+ *
+ * @param[in] optv Pointer to array of config_options
+ * @param[in] optc Number of config_options
+ */
+void free_opts(struct config_options *optv, int optc);
+
+/**
+ * Convert comma-delimited string into integer arguments
+ *
+ * @param[in] line Line to split
+ * @param[out] args Pointer to double-pointer of successfully extracted
+ * integers
+ *
+ * @see free_csv2int()
+ *
+ * @return -1 on error, otherwise number of arguments
+ */
+int csv2int(const char *line, int ***args);
+
+/**
+ * Free array of previously-returned csv2int arguments
+ *
+ * @param[in] argc Number of arguments
+ * @param[in] args Pointer to array of pointers to ints
+ */
+void free_csv2int(int argc, int **args);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/Radio/HW/BladeRF/common/include/range.h b/Radio/HW/BladeRF/common/include/range.h
new file mode 100644
index 0000000..c15a005
--- /dev/null
+++ b/Radio/HW/BladeRF/common/include/range.h
@@ -0,0 +1,54 @@
+/* This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (c) 2018 Nuand LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef RANGE_H_
+#define RANGE_H_
+
+#if !defined(BLADERF_NIOS_BUILD) && !defined(BLADERF_NIOS_PC_SIMULATION)
+#include <libbladeRF.h>
+#else
+#include "libbladeRF_nios_compat.h"
+#endif
+
+#include "bladerf2_common.h"
+
+#ifdef BLADERF_NIOS_BUILD
+// don't do scaling on the Nios, since multiplication and division suck
+#define __scale(r, v) (v)
+#define __unscale(r, v) (v)
+#else
+#define __scale(r, v) ((float)(v) / (r)->scale)
+#define __unscale(r, v) ((float)(v) * (r)->scale)
+#endif // BLADERF_NIOS_BUILD
+
+#define __scale_int(r, v) (__round_int(__scale(r, v)))
+#define __scale_int64(r, v) (__round_int64(__scale(r, v)))
+
+#define __unscale_int(r, v) (__round_int(__unscale(r, v)))
+#define __unscale_int64(r, v) (__round_int64(__unscale(r, v)))
+
+bool is_within_range(struct bladerf_range const *range, int64_t value);
+int64_t clamp_to_range(struct bladerf_range const *range, int64_t value);
+
+#endif // RANGE_H_
diff --git a/Radio/HW/BladeRF/common/include/rel_assert.h b/Radio/HW/BladeRF/common/include/rel_assert.h
new file mode 100644
index 0000000..4727710
--- /dev/null
+++ b/Radio/HW/BladeRF/common/include/rel_assert.h
@@ -0,0 +1,14 @@
+#ifndef _REL_ASSERT_H_
+#define _REL_ASSERT_H_
+
+#ifdef NDEBUG
+#define NDEBUG_UNDEF
+#endif
+#undef NDEBUG
+#include <assert.h>
+#ifdef NDEBUG_UNDEF
+#define NDEBUG
+#undef NDEBUG_UNDEF
+#endif
+
+#endif /* _REL_ASSERT_H_ */ \ No newline at end of file
diff --git a/Radio/HW/BladeRF/common/include/sha256.h b/Radio/HW/BladeRF/common/include/sha256.h
new file mode 100644
index 0000000..7517ecd
--- /dev/null
+++ b/Radio/HW/BladeRF/common/include/sha256.h
@@ -0,0 +1,61 @@
+/*-
+ * Copyright 2005 Colin Percival
+ * Copyright 2013 Daniel Gröber
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SHA256_H_
+#define _SHA256_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SHA256_DIGEST_SIZE 32
+
+typedef struct SHA256Context {
+ uint32_t state[8];
+ uint32_t count[2];
+ unsigned char buf[64];
+} SHA256_CTX;
+
+void SHA256_Init(SHA256_CTX *);
+void SHA256_Update(SHA256_CTX *, const void *, size_t);
+void SHA256_Final(unsigned char [32], SHA256_CTX *);
+/* char *SHA256_End(SHA256_CTX *, char *); */
+/* char *SHA256_File(const char *, char *); */
+/* char *SHA256_FileChunk(const char *, char *, off_t, off_t); */
+/* char *SHA256_Data(const void *, unsigned int, char *); */
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* !_SHA256_H_ */
diff --git a/Radio/HW/BladeRF/common/include/str_queue.h b/Radio/HW/BladeRF/common/include/str_queue.h
new file mode 100644
index 0000000..9ed1769
--- /dev/null
+++ b/Radio/HW/BladeRF/common/include/str_queue.h
@@ -0,0 +1,93 @@
+/**
+ * @file str_queue.h
+ *
+ * @brief Simple string queue
+ *
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (c) 2014 Nuand LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef STR_QUEUE_H_
+#define STR_QUEUE_H_
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct str_queue_entry;
+
+struct str_queue {
+ struct str_queue_entry *head;
+ struct str_queue_entry *tail;
+};
+
+/**
+ * Allocate and initialize a string queue
+ *
+ * @param[in] q Queue to initialize
+ */
+void str_queue_init(struct str_queue *q);
+
+/**
+ * Deallocate all resources used by the specified string queue
+ *
+ * @param[in] q Queue to deinitialize
+ */
+void str_queue_deinit(struct str_queue *q);
+
+/** Deinitialization simply clears out the queue - same operation */
+#define str_queue_clear str_queue_deinit
+
+/**
+ * Add a string to the end of the provided string queue
+ *
+ * @param q String queue to append to
+ * @param cmd_str String to append. This string will be copied
+ * to a heap-allocated buffer.
+ *
+ * @return 0 on success, -1 on memory allocation failure
+ */
+int str_queue_enq(struct str_queue *q, const char *str);
+
+/**
+ * Remove a string from the front of the specified string queue.
+ *
+ * @param[in] q Queue to remove from
+ *
+ * @return Heap-allocated string removed from queue, or NULL if the queue is
+ * empty. The caller is responsible for free()-ing the returned string.
+ */
+char * str_queue_deq(struct str_queue *q);
+
+/**
+ * @return true if the queue is empty
+ */
+bool str_queue_empty(struct str_queue *q);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+
+#endif
diff --git a/Radio/HW/BladeRF/common/include/thread.h b/Radio/HW/BladeRF/common/include/thread.h
new file mode 100644
index 0000000..855a24b
--- /dev/null
+++ b/Radio/HW/BladeRF/common/include/thread.h
@@ -0,0 +1,74 @@
+/**
+ * @file thread.h
+ *
+ * @brief Threading portability and debug wrappers
+ *
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (c) 2014 Nuand LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef BLADERF_THREAD_H_
+#define BLADERF_THREAD_H_
+
+/* Currently, only pthreads is supported. In the future, native windows threads
+ * may be used; one of the objectives of this file is to ease that transistion.
+ */
+#include <pthread.h>
+#include "rel_assert.h"
+
+#define MUTEX pthread_mutex_t
+
+#ifdef ENABLE_LOCK_CHECKS
+# define MUTEX_INIT(m) do { \
+ int status; \
+ pthread_mutexattr_t mutex_attr; \
+ status = pthread_mutexattr_init(&mutex_attr); \
+ assert(status == 0 && "Mutex attr init failure"); \
+ status = pthread_mutexattr_settype(&mutex_attr, \
+ PTHREAD_MUTEX_ERRORCHECK); \
+ assert(status == 0 && "Mutex attr setype failure"); \
+ status = pthread_mutex_init(m, &mutex_attr); \
+ assert(status == 0 && "Mutex init failure"); \
+ } while (0)
+
+# define MUTEX_LOCK(m) do { \
+ int status = pthread_mutex_lock(m); \
+ assert(status == 0 && "Mutex lock failure");\
+ } while (0)
+
+# define MUTEX_UNLOCK(m) do { \
+ int status = pthread_mutex_unlock(m); \
+ assert(status == 0 && "Mutex unlock failure");\
+ } while (0)
+
+# define MUTEX_DESTROY(m) do { \
+ int status = pthread_mutex_destroy(m); \
+ assert(status == 0 && "Mutex destroy failure");\
+ } while (0)
+#else
+# define MUTEX_INIT(m) pthread_mutex_init(m, NULL)
+# define MUTEX_LOCK(m) pthread_mutex_lock(m)
+# define MUTEX_UNLOCK(m) pthread_mutex_unlock(m)
+# define MUTEX_DESTROY(m) pthread_mutex_destroy(m)
+#endif
+
+#endif
diff --git a/Radio/HW/BladeRF/common/src/conversions.c b/Radio/HW/BladeRF/common/src/conversions.c
new file mode 100644
index 0000000..ad08520
--- /dev/null
+++ b/Radio/HW/BladeRF/common/src/conversions.c
@@ -0,0 +1,730 @@
+/*
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (c) 2017-2018 Nuand LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "conversions.h"
+
+int str2version(const char *str, struct bladerf_version *version)
+{
+ unsigned long tmp;
+ const char *start = str;
+ char *end;
+
+ /* Major version */
+ errno = 0;
+ tmp = strtoul(start, &end, 10);
+ if (errno != 0 || tmp > UINT16_MAX || end == start || *end != '.') {
+ return -1;
+ }
+ version->major = (uint16_t)tmp;
+
+ /* Minor version */
+ if (end[0] == '\0' || end[1] == '\0') {
+ return -1;
+ }
+ errno = 0;
+ start = &end[1];
+ tmp = strtoul(start, &end, 10);
+ if (errno != 0 || tmp > UINT16_MAX || end == start || *end != '.') {
+ return -1;
+ }
+ version->minor = (uint16_t)tmp;
+
+ /* Patch version */
+ if (end[0] == '\0' || end[1] == '\0') {
+ return -1;
+ }
+ errno = 0;
+ start = &end[1];
+ tmp = strtoul(start, &end, 10);
+ if (errno != 0 || tmp > UINT16_MAX || end == start ||
+ (*end != '-' && *end != '\0')) {
+ return -1;
+ }
+ version->patch = (uint16_t)tmp;
+
+ version->describe = str;
+
+ return 0;
+}
+
+const char *devspeed2str(bladerf_dev_speed speed)
+{
+ switch (speed) {
+ case BLADERF_DEVICE_SPEED_HIGH:
+ /* Yeah, the USB IF actually spelled it "Hi" instead of "High".
+ * I know. It hurts me too. */
+ return "Hi-Speed";
+
+ case BLADERF_DEVICE_SPEED_SUPER:
+ /* ...and no hyphen :( */
+ return "SuperSpeed";
+
+ default:
+ return "Unknown";
+ }
+}
+
+bladerf_log_level str2loglevel(const char *str, bool *ok)
+{
+ bladerf_log_level level = BLADERF_LOG_LEVEL_ERROR;
+ bool valid = true;
+
+ if (!strcasecmp(str, "critical")) {
+ level = BLADERF_LOG_LEVEL_CRITICAL;
+ } else if (!strcasecmp(str, "error")) {
+ level = BLADERF_LOG_LEVEL_ERROR;
+ } else if (!strcasecmp(str, "warning")) {
+ level = BLADERF_LOG_LEVEL_WARNING;
+ } else if (!strcasecmp(str, "info")) {
+ level = BLADERF_LOG_LEVEL_INFO;
+ } else if (!strcasecmp(str, "debug")) {
+ level = BLADERF_LOG_LEVEL_DEBUG;
+ } else if (!strcasecmp(str, "verbose")) {
+ level = BLADERF_LOG_LEVEL_VERBOSE;
+ } else {
+ valid = false;
+ }
+
+ *ok = valid;
+ return level;
+}
+
+const char *module2str(bladerf_module m)
+{
+ switch (m) {
+ case BLADERF_MODULE_RX:
+ return "RX";
+ case BLADERF_MODULE_TX:
+ return "TX";
+ default:
+ return "Unknown";
+ }
+}
+
+bladerf_module str2module(const char *str)
+{
+ if (!strcasecmp(str, "RX")) {
+ return BLADERF_MODULE_RX;
+ } else if (!strcasecmp(str, "TX")) {
+ return BLADERF_MODULE_TX;
+ } else {
+ return BLADERF_MODULE_INVALID;
+ }
+}
+
+const char *channel2str(bladerf_channel ch)
+{
+ switch (ch) {
+ case BLADERF_CHANNEL_RX(0):
+ return "RX1";
+ case BLADERF_CHANNEL_TX(0):
+ return "TX1";
+ case BLADERF_CHANNEL_RX(1):
+ return "RX2";
+ case BLADERF_CHANNEL_TX(1):
+ return "TX2";
+ default:
+ return "Unknown";
+ }
+}
+
+bladerf_channel str2channel(char const *str)
+{
+ bladerf_channel rv;
+
+ if (strcasecmp(str, "rx") == 0 || strcasecmp(str, "rx1") == 0) {
+ rv = BLADERF_CHANNEL_RX(0);
+ } else if (strcasecmp(str, "rx2") == 0) {
+ rv = BLADERF_CHANNEL_RX(1);
+ } else if (strcasecmp(str, "tx") == 0 || strcasecmp(str, "tx1") == 0) {
+ rv = BLADERF_CHANNEL_TX(0);
+ } else if (strcasecmp(str, "tx2") == 0) {
+ rv = BLADERF_CHANNEL_TX(1);
+ } else {
+ rv = BLADERF_CHANNEL_INVALID;
+ }
+
+ return rv;
+}
+
+bladerf_direction channel2direction (bladerf_channel ch) {
+ if (ch == BLADERF_CHANNEL_RX(0) || ch == BLADERF_CHANNEL_RX(1)) {
+ return BLADERF_RX;
+ } else {
+ return BLADERF_TX;
+ }
+}
+
+const char *direction2str(bladerf_direction dir)
+{
+ switch (dir) {
+ case BLADERF_RX:
+ return "RX";
+ case BLADERF_TX:
+ return "TX";
+ default:
+ return "Unknown";
+ }
+}
+
+const char *trigger2str(bladerf_trigger_signal trigger)
+{
+ switch (trigger) {
+ case BLADERF_TRIGGER_J71_4:
+ return "J71-4";
+
+ case BLADERF_TRIGGER_J51_1:
+ return "J51-1";
+
+ case BLADERF_TRIGGER_MINI_EXP_1:
+ return "MiniExp-1";
+
+ case BLADERF_TRIGGER_USER_0:
+ return "User-0";
+
+ case BLADERF_TRIGGER_USER_1:
+ return "User-1";
+
+ case BLADERF_TRIGGER_USER_2:
+ return "User-2";
+
+ case BLADERF_TRIGGER_USER_3:
+ return "User-3";
+
+ case BLADERF_TRIGGER_USER_4:
+ return "User-4";
+
+ case BLADERF_TRIGGER_USER_5:
+ return "User-5";
+
+ case BLADERF_TRIGGER_USER_6:
+ return "User-6";
+
+ case BLADERF_TRIGGER_USER_7:
+ return "User-7";
+
+ default:
+ return "Unknown";
+ }
+}
+
+bladerf_trigger_signal str2trigger(const char *str)
+{
+ if (!strcasecmp("J71-4", str)) {
+ return BLADERF_TRIGGER_J71_4;
+ } else if (!strcasecmp("J51-1", str)) {
+ return BLADERF_TRIGGER_J51_1;
+ } else if (!strcasecmp("Miniexp-1", str)) {
+ return BLADERF_TRIGGER_MINI_EXP_1;
+ } else if (!strcasecmp("User-0", str)) {
+ return BLADERF_TRIGGER_USER_0;
+ } else if (!strcasecmp("User-1", str)) {
+ return BLADERF_TRIGGER_USER_1;
+ } else if (!strcasecmp("User-2", str)) {
+ return BLADERF_TRIGGER_USER_2;
+ } else if (!strcasecmp("User-3", str)) {
+ return BLADERF_TRIGGER_USER_3;
+ } else if (!strcasecmp("User-4", str)) {
+ return BLADERF_TRIGGER_USER_4;
+ } else if (!strcasecmp("User-5", str)) {
+ return BLADERF_TRIGGER_USER_5;
+ } else if (!strcasecmp("User-6", str)) {
+ return BLADERF_TRIGGER_USER_6;
+ } else if (!strcasecmp("User-7", str)) {
+ return BLADERF_TRIGGER_USER_7;
+ } else {
+ return BLADERF_TRIGGER_INVALID;
+ }
+}
+
+const char *triggerrole2str(bladerf_trigger_role role)
+{
+ switch (role) {
+ case BLADERF_TRIGGER_ROLE_MASTER:
+ return "Master";
+ case BLADERF_TRIGGER_ROLE_SLAVE:
+ return "Slave";
+ case BLADERF_TRIGGER_ROLE_DISABLED:
+ return "Disabled";
+ default:
+ return "Unknown";
+ }
+}
+
+bladerf_trigger_role str2triggerrole(const char *str)
+{
+ if (!strcasecmp("Master", str)) {
+ return BLADERF_TRIGGER_ROLE_MASTER;
+ } else if (!strcasecmp("Slave", str)) {
+ return BLADERF_TRIGGER_ROLE_SLAVE;
+ } else if (!strcasecmp("Disabled", str) || !strcasecmp("Off", str)) {
+ return BLADERF_TRIGGER_ROLE_DISABLED;
+ } else {
+ return BLADERF_TRIGGER_ROLE_INVALID;
+ }
+}
+
+int str2loopback(const char *str, bladerf_loopback *loopback)
+{
+ int status = 0;
+
+ if (!strcasecmp("firmware", str)) {
+ *loopback = BLADERF_LB_FIRMWARE;
+ } else if (!strcasecmp("bb_txlpf_rxvga2", str)) {
+ *loopback = BLADERF_LB_BB_TXLPF_RXVGA2;
+ } else if (!strcasecmp("bb_txlpf_rxlpf", str)) {
+ *loopback = BLADERF_LB_BB_TXLPF_RXLPF;
+ } else if (!strcasecmp("bb_txvga1_rxvga2", str)) {
+ *loopback = BLADERF_LB_BB_TXVGA1_RXVGA2;
+ } else if (!strcasecmp("bb_txvga1_rxlpf", str)) {
+ *loopback = BLADERF_LB_BB_TXVGA1_RXLPF;
+ } else if (!strcasecmp("rf_lna1", str)) {
+ *loopback = BLADERF_LB_RF_LNA1;
+ } else if (!strcasecmp("rf_lna2", str)) {
+ *loopback = BLADERF_LB_RF_LNA2;
+ } else if (!strcasecmp("rf_lna3", str)) {
+ *loopback = BLADERF_LB_RF_LNA3;
+ } else if (!strcasecmp("rfic_bist", str)) {
+ *loopback = BLADERF_LB_RFIC_BIST;
+ } else if (!strcasecmp("none", str)) {
+ *loopback = BLADERF_LB_NONE;
+ } else {
+ status = -1;
+ }
+
+ return status;
+}
+
+char const *loopback2str(bladerf_loopback loopback)
+{
+ switch (loopback) {
+ case BLADERF_LB_BB_TXLPF_RXVGA2:
+ return "bb_txlpf_rxvga2";
+
+ case BLADERF_LB_BB_TXLPF_RXLPF:
+ return "bb_txlpf_rxlpf";
+
+ case BLADERF_LB_BB_TXVGA1_RXVGA2:
+ return "bb_txvga1_rxvga2";
+
+ case BLADERF_LB_BB_TXVGA1_RXLPF:
+ return "bb_txvga1_rxlpf";
+
+ case BLADERF_LB_RF_LNA1:
+ return "rf_lna1";
+
+ case BLADERF_LB_RF_LNA2:
+ return "rf_lna2";
+
+ case BLADERF_LB_RF_LNA3:
+ return "rf_lna3";
+
+ case BLADERF_LB_FIRMWARE:
+ return "firmware";
+
+ case BLADERF_LB_NONE:
+ return "none";
+
+ case BLADERF_LB_RFIC_BIST:
+ return "rfic_bist";
+
+ default:
+ return "unknown";
+ }
+}
+
+int str2lnagain(const char *str, bladerf_lna_gain *gain)
+{
+ *gain = BLADERF_LNA_GAIN_MAX;
+
+ if (!strcasecmp("max", str) || !strcasecmp("BLADERF_LNA_GAIN_MAX", str)) {
+ *gain = BLADERF_LNA_GAIN_MAX;
+ return 0;
+ } else if (!strcasecmp("mid", str) ||
+ !strcasecmp("BLADERF_LNA_GAIN_MID", str)) {
+ *gain = BLADERF_LNA_GAIN_MID;
+ return 0;
+ } else if (!strcasecmp("bypass", str) ||
+ !strcasecmp("BLADERF_LNA_GAIN_BYPASS", str)) {
+ *gain = BLADERF_LNA_GAIN_BYPASS;
+ return 0;
+ } else {
+ *gain = BLADERF_LNA_GAIN_UNKNOWN;
+ return -1;
+ }
+}
+
+char const *tuningmode2str(bladerf_tuning_mode mode)
+{
+ switch (mode) {
+ case BLADERF_TUNING_MODE_HOST:
+ return "Host";
+ case BLADERF_TUNING_MODE_FPGA:
+ return "FPGA";
+ default:
+ return "Unknown";
+ }
+}
+
+const char *backend_description(bladerf_backend b)
+{
+ switch (b) {
+ case BLADERF_BACKEND_ANY:
+ return "Any";
+
+ case BLADERF_BACKEND_LINUX:
+ return "Linux kernel driver";
+
+ case BLADERF_BACKEND_LIBUSB:
+ return "libusb";
+
+ case BLADERF_BACKEND_CYPRESS:
+ return "Cypress driver";
+
+ case BLADERF_BACKEND_DUMMY:
+ return "Dummy";
+
+ default:
+ return "Unknown";
+ }
+}
+
+void sc16q11_to_float(const int16_t *in, float *out, unsigned int n)
+{
+ unsigned int i;
+
+ for (i = 0; i < (2 * n); i += 2) {
+ out[i] = (float)in[i] * (1.0f / 2048.0f);
+ out[i + 1] = (float)in[i + 1] * (1.0f / 2048.0f);
+ }
+}
+
+void float_to_sc16q11(const float *in, int16_t *out, unsigned int n)
+{
+ unsigned int i;
+
+ for (i = 0; i < (2 * n); i += 2) {
+ out[i] = (int16_t)(in[i] * 2048.0f);
+ out[i + 1] = (int16_t)(in[i + 1] * 2048.0f);
+ }
+}
+
+bladerf_cal_module str_to_bladerf_cal_module(const char *str)
+{
+ bladerf_cal_module module = BLADERF_DC_CAL_INVALID;
+
+ if (!strcasecmp(str, "lpf_tuning") || !strcasecmp(str, "lpftuning") ||
+ !strcasecmp(str, "tuning")) {
+ module = BLADERF_DC_CAL_LPF_TUNING;
+ } else if (!strcasecmp(str, "tx_lpf") || !strcasecmp(str, "txlpf")) {
+ module = BLADERF_DC_CAL_TX_LPF;
+ } else if (!strcasecmp(str, "rx_lpf") || !strcasecmp(str, "rxlpf")) {
+ module = BLADERF_DC_CAL_RX_LPF;
+ } else if (!strcasecmp(str, "rx_vga2") || !strcasecmp(str, "rxvga2")) {
+ module = BLADERF_DC_CAL_RXVGA2;
+ }
+
+ return module;
+}
+
+const char *smb_mode_to_str(bladerf_smb_mode mode)
+{
+ switch (mode) {
+ case BLADERF_SMB_MODE_DISABLED:
+ return "Disabled";
+
+ case BLADERF_SMB_MODE_OUTPUT:
+ return "Output";
+
+ case BLADERF_SMB_MODE_INPUT:
+ return "Input";
+
+ case BLADERF_SMB_MODE_UNAVAILBLE:
+ return "Unavailable";
+
+ default:
+ return "Unknown";
+ }
+};
+
+bladerf_smb_mode str_to_smb_mode(const char *str)
+{
+ if (!strcasecmp(str, "disabled") || !strcasecmp(str, "off")) {
+ return BLADERF_SMB_MODE_DISABLED;
+ } else if (!strcasecmp(str, "output")) {
+ return BLADERF_SMB_MODE_OUTPUT;
+ } else if (!strcasecmp(str, "input")) {
+ return BLADERF_SMB_MODE_INPUT;
+ } else if (!strcasecmp(str, "unavailable")) {
+ return BLADERF_SMB_MODE_UNAVAILBLE;
+ } else {
+ return BLADERF_SMB_MODE_INVALID;
+ }
+}
+
+bladerf_tuning_mode str_to_tuning_mode(const char *str)
+{
+ if (!strcasecmp(str, "fpga")) {
+ return BLADERF_TUNING_MODE_FPGA;
+ } else if (!strcasecmp(str, "host")) {
+ return BLADERF_TUNING_MODE_HOST;
+ } else {
+ return BLADERF_TUNING_MODE_INVALID;
+ }
+}
+
+unsigned int str2uint(const char *str,
+ unsigned int min,
+ unsigned int max,
+ bool *ok)
+{
+ unsigned int ret;
+ char *optr;
+
+ errno = 0;
+ ret = strtoul(str, &optr, 0);
+
+ if (errno == ERANGE || (errno != 0 && ret == 0)) {
+ *ok = false;
+ return 0;
+ }
+
+ if (str == optr) {
+ *ok = false;
+ return 0;
+ }
+
+ if (ret >= min && ret <= max) {
+ *ok = true;
+ return (unsigned int)ret;
+ }
+
+ *ok = false;
+ return 0;
+}
+
+int str2int(const char *str, int min, int max, bool *ok)
+{
+ long int ret;
+ char *optr;
+
+ errno = 0;
+ ret = strtol(str, &optr, 0);
+
+ if ((errno == ERANGE && (ret == LONG_MAX || ret == LONG_MIN)) ||
+ (errno != 0 && ret == 0)) {
+ *ok = false;
+ return 0;
+ }
+
+ if (str == optr) {
+ *ok = false;
+ return 0;
+ }
+
+ if (ret >= min && ret <= max) {
+ *ok = true;
+ return (int)ret;
+ }
+
+ *ok = false;
+ return 0;
+}
+
+uint64_t str2uint64(const char *str, uint64_t min, uint64_t max, bool *ok)
+{
+ uint64_t ret;
+ char *optr;
+
+ errno = 0;
+ ret = (uint64_t)strtod(str, &optr);
+
+ if ((errno == ERANGE && ret == ULONG_MAX) || (errno != 0 && ret == 0)) {
+ *ok = false;
+ return 0;
+ }
+
+ if (str == optr) {
+ *ok = false;
+ return 0;
+ }
+
+ if (ret >= min && ret <= max) {
+ *ok = true;
+ return ret;
+ }
+
+ *ok = false;
+ return 0;
+}
+
+double str2double(const char *str, double min, double max, bool *ok)
+{
+ double ret;
+ char *optr;
+
+ errno = 0;
+ ret = strtod(str, &optr);
+
+ if (errno == ERANGE || (errno != 0 && ret == 0)) {
+ *ok = false;
+ return NAN;
+ }
+
+ if (str == optr) {
+ *ok = false;
+ return NAN;
+ }
+
+ if (ret >= min && ret <= max) {
+ *ok = true;
+ return ret;
+ }
+
+ *ok = false;
+ return NAN;
+}
+
+static uint64_t suffix_multiplier(const char *str,
+ const struct numeric_suffix *suffixes,
+ const size_t num_suff,
+ bool *ok)
+{
+ unsigned i;
+
+ *ok = true;
+
+ if (!strlen(str))
+ return 1;
+
+ for (i = 0; i < num_suff; i++) {
+ if (!strcasecmp(suffixes[i].suffix, str)) {
+ return suffixes[i].multiplier;
+ }
+ }
+
+ *ok = false;
+ return 0;
+}
+
+unsigned int str2uint_suffix(const char *str,
+ unsigned int min,
+ unsigned int max,
+ const struct numeric_suffix *suffixes,
+ const size_t num_suff,
+ bool *ok)
+{
+ uint64_t mult;
+ unsigned int rv;
+ double val;
+ char *optr;
+
+ errno = 0;
+ val = strtod(str, &optr);
+
+ if (errno == ERANGE || (errno != 0 && val == 0)) {
+ *ok = false;
+ return 0;
+ }
+
+ if (str == optr) {
+ *ok = false;
+ return 0;
+ }
+
+ mult = suffix_multiplier(optr, suffixes, num_suff, ok);
+ if (!*ok)
+ return false;
+
+ rv = (unsigned int)(val * mult);
+
+ if (rv >= min && rv <= max) {
+ return rv;
+ }
+
+ *ok = false;
+ return 0;
+}
+
+uint64_t str2uint64_suffix(const char *str,
+ uint64_t min,
+ uint64_t max,
+ const struct numeric_suffix *suffixes,
+ const size_t num_suff,
+ bool *ok)
+{
+ uint64_t mult, rv;
+ long double val;
+ char *optr;
+
+ errno = 0;
+ val = strtold(str, &optr);
+
+ if (errno == ERANGE && (errno != 0 && val == 0)) {
+ *ok = false;
+ return 0;
+ }
+
+ if (str == optr) {
+ *ok = false;
+ return 0;
+ }
+
+ mult = suffix_multiplier(optr, suffixes, num_suff, ok);
+ if (!*ok)
+ return false;
+
+ rv = (uint64_t)(val * mult);
+ if (rv >= min && rv <= max) {
+ return rv;
+ }
+
+ *ok = false;
+ return 0;
+}
+
+int str2bool(const char *str, bool *val)
+{
+ unsigned int i;
+
+ char *str_true[] = { "true", "t", "one", "1", "enable", "en", "on" };
+ char *str_false[] = { "false", "f", "zero", "0", "disable", "dis", "off" };
+
+ for (i = 0; i < ARRAY_SIZE(str_true); i++) {
+ if (!strcasecmp(str_true[i], str)) {
+ *val = true;
+ return 0;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(str_false); i++) {
+ if (!strcasecmp(str_false[i], str)) {
+ *val = false;
+ return 0;
+ }
+ }
+
+ return BLADERF_ERR_INVAL;
+}
diff --git a/Radio/HW/BladeRF/common/src/dc_calibration.c b/Radio/HW/BladeRF/common/src/dc_calibration.c
new file mode 100644
index 0000000..c746c3c
--- /dev/null
+++ b/Radio/HW/BladeRF/common/src/dc_calibration.c
@@ -0,0 +1,1745 @@
+/**
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (c) 2015 Nuand LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <limits.h>
+
+#define _USE_MATH_DEFINES /* Required for MSVC */
+#include <math.h>
+
+#include <libbladeRF.h>
+
+#include "dc_calibration.h"
+#include "conversions.h"
+
+struct complexf {
+ float i;
+ float q;
+};
+
+struct gain_mode {
+ bladerf_lna_gain lna_gain;
+ int rxvga1, rxvga2;
+};
+/*******************************************************************************
+ * Debug items
+ ******************************************************************************/
+
+/* Enable this to print diagnostic and debug information */
+//#define ENABLE_DC_CALIBRATION_DEBUG
+//#define ENABLE_DC_CALIBRATION_VERBOSE
+
+#ifndef PR_DBG
+# ifdef ENABLE_DC_CALIBRATION_DEBUG
+# define PR_DBG(...) fprintf(stderr, " " __VA_ARGS__)
+# else
+# define PR_DBG(...) do {} while (0)
+# endif
+#endif
+
+#ifndef PR_VERBOSE
+# ifdef ENABLE_DC_CALIBRATION_VERBOSE
+# define PR_VERBOSE(...) fprintf(stderr, " " __VA_ARGS__)
+# else
+# define PR_VERBOSE(...) do {} while (0)
+# endif
+#endif
+
+/*******************************************************************************
+ * Debug routines for saving samples
+ ******************************************************************************/
+
+//#define ENABLE_SAVE_SC16Q11
+#ifdef ENABLE_SAVE_SC16Q11
+static void save_sc16q11(const char *name, int16_t *samples, unsigned int count)
+{
+ FILE *out = fopen(name, "wb");
+ if (!out) {
+ return;
+ }
+
+ fwrite(samples, 2 * sizeof(samples[0]), count, out);
+ fclose(out);
+}
+#else
+# define save_sc16q11(name, samples, count) do {} while (0)
+#endif
+
+//#define ENABLE_SAVE_COMPLEXF
+#ifdef ENABLE_SAVE_COMPLEXF
+static void save_complexf(const char *name, struct complexf *samples,
+ unsigned int count)
+{
+ unsigned int n;
+ FILE *out = fopen(name, "wb");
+ if (!out) {
+ return;
+ }
+
+ for (n = 0; n < count; n++) {
+ fwrite(&samples[n].i, sizeof(samples[n].i), 1, out);
+ fwrite(&samples[n].q, sizeof(samples[n].q), 1, out);
+ }
+
+ fclose(out);
+}
+#else
+# define save_complexf(name, samples, count) do {} while (0)
+#endif
+
+
+/*******************************************************************************
+ * LMS6002D DC offset calibration
+ ******************************************************************************/
+
+/* We've found that running samples through the LMS6 tends to be required
+ * for the TX LPF calibration to converge */
+static inline int tx_lpf_dummy_tx(struct bladerf *dev)
+{
+ int status;
+ int retval = 0;
+ struct bladerf_metadata meta;
+ int16_t zero_sample[] = { 0, 0 };
+
+ bladerf_loopback loopback_backup;
+ struct bladerf_rational_rate sample_rate_backup;
+
+ memset(&meta, 0, sizeof(meta));
+
+ status = bladerf_get_loopback(dev, &loopback_backup);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_get_rational_sample_rate(dev, BLADERF_MODULE_TX,
+ &sample_rate_backup);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_set_loopback(dev, BLADERF_LB_BB_TXVGA1_RXVGA2);
+ if (status != 0) {
+ goto out;
+ }
+
+ status = bladerf_set_sample_rate(dev, BLADERF_MODULE_TX, 3000000, NULL);
+ if (status != 0) {
+ goto out;
+ }
+
+ status = bladerf_sync_config(dev, BLADERF_MODULE_TX,
+ BLADERF_FORMAT_SC16_Q11_META,
+ 64, 16384, 16, 1000);
+ if (status != 0) {
+ goto out;
+ }
+
+ status = bladerf_enable_module(dev, BLADERF_MODULE_TX, true);
+ if (status != 0) {
+ goto out;
+ }
+
+ meta.flags = BLADERF_META_FLAG_TX_BURST_START |
+ BLADERF_META_FLAG_TX_BURST_END |
+ BLADERF_META_FLAG_TX_NOW;
+
+ status = bladerf_sync_tx(dev, zero_sample, 1, &meta, 2000);
+ if (status != 0) {
+ goto out;
+ }
+
+out:
+ status = bladerf_enable_module(dev, BLADERF_MODULE_TX, false);
+ if (status != 0 && retval == 0) {
+ retval = status;
+ }
+
+ status = bladerf_set_rational_sample_rate(dev, BLADERF_MODULE_TX,
+ &sample_rate_backup, NULL);
+ if (status != 0 && retval == 0) {
+ retval = status;
+ }
+
+ status = bladerf_set_loopback(dev, loopback_backup);
+ if (status != 0 && retval == 0) {
+ retval = status;
+ }
+
+ return retval;
+}
+
+static int cal_tx_lpf(struct bladerf *dev)
+{
+ int status;
+
+ status = tx_lpf_dummy_tx(dev);
+ if (status == 0) {
+ status = bladerf_calibrate_dc(dev, BLADERF_DC_CAL_TX_LPF);
+ }
+
+ return status;
+}
+
+int dc_calibration_lms6(struct bladerf *dev, const char *module_str)
+{
+ int status;
+ bladerf_cal_module module;
+
+ if (!strcasecmp(module_str, "all")) {
+ status = bladerf_calibrate_dc(dev, BLADERF_DC_CAL_LPF_TUNING);
+ if (status != 0) {
+ return status;
+ }
+
+ status = cal_tx_lpf(dev);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_calibrate_dc(dev, BLADERF_DC_CAL_RX_LPF);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_calibrate_dc(dev, BLADERF_DC_CAL_RXVGA2);
+ } else {
+ module = str_to_bladerf_cal_module(module_str);
+ if (module == BLADERF_DC_CAL_INVALID) {
+ return BLADERF_ERR_INVAL;
+ }
+
+ if (module == BLADERF_DC_CAL_TX_LPF) {
+ status = cal_tx_lpf(dev);
+ } else {
+ status = bladerf_calibrate_dc(dev, module);
+ }
+ }
+
+ return status;
+}
+
+
+
+/*******************************************************************************
+ * Shared utility routines
+ ******************************************************************************/
+
+/* Round float to int16_t */
+static inline int16_t float_to_int16(float val)
+{
+ if ((val - 0.5) <= INT16_MIN) {
+ return INT16_MIN;
+ }
+ if ((val + 0.5) >= INT16_MAX) {
+ return INT16_MAX;
+ }
+ return val >= 0 ? (int16_t)(val + 0.5) : (int16_t)(val - 0.5);
+}
+
+/* Convert ms to samples */
+#define MS_TO_SAMPLES(ms_, rate_) (\
+ (unsigned int) (ms_ * ((uint64_t) rate_) / 1000) \
+)
+
+/* RX samples, retrying if the machine is struggling to keep up. */
+static int rx_samples(struct bladerf *dev, int16_t *samples,
+ unsigned int count, uint64_t *ts, uint64_t ts_inc)
+{
+ int status = 0;
+ struct bladerf_metadata meta;
+ int retry = 0;
+ const int max_retries = 10;
+ bool overrun = true;
+
+ memset(&meta, 0, sizeof(meta));
+ meta.timestamp = *ts;
+
+ while (status == 0 && overrun && retry < max_retries) {
+ meta.timestamp = *ts;
+ status = bladerf_sync_rx(dev, samples, count, &meta, 2000);
+
+ if (status == BLADERF_ERR_TIME_PAST) {
+ status = bladerf_get_timestamp(dev, BLADERF_MODULE_RX, ts);
+ if (status != 0) {
+ return status;
+ } else {
+ *ts += 20 * ts_inc;
+ retry++;
+ status = 0;
+ }
+ } else if (status == 0) {
+ overrun = (meta.flags & BLADERF_META_STATUS_OVERRUN) != 0;
+ if (overrun) {
+ *ts += count + ts_inc;
+ retry++;
+ }
+ } else {
+ return status;
+ }
+ }
+
+ if (retry >= max_retries) {
+ status = BLADERF_ERR_IO;
+ } else if (status == 0) {
+ *ts += count + ts_inc;
+ }
+
+ return status;
+}
+
+
+
+/*******************************************************************************
+ * RX DC offset calibration
+ ******************************************************************************/
+
+#define RX_CAL_RATE (3000000)
+#define RX_CAL_BW (1500000)
+#define RX_CAL_TS_INC (MS_TO_SAMPLES(15, RX_CAL_RATE))
+#define RX_CAL_COUNT (MS_TO_SAMPLES(5, RX_CAL_RATE))
+
+#define RX_CAL_MAX_SWEEP_LEN (2 * 2048 / 32) /* -2048 : 32 : 2048 */
+
+struct rx_cal {
+ struct bladerf *dev;
+
+ int16_t *samples;
+ unsigned int num_samples;
+
+ int16_t *corr_sweep;
+
+ uint64_t ts;
+
+ uint64_t tx_freq;
+};
+
+struct rx_cal_backup {
+ struct bladerf_rational_rate rational_sample_rate;
+ unsigned int bandwidth;
+ uint64_t tx_freq;
+};
+
+static int get_rx_cal_backup(struct bladerf *dev, struct rx_cal_backup *b)
+{
+ int status;
+
+ status = bladerf_get_rational_sample_rate(dev, BLADERF_MODULE_RX,
+ &b->rational_sample_rate);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_get_bandwidth(dev, BLADERF_MODULE_RX, &b->bandwidth);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_get_frequency(dev, BLADERF_MODULE_TX, &b->tx_freq);
+ if (status != 0) {
+ return status;
+ }
+
+ return status;
+}
+
+static int set_rx_cal_backup(struct bladerf *dev, struct rx_cal_backup *b)
+{
+ int status;
+ int retval = 0;
+
+ status = bladerf_set_rational_sample_rate(dev, BLADERF_MODULE_RX,
+ &b->rational_sample_rate, NULL);
+ if (status != 0 && retval == 0) {
+ retval = status;
+ }
+
+ status = bladerf_set_bandwidth(dev, BLADERF_MODULE_RX, b->bandwidth, NULL);
+ if (status != 0 && retval == 0) {
+ retval = status;
+ }
+
+ status = bladerf_set_frequency(dev, BLADERF_MODULE_TX, b->tx_freq);
+ if (status != 0 && retval == 0) {
+ retval = status;
+ }
+
+ return retval;
+}
+
+/* Ensure TX >= 1 MHz away from the RX frequency to avoid any potential
+ * artifacts from the PLLs interfering with one another */
+static int rx_cal_update_frequency(struct rx_cal *cal, uint64_t rx_freq)
+{
+ int status = 0;
+ uint64_t f_diff;
+
+ if (rx_freq < cal->tx_freq) {
+ f_diff = cal->tx_freq - rx_freq;
+ } else {
+ f_diff = rx_freq - cal->tx_freq;
+ }
+
+ PR_DBG("Set F_RX = %u\n", rx_freq);
+ PR_DBG("F_diff(RX, TX) = %u\n", f_diff);
+
+ if (f_diff < 1000000) {
+ if (rx_freq >= (BLADERF_FREQUENCY_MIN + 1000000)) {
+ cal->tx_freq = rx_freq - 1000000;
+ } else {
+ cal->tx_freq = rx_freq + 1000000;
+ }
+
+ status = bladerf_set_frequency(cal->dev, BLADERF_MODULE_TX,
+ cal->tx_freq);
+ if (status != 0) {
+ return status;
+ }
+
+ PR_DBG("Adjusted TX frequency: %u\n", cal->tx_freq);
+ }
+
+ status = bladerf_set_frequency(cal->dev, BLADERF_MODULE_RX, rx_freq);
+ if (status != 0) {
+ return status;
+ }
+
+ cal->ts += RX_CAL_TS_INC;
+
+ return status;
+}
+
+static inline void sample_mean(int16_t *samples, size_t count,
+ float *mean_i, float *mean_q)
+{
+ int64_t accum_i = 0;
+ int64_t accum_q = 0;
+
+ size_t n;
+
+
+ if (count == 0) {
+ assert(!"Invalid count (0) provided to sample_mean()");
+ *mean_i = 0;
+ *mean_q = 0;
+ return;
+ }
+
+ for (n = 0; n < (2 * count); n += 2) {
+ accum_i += samples[n];
+ accum_q += samples[n + 1];
+ }
+
+ *mean_i = ((float) accum_i) / count;
+ *mean_q = ((float) accum_q) / count;
+}
+
+static inline int set_rx_dc_corr(struct bladerf *dev, int16_t i, int16_t q)
+{
+ int status;
+
+ status = bladerf_set_correction(dev, BLADERF_MODULE_RX,
+ BLADERF_CORR_LMS_DCOFF_I, i);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_set_correction(dev, BLADERF_MODULE_RX,
+ BLADERF_CORR_LMS_DCOFF_Q, q);
+ return status;
+}
+
+/* Get the mean for one of the coarse estimate points. If it seems that this
+ * value might be (or close) causing us to clamp, adjust it and retry */
+static int rx_cal_coarse_means(struct rx_cal *cal, int16_t *corr_value,
+ float *mean_i, float *mean_q)
+{
+ int status;
+ const int16_t mean_limit_high = 2000;
+ const int16_t mean_limit_low = -mean_limit_high;
+ const int16_t corr_limit = 128;
+ bool retry = false;
+
+ do {
+ status = set_rx_dc_corr(cal->dev, *corr_value, *corr_value);
+ if (status != 0) {
+ return status;
+ }
+
+ status = rx_samples(cal->dev, cal->samples, cal->num_samples,
+ &cal->ts, RX_CAL_TS_INC);
+ if (status != 0) {
+ return status;
+ }
+
+ sample_mean(cal->samples, cal->num_samples, mean_i, mean_q);
+
+ if (*mean_i > mean_limit_high || *mean_q > mean_limit_high ||
+ *mean_i < mean_limit_low || *mean_q < mean_limit_low ) {
+
+ if (*corr_value < 0) {
+ retry = (*corr_value <= -corr_limit);
+ } else {
+ retry = (*corr_value >= corr_limit);
+ }
+
+ if (retry) {
+ PR_DBG("Coarse estimate point Corr=%4d yields extreme means: "
+ "(%4f, %4f). Retrying...\n",
+ *corr_value, *mean_i, *mean_q);
+
+ *corr_value = *corr_value / 2;
+ }
+ } else {
+ retry = false;
+ }
+ } while (retry);
+
+ if (retry) {
+ PR_DBG("Non-ideal values are being used.\n");
+ }
+
+ return 0;
+}
+
+/* Estimate the DC correction values that yield zero DC offset via a linear
+ * approximation */
+static int rx_cal_coarse_estimate(struct rx_cal *cal,
+ int16_t *i_est, int16_t *q_est)
+{
+ int status;
+ int16_t x1 = -2048;
+ int16_t x2 = 2048;
+ float y1i, y1q, y2i, y2q;
+ float mi, mq;
+ float bi, bq;
+ float i_guess, q_guess;
+
+ status = rx_cal_coarse_means(cal, &x1, &y1i, &y1q);
+ if (status != 0) {
+ *i_est = 0;
+ *q_est = 0;
+ return status;
+ }
+
+ PR_VERBOSE("Means for x1=%d: y1i=%f, y1q=%f\n", x1, y1i, y1q);
+
+ status = rx_cal_coarse_means(cal, &x2, &y2i, &y2q);
+ if (status != 0) {
+ *i_est = 0;
+ *q_est = 0;
+ return status;
+ }
+
+ PR_VERBOSE("Means for x2: y2i=%f, y2q=%f\n", y2i, y2q);
+
+ mi = (y2i - y1i) / (x2 - x1);
+ mq = (y2q - y1q) / (x2 - x1);
+
+ bi = y1i - mi * x1;
+ bq = y1q - mq * x1;
+
+ PR_VERBOSE("mi=%f, bi=%f, mq=%f, bq=%f\n", mi, bi, mq, bq);
+
+ i_guess = -bi/mi + 0.5f;
+ if (i_guess < -2048) {
+ i_guess = -2048;
+ } else if (i_guess > 2048) {
+ i_guess = 2048;
+ }
+
+ q_guess = -bq/mq + 0.5f;
+ if (q_guess < -2048) {
+ q_guess = -2048;
+ } else if (q_guess > 2048) {
+ q_guess = 2048;
+ }
+
+ *i_est = (int16_t) i_guess;
+ *q_est = (int16_t) q_guess;
+
+ PR_DBG("Coarse estimate: I=%d, Q=%d\n", *i_est, *q_est);
+
+ return 0;
+}
+
+static void init_rx_cal_sweep(int16_t *corr, unsigned int *sweep_len,
+ int16_t i_est, int16_t q_est)
+{
+ unsigned int actual_len = 0;
+ unsigned int i;
+
+ int16_t sweep_min, sweep_max, sweep_val;
+
+ /* LMS6002D RX DC calibrations have a limited range. libbladeRF throws away
+ * the lower 5 bits. */
+ const int16_t sweep_inc = 32;
+
+ const int16_t min_est = (i_est < q_est) ? i_est : q_est;
+ const int16_t max_est = (i_est > q_est) ? i_est : q_est;
+
+ sweep_min = min_est - 12 * 32;
+ if (sweep_min < -2048) {
+ sweep_min = -2048;
+ }
+
+ sweep_max = max_est + 12 * 32;
+ if (sweep_max > 2048) {
+ sweep_max = 2048;
+ }
+
+ /* Given that these lower bits are thrown away, it can be confusing to
+ * see that values change in their LSBs that don't matter. Therefore,
+ * we'll adjust to muliples of sweep_inc */
+ sweep_min = (sweep_min / 32) * 32;
+ sweep_max = (sweep_max / 32) * 32;
+
+
+ PR_DBG("Sweeping [%d : %d : %d]\n", sweep_min, sweep_inc, sweep_max);
+
+ sweep_val = sweep_min;
+ for (i = 0; sweep_val < sweep_max && i < RX_CAL_MAX_SWEEP_LEN; i++) {
+ corr[i] = sweep_val;
+ sweep_val += sweep_inc;
+ actual_len++;
+ }
+
+ *sweep_len = actual_len;
+}
+
+static int save_gains(struct rx_cal *cal, struct gain_mode *gain) {
+ int status;
+
+ status = bladerf_get_lna_gain(cal->dev, &gain->lna_gain);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_get_rxvga1(cal->dev, &gain->rxvga1);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_get_rxvga2(cal->dev, &gain->rxvga2);
+ if (status != 0) {
+ return status;
+ }
+
+ return status;
+}
+
+static int load_gains(struct rx_cal *cal, struct gain_mode *gain) {
+ int status;
+
+ status = bladerf_set_lna_gain(cal->dev, gain->lna_gain);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_set_rxvga1(cal->dev, gain->rxvga1);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_set_rxvga2(cal->dev, gain->rxvga2);
+ if (status != 0) {
+ return status;
+ }
+
+ return status;
+}
+
+static int rx_cal_dc_off(struct rx_cal *cal, struct gain_mode *gains,
+ int16_t *dc_i, int16_t *dc_q)
+{
+ int status = BLADERF_ERR_UNEXPECTED;
+
+ float mean_i, mean_q;
+
+ status = load_gains(cal, gains);
+ if (status != 0) {
+ return status;
+ }
+
+ status = rx_samples(cal->dev, cal->samples, cal->num_samples,
+ &cal->ts, RX_CAL_TS_INC);
+ if (status != 0) {
+ return status;
+ }
+
+ sample_mean(cal->samples, cal->num_samples, &mean_i, &mean_q);
+ *dc_i = float_to_int16(mean_i);
+ *dc_q = float_to_int16(mean_q);
+
+ return 0;
+}
+
+static int rx_cal_sweep(struct rx_cal *cal,
+ int16_t *corr, unsigned int sweep_len,
+ int16_t *result_i, int16_t *result_q,
+ float *error_i, float *error_q)
+{
+ int status = BLADERF_ERR_UNEXPECTED;
+ unsigned int n;
+
+ int16_t min_corr_i = 0;
+ int16_t min_corr_q = 0;
+
+ float mean_i, mean_q;
+ float min_val_i, min_val_q;
+
+ min_val_i = min_val_q = 2048;
+
+ for (n = 0; n < sweep_len; n++) {
+ status = set_rx_dc_corr(cal->dev, corr[n], corr[n]);
+ if (status != 0) {
+ return status;
+ }
+
+ status = rx_samples(cal->dev, cal->samples, cal->num_samples,
+ &cal->ts, RX_CAL_TS_INC);
+ if (status != 0) {
+ return status;
+ }
+
+ sample_mean(cal->samples, cal->num_samples, &mean_i, &mean_q);
+
+ PR_VERBOSE(" Corr=%4d, Mean_I=%4.2f, Mean_Q=%4.2f\n",
+ corr[n], mean_i, mean_q);
+
+ /* Not using fabs() to avoid adding a -lm dependency */
+ if (mean_i < 0) {
+ mean_i = -mean_i;
+ }
+
+ if (mean_q < 0) {
+ mean_q = -mean_q;
+ }
+
+ if (mean_i < min_val_i) {
+ min_val_i = mean_i;
+ min_corr_i = corr[n];
+ }
+
+ if (mean_q < min_val_q) {
+ min_val_q = mean_q;
+ min_corr_q = corr[n];
+ }
+ }
+
+ *result_i = min_corr_i;
+ *result_q = min_corr_q;
+ *error_i = min_val_i;
+ *error_q = min_val_q;
+
+ return 0;
+}
+
+static int perform_rx_cal(struct rx_cal *cal, struct dc_calibration_params *p)
+{
+ int status;
+ int16_t i_est, q_est;
+ unsigned int sweep_len = RX_CAL_MAX_SWEEP_LEN;
+ struct gain_mode saved_gains;
+
+ struct gain_mode agc_gains[] = {
+ { .lna_gain = BLADERF_LNA_GAIN_MAX, .rxvga1 = 30, .rxvga2 = 15 }, /* AGC Max Gain */
+ { .lna_gain = BLADERF_LNA_GAIN_MID, .rxvga1 = 30, .rxvga2 = 0 }, /* AGC Mid Gain */
+ { .lna_gain = BLADERF_LNA_GAIN_MID, .rxvga1 = 12, .rxvga2 = 0 } /* AGC Min Gain */
+ };
+
+ status = rx_cal_update_frequency(cal, p->frequency);
+ if (status != 0) {
+ return status;
+ }
+
+ /* Get an initial guess at our correction values */
+ status = rx_cal_coarse_estimate(cal, &i_est, &q_est);
+ if (status != 0) {
+ return status;
+ }
+
+ /* Perform a finer sweep of correction values */
+ init_rx_cal_sweep(cal->corr_sweep, &sweep_len, i_est, q_est);
+
+ /* Advance our timestmap just to account for any time we may have lost */
+ cal->ts += RX_CAL_TS_INC;
+
+ status = rx_cal_sweep(cal, cal->corr_sweep, sweep_len,
+ &p->corr_i, &p->corr_q,
+ &p->error_i, &p->error_q);
+
+ if (status != 0) {
+ return status;
+ }
+
+ /* Apply the nominal correction values */
+ status = set_rx_dc_corr(cal->dev, p->corr_i, p->corr_q);
+ if (status != 0) {
+ return status;
+ }
+
+ bladerf_fpga_size fpga_size;
+ status = bladerf_get_fpga_size(cal->dev, &fpga_size);
+ if (status != 0) {
+ return status;
+ }
+
+ if (fpga_size != BLADERF_FPGA_40KLE &&
+ fpga_size != BLADERF_FPGA_115KLE) {
+ return 0;
+ }
+
+ /* Measure DC correction for AGC */
+ status = save_gains(cal, &saved_gains);
+ if (status != 0) {
+ return status;
+ }
+
+ status = rx_cal_dc_off(cal, &agc_gains[2], &p->min_dc_i, &p->min_dc_q);
+ if (status != 0) {
+ return status;
+ }
+
+ status = rx_cal_dc_off(cal, &agc_gains[1], &p->mid_dc_i, &p->mid_dc_q);
+ if (status != 0) {
+ return status;
+ }
+
+ status = rx_cal_dc_off(cal, &agc_gains[0], &p->max_dc_i, &p->max_dc_q);
+ if (status != 0) {
+ return status;
+ }
+
+ status = load_gains(cal, &saved_gains);
+
+ return status;
+}
+
+static int rx_cal_init_state(struct bladerf *dev,
+ const struct rx_cal_backup *backup,
+ struct rx_cal *state)
+{
+ int status;
+
+ state->dev = dev;
+
+ state->num_samples = RX_CAL_COUNT;
+
+ state->samples = malloc(2 * sizeof(state->samples[0]) * RX_CAL_COUNT);
+ if (state->samples == NULL) {
+ return BLADERF_ERR_MEM;
+ }
+
+ state->corr_sweep = malloc(sizeof(state->corr_sweep[0]) * RX_CAL_MAX_SWEEP_LEN);
+ if (state->corr_sweep == NULL) {
+ return BLADERF_ERR_MEM;
+ }
+
+ state->tx_freq = backup->tx_freq;
+
+ status = bladerf_get_timestamp(dev, BLADERF_MODULE_RX, &state->ts);
+ if (status != 0) {
+ return status;
+ }
+
+ /* Schedule first RX well into the future */
+ state->ts += 20 * RX_CAL_TS_INC;
+
+ return status;
+}
+
+static int rx_cal_init(struct bladerf *dev)
+{
+ int status;
+
+ status = bladerf_set_sample_rate(dev, BLADERF_MODULE_RX, RX_CAL_RATE, NULL);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_set_bandwidth(dev, BLADERF_MODULE_RX, RX_CAL_BW, NULL);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_sync_config(dev, BLADERF_MODULE_RX,
+ BLADERF_FORMAT_SC16_Q11_META,
+ 64, 16384, 16, 1000);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_enable_module(dev, BLADERF_MODULE_RX, true);
+ if (status != 0) {
+ return status;
+ }
+
+ return status;
+}
+
+int dc_calibration_rx(struct bladerf *dev,
+ struct dc_calibration_params *params,
+ size_t params_count, bool print_status)
+{
+ int status = 0;
+ int retval = 0;
+ struct rx_cal state;
+ struct rx_cal_backup backup;
+ size_t i;
+
+ memset(&state, 0, sizeof(state));
+
+ status = get_rx_cal_backup(dev, &backup);
+ if (status != 0) {
+ return status;
+ }
+
+ status = rx_cal_init(dev);
+ if (status != 0) {
+ goto out;
+ }
+
+ status = rx_cal_init_state(dev, &backup, &state);
+ if (status != 0) {
+ goto out;
+ }
+
+ for (i = 0; i < params_count && status == 0; i++) {
+ status = perform_rx_cal(&state, &params[i]);
+
+ if (status == 0 && print_status) {
+# ifdef DEBUG_DC_CALIBRATION
+ const char sol = '\n';
+ const char eol = '\n';
+# else
+ const char sol = '\r';
+ const char eol = '\0';
+# endif
+ printf("%cCalibrated @ %10" PRIu64 " Hz: I=%4d (Error: %4.2f), "
+ "Q=%4d (Error: %4.2f) ",
+ sol,
+ params[i].frequency,
+ params[i].corr_i, params[i].error_i,
+ params[i].corr_q, params[i].error_q);
+ printf("DC-LUT: Max (I=%3d, Q=%3d) Mid (I=%3d, Q=%3d)"
+ " Min (I=%3d, Q=%3d)%c",
+ params[i].max_dc_i, params[i].max_dc_q, params[i].mid_dc_i, params[i].mid_dc_q,
+ params[i].min_dc_i, params[i].min_dc_q, eol);
+ fflush(stdout);
+ }
+ }
+
+ if (print_status) {
+ putchar('\n');
+ }
+
+out:
+ free(state.samples);
+ free(state.corr_sweep);
+
+ retval = status;
+
+ status = bladerf_enable_module(dev, BLADERF_MODULE_RX, false);
+ if (status != 0 && retval == 0) {
+ retval = status;
+ }
+
+ status = set_rx_cal_backup(dev, &backup);
+ if (status != 0 && retval == 0) {
+ retval = status;
+ }
+
+ return retval;
+}
+
+
+
+/*******************************************************************************
+ * TX DC offset calibration
+ ******************************************************************************/
+
+#define TX_CAL_RATE (4000000)
+
+#define TX_CAL_RX_BW (3000000)
+#define TX_CAL_RX_LNA (BLADERF_LNA_GAIN_MAX)
+#define TX_CAL_RX_VGA1 (25)
+#define TX_CAL_RX_VGA2 (0)
+
+#define TX_CAL_TX_BW (1500000)
+
+#define TX_CAL_TS_INC (MS_TO_SAMPLES(15, TX_CAL_RATE))
+#define TX_CAL_COUNT (MS_TO_SAMPLES(5, TX_CAL_RATE))
+
+#define TX_CAL_CORR_SWEEP_LEN (4096 / 16) /* -2048:16:2048 */
+
+#define TX_CAL_DEFAULT_LB (BLADERF_LB_RF_LNA1)
+
+struct tx_cal_backup {
+ uint64_t rx_freq;
+ struct bladerf_rational_rate rx_sample_rate;
+ unsigned int rx_bandwidth;
+
+ bladerf_lna_gain rx_lna;
+ int rx_vga1;
+ int rx_vga2;
+
+ struct bladerf_rational_rate tx_sample_rate;
+ unsigned int tx_bandwidth;
+
+ bladerf_loopback loopback;
+};
+
+struct tx_cal {
+ struct bladerf *dev;
+ int16_t *samples; /* Raw samples */
+ unsigned int num_samples; /* Number of raw samples */
+ struct complexf *filt; /* Filter state */
+ struct complexf *filt_out; /* Filter output */
+ struct complexf *post_mix; /* Post-filter, mixed to baseband */
+ int16_t *sweep; /* Correction sweep */
+ float *mag; /* Magnitude results from sweep */
+ uint64_t ts; /* Timestamp */
+ bladerf_loopback loopback; /* Current loopback mode */
+ bool rx_low; /* RX tuned lower than TX */
+};
+
+/* Filter used to isolate contribution of TX LO leakage in received
+ * signal. 15th order Equiripple FIR with Fs=4e6, Fpass=1, Fstop=1e6
+ */
+static const float tx_cal_filt[] = {
+ 0.000327949366768f, 0.002460188536582f, 0.009842382390924f,
+ 0.027274728394777f, 0.057835200476419f, 0.098632713294830f,
+ 0.139062540460741f, 0.164562494987592f, 0.164562494987592f,
+ 0.139062540460741f, 0.098632713294830f, 0.057835200476419f,
+ 0.027274728394777f, 0.009842382390924f, 0.002460188536582f,
+ 0.000327949366768f,
+};
+
+static const unsigned int tx_cal_filt_num_taps =
+ (sizeof(tx_cal_filt) / sizeof(tx_cal_filt[0]));
+
+static inline int set_tx_dc_corr(struct bladerf *dev, int16_t i, int16_t q)
+{
+ int status;
+
+ status = bladerf_set_correction(dev, BLADERF_MODULE_TX,
+ BLADERF_CORR_LMS_DCOFF_I, i);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_set_correction(dev, BLADERF_MODULE_TX,
+ BLADERF_CORR_LMS_DCOFF_Q, q);
+ return status;
+}
+
+static int get_tx_cal_backup(struct bladerf *dev, struct tx_cal_backup *b)
+{
+ int status;
+
+ status = bladerf_get_frequency(dev, BLADERF_MODULE_RX, &b->rx_freq);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_get_rational_sample_rate(dev, BLADERF_MODULE_RX,
+ &b->rx_sample_rate);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_get_bandwidth(dev, BLADERF_MODULE_RX, &b->rx_bandwidth);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_get_lna_gain(dev, &b->rx_lna);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_get_rxvga1(dev, &b->rx_vga1);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_get_rxvga2(dev, &b->rx_vga2);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_get_rational_sample_rate(dev, BLADERF_MODULE_TX,
+ &b->tx_sample_rate);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_get_loopback(dev, &b->loopback);
+
+ return status;
+}
+
+static int set_tx_cal_backup(struct bladerf *dev, struct tx_cal_backup *b)
+{
+ int status;
+ int retval = 0;
+
+ status = bladerf_set_loopback(dev, b->loopback);
+ if (status != 0 && retval == 0) {
+ retval = status;
+ }
+
+ status = bladerf_set_frequency(dev, BLADERF_MODULE_RX, b->rx_freq);
+ if (status != 0 && retval == 0) {
+ retval = status;
+ }
+
+ status = bladerf_set_rational_sample_rate(dev, BLADERF_MODULE_RX,
+ &b->rx_sample_rate, NULL);
+ if (status != 0 && retval == 0) {
+ retval = status;
+ }
+
+ status = bladerf_set_bandwidth(dev, BLADERF_MODULE_RX,
+ b->rx_bandwidth, NULL);
+ if (status != 0 && retval == 0) {
+ retval = status;
+ }
+
+ status = bladerf_set_lna_gain(dev, b->rx_lna);
+ if (status != 0 && retval == 0) {
+ retval = status;
+ }
+
+ status = bladerf_set_rxvga1(dev, b->rx_vga1);
+ if (status != 0 && retval == 0) {
+ retval = status;
+ }
+
+ status = bladerf_set_rxvga2(dev, b->rx_vga2);
+ if (status != 0 && retval == 0) {
+ retval = status;
+ }
+
+ status = bladerf_set_rational_sample_rate(dev, BLADERF_MODULE_TX,
+ &b->tx_sample_rate, NULL);
+ if (status != 0 && retval == 0) {
+ retval = status;
+ }
+
+ return retval;
+}
+
+static int tx_cal_update_frequency(struct tx_cal *state, uint64_t freq)
+{
+ int status;
+ bladerf_loopback lb;
+ uint64_t rx_freq;
+
+ status = bladerf_set_frequency(state->dev, BLADERF_MODULE_TX, freq);
+ if (status != 0) {
+ return status;
+ }
+
+ rx_freq = freq - 1000000;
+ if (rx_freq < BLADERF_FREQUENCY_MIN) {
+ rx_freq = freq + 1000000;
+ state->rx_low = false;
+ } else {
+ state->rx_low = true;
+ }
+
+ status = bladerf_set_frequency(state->dev, BLADERF_MODULE_RX, rx_freq);
+ if (status != 0) {
+ return status;
+ }
+
+ if (freq < 1500000000) {
+ lb = BLADERF_LB_RF_LNA1;
+ PR_DBG("Switching to RF LNA1 loopback.\n");
+ } else {
+ lb = BLADERF_LB_RF_LNA2;
+ PR_DBG("Switching to RF LNA2 loopback.\n");
+ }
+
+ if (state->loopback != lb) {
+ status = bladerf_set_loopback(state->dev, lb);
+ if (status == 0) {
+ state->loopback = lb;
+ }
+ }
+
+ return status;
+}
+
+static int apply_tx_cal_settings(struct bladerf *dev)
+{
+ int status;
+
+ status = bladerf_set_sample_rate(dev, BLADERF_MODULE_RX, TX_CAL_RATE, NULL);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_set_bandwidth(dev, BLADERF_MODULE_RX, TX_CAL_RX_BW, NULL);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_set_lna_gain(dev, TX_CAL_RX_LNA);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_set_rxvga1(dev, TX_CAL_RX_VGA1);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_set_rxvga2(dev, TX_CAL_RX_VGA2);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_set_sample_rate(dev, BLADERF_MODULE_TX, TX_CAL_RATE, NULL);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_set_loopback(dev, TX_CAL_DEFAULT_LB);
+ if (status != 0) {
+ return status;
+ }
+
+ return status;
+}
+
+/* We just need to flush some zeros through the system to hole the DAC at
+ * 0+0j and remain there while letting it underrun. This alleviates the
+ * need to worry about continuously TX'ing zeros. */
+static int tx_cal_tx_init(struct bladerf *dev)
+{
+ int status;
+ int16_t zero_sample[] = { 0, 0 };
+ struct bladerf_metadata meta;
+
+ memset(&meta, 0, sizeof(meta));
+
+ status = bladerf_sync_config(dev, BLADERF_MODULE_TX,
+ BLADERF_FORMAT_SC16_Q11_META,
+ 4, 16384, 2, 1000);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_enable_module(dev, BLADERF_MODULE_TX, true);
+ if (status != 0) {
+ return status;
+ }
+
+ meta.flags = BLADERF_META_FLAG_TX_BURST_START |
+ BLADERF_META_FLAG_TX_BURST_END |
+ BLADERF_META_FLAG_TX_NOW;
+
+ status = bladerf_sync_tx(dev, &zero_sample, 1, &meta, 2000);
+ return status;
+}
+
+static int tx_cal_rx_init(struct bladerf *dev)
+{
+ int status;
+
+ status = bladerf_sync_config(dev, BLADERF_MODULE_RX,
+ BLADERF_FORMAT_SC16_Q11_META,
+ 64, 16384, 32, 1000);
+ if (status != 0) {
+ return status;
+ }
+
+ status = bladerf_enable_module(dev, BLADERF_MODULE_RX, true);
+ return status;
+}
+
+static void tx_cal_state_deinit(struct tx_cal *cal)
+{
+ free(cal->sweep);
+ free(cal->mag);
+ free(cal->samples);
+ free(cal->filt);
+ free(cal->filt_out);
+ free(cal->post_mix);
+}
+
+/* This should be called immediately preceding the cal routines */
+static int tx_cal_state_init(struct bladerf *dev, struct tx_cal *cal)
+{
+ int status;
+
+ cal->dev = dev;
+ cal->num_samples = TX_CAL_COUNT;
+ cal->loopback = TX_CAL_DEFAULT_LB;
+
+ /* Interleaved SC16 Q11 samples */
+ cal->samples = malloc(2 * sizeof(cal->samples[0]) * cal->num_samples);
+ if (cal->samples == NULL) {
+ return BLADERF_ERR_MEM;
+ }
+
+ /* Filter state */
+ cal->filt = malloc(2 * sizeof(cal->filt[0]) * tx_cal_filt_num_taps);
+ if (cal->filt == NULL) {
+ return BLADERF_ERR_MEM;
+ }
+
+ /* Filter output */
+ cal->filt_out = malloc(sizeof(cal->filt_out[0]) * cal->num_samples);
+ if (cal->filt_out == NULL) {
+ return BLADERF_ERR_MEM;
+ }
+
+ /* Post-mix */
+ cal->post_mix = malloc(sizeof(cal->post_mix[0]) * cal->num_samples);
+ if (cal->post_mix == NULL) {
+ return BLADERF_ERR_MEM;
+ }
+
+ /* Correction sweep and results */
+ cal->sweep = malloc(sizeof(cal->sweep[0]) * TX_CAL_CORR_SWEEP_LEN);
+ if (cal->sweep == NULL) {
+ return BLADERF_ERR_MEM;
+ }
+
+ cal->mag = malloc(sizeof(cal->mag[0]) * TX_CAL_CORR_SWEEP_LEN);
+ if (cal->mag == NULL) {
+ return BLADERF_ERR_MEM;
+ }
+
+ /* Set initial RX in the future */
+ status = bladerf_get_timestamp(cal->dev, BLADERF_MODULE_RX, &cal->ts);
+ if (status == 0) {
+ cal->ts += 20 * TX_CAL_TS_INC;
+ }
+
+ return status;
+}
+
+/* Filter samples
+ * Input: state->post_mix
+ * Output: state->filt_out
+ */
+static void tx_cal_filter(struct tx_cal *state)
+{
+ unsigned int n, m;
+ struct complexf *ins1, *ins2;
+ struct complexf *curr; /* Current filter state */
+ const struct complexf *filt_end = &state->filt[2 * tx_cal_filt_num_taps];
+
+ /* Reset filter state */
+ ins1 = &state->filt[0];
+ ins2 = &state->filt[tx_cal_filt_num_taps];
+ memset(state->filt, 0, 2 * sizeof(state->filt[0]) * tx_cal_filt_num_taps);
+
+ for (n = 0; n < state->num_samples; n++) {
+ /* Insert sample */
+ *ins1 = *ins2 = state->post_mix[n];
+
+ /* Convolve */
+ state->filt_out[n].i = 0;
+ state->filt_out[n].q = 0;
+ curr = ins2;
+
+ for (m = 0; m < tx_cal_filt_num_taps; m++, curr--) {
+ state->filt_out[n].i += tx_cal_filt[m] * curr->i;
+ state->filt_out[n].q += tx_cal_filt[m] * curr->q;
+ }
+
+ /* Update insertion points */
+ ins2++;
+ if (ins2 == filt_end) {
+ ins1 = &state->filt[0];
+ ins2 = &state->filt[tx_cal_filt_num_taps];
+ } else {
+ ins1++;
+ }
+
+ }
+}
+
+/* Deinterleave, scale, and mix with an -Fs/4 tone to shift TX DC offset out at
+ * Fs/4 to baseband.
+ * Input: state->samples
+ * Output: state->post_mix
+ */
+static void tx_cal_mix(struct tx_cal *state)
+{
+ unsigned int n, m;
+ int mix_state;
+ float scaled_i, scaled_q;
+
+ /* Mix with -Fs/4 if RX is tuned "lower" than TX, and Fs/4 otherwise */
+ const int mix_state_inc = state->rx_low ? 1 : -1;
+ mix_state = 0;
+
+ for (n = 0, m = 0; n < (2 * state->num_samples); n += 2, m++) {
+ scaled_i = state->samples[n] / 2048.0f;
+ scaled_q = state->samples[n+1] / 2048.0f;
+
+ switch (mix_state) {
+ case 0:
+ state->post_mix[m].i = scaled_i;
+ state->post_mix[m].q = scaled_q;
+ break;
+
+ case 1:
+ state->post_mix[m].i = scaled_q;
+ state->post_mix[m].q = -scaled_i;
+ break;
+
+ case 2:
+ state->post_mix[m].i = -scaled_i;
+ state->post_mix[m].q = -scaled_q;
+ break;
+
+ case 3:
+ state->post_mix[m].i = -scaled_q;
+ state->post_mix[m].q = scaled_i;
+ break;
+ }
+
+ mix_state = (mix_state + mix_state_inc) & 0x3;
+ }
+}
+
+static int tx_cal_avg_magnitude(struct tx_cal *state, float *avg_mag)
+{
+ int status;
+ const unsigned int start = (tx_cal_filt_num_taps + 1) / 2;
+ unsigned int n;
+ float accum;
+
+ /* Fetch samples at the current settings */
+ status = rx_samples(state->dev, state->samples, state->num_samples,
+ &state->ts, TX_CAL_TS_INC);
+ if (status != 0) {
+ return status;
+ }
+
+ /* Deinterleave & mix TX's DC offset contribution to baseband */
+ tx_cal_mix(state);
+
+ /* Filter out everything other than the TX DC offset's contribution */
+ tx_cal_filter(state);
+
+ /* Compute the power (magnitude^2 to alleviate need for square root).
+ * We skip samples here to account for the group delay of the filter;
+ * the initial samples will be ramping up. */
+ accum = 0;
+ for (n = start; n < state->num_samples; n++) {
+ const struct complexf *s = &state->filt_out[n];
+ const float m = (float) sqrt(s->i * s->i + s->q * s->q);
+ accum += m;
+ }
+
+ *avg_mag = (accum / (state->num_samples - start));
+
+ /* Scale this back up to DAC/ADC counts, just for convenience */
+ *avg_mag *= 2048.0;
+
+ return status;
+}
+
+/* Apply the correction value and read the TX DC offset magnitude */
+static int tx_cal_measure_correction(struct tx_cal *state,
+ bladerf_correction c,
+ int16_t value, float *mag)
+{
+ int status;
+
+ status = bladerf_set_correction(state->dev, BLADERF_MODULE_TX, c, value);
+ if (status != 0) {
+ return status;
+ }
+
+ state->ts += TX_CAL_TS_INC;
+
+ status = tx_cal_avg_magnitude(state, mag);
+ if (status == 0) {
+ PR_VERBOSE(" Corr=%5d, Avg_magnitude=%f\n", value, *mag);
+ }
+
+ return status;
+}
+
+static int tx_cal_get_corr(struct tx_cal *state, bool i_ch,
+ int16_t *corr_value, float *error_value)
+{
+ int status;
+ unsigned int n;
+ int16_t corr;
+ float mag[4];
+ float m1, m2, b1, b2;
+ int16_t range_min, range_max;
+ int16_t min_corr;
+ float min_mag;
+
+ const int16_t x[4] = { -1800, -1000, 1000, 1800 };
+
+ const bladerf_correction corr_module =
+ i_ch ? BLADERF_CORR_LMS_DCOFF_I : BLADERF_CORR_LMS_DCOFF_Q;
+
+ PR_DBG("Getting coarse estimate for %c\n", i_ch ? 'I' : 'Q');
+
+ for (n = 0; n < 4; n++) {
+ status = tx_cal_measure_correction(state, corr_module, x[n], &mag[n]);
+ if (status != 0) {
+ return status;
+ }
+
+ }
+
+ m1 = (mag[1] - mag[0]) / (x[1] - x[0]);
+ b1 = mag[0] - m1 * x[0];
+
+ m2 = (mag[3] - mag[2]) / (x[3] - x[2]);
+ b2 = mag[2] - m2 * x[2];
+
+ PR_VERBOSE(" m1=%3.8f, b1=%3.8f, m2=%3.8f, b=%3.8f\n", m1, b1, m2, b2);
+
+ if (m1 < 0 && m2 > 0) {
+ const int16_t tmp = (int16_t)((b2 - b1) / (m1 - m2) + 0.5);
+ const int16_t corr_est = (tmp / 16) * 16;
+
+ /* Number of points to sweep on either side of our estimate */
+ const unsigned int n_sweep = 10;
+
+ PR_VERBOSE(" corr_est=%d\n", corr_est);
+
+ range_min = corr_est - 16 * n_sweep;
+ if (range_min < -2048) {
+ range_min = -2048;
+ }
+
+ range_max = corr_est + 16 * n_sweep;
+ if (range_max > 2048) {
+ range_max = 2048;
+ }
+
+ } else {
+ /* The frequency and gain combination have yielded a set of
+ * points that do not form intersecting lines. This may be indicative
+ * of a case where the LMS6 DC bias settings can't pull the DC offset
+ * to a zero-crossing. We'll just do a slow, full scan to find
+ * a minimum */
+ PR_VERBOSE(" Could not compute estimate. Performing full sweep.\n");
+ range_min = -2048;
+ range_max = 2048;
+ }
+
+
+ PR_DBG("Performing correction value sweep: [%-5d : 16 :%5d]\n",
+ range_min, range_max);
+
+ min_corr = 0;
+ min_mag = 2048;
+
+ for (n = 0, corr = range_min;
+ corr <= range_max && n < TX_CAL_CORR_SWEEP_LEN;
+ n++, corr += 16) {
+
+ float tmp;
+
+ status = tx_cal_measure_correction(state, corr_module, corr, &tmp);
+ if (status != 0) {
+ return status;
+ }
+
+ if (tmp < 0) {
+ tmp = -tmp;
+ }
+
+ if (tmp < min_mag) {
+ min_corr = corr;
+ min_mag = tmp;
+ }
+ }
+
+ /* Leave the device set to the minimum */
+ status = bladerf_set_correction(state->dev, BLADERF_MODULE_TX,
+ corr_module, min_corr);
+ if (status == 0) {
+ *corr_value = min_corr;
+ *error_value = min_mag;
+ }
+
+ return status;
+}
+
+static int perform_tx_cal(struct tx_cal *state, struct dc_calibration_params *p)
+{
+ int status = 0;
+
+ status = tx_cal_update_frequency(state, p->frequency);
+ if (status != 0) {
+ return status;
+ }
+
+ state->ts += TX_CAL_TS_INC;
+
+ /* Perform I calibration */
+ status = tx_cal_get_corr(state, true, &p->corr_i, &p->error_i);
+ if (status != 0) {
+ return status;
+ }
+
+ /* Perform Q calibration */
+ status = tx_cal_get_corr(state, false, &p->corr_q, &p->error_q);
+ if (status != 0) {
+ return status;
+ }
+
+ /* Re-do I calibration to try to further fine-tune result */
+ status = tx_cal_get_corr(state, true, &p->corr_i, &p->error_i);
+ if (status != 0) {
+ return status;
+ }
+
+ /* Apply the resulting nominal values */
+ status = set_tx_dc_corr(state->dev, p->corr_i, p->corr_q);
+
+ return status;
+}
+
+int dc_calibration_tx(struct bladerf *dev,
+ struct dc_calibration_params *params,
+ size_t num_params, bool print_status)
+{
+ int status = 0;
+ int retval = 0;
+ struct tx_cal_backup backup;
+ struct tx_cal state;
+ size_t i;
+
+ memset(&state, 0, sizeof(state));
+
+ /* Backup the device state prior to making changes */
+ status = get_tx_cal_backup(dev, &backup);
+ if (status != 0) {
+ return status;
+ }
+
+ /* Configure the device for our TX cal operation */
+ status = apply_tx_cal_settings(dev);
+ if (status != 0) {
+ goto out;
+ }
+
+ /* Enable TX and run zero samples through the device */
+ status = tx_cal_tx_init(dev);
+ if (status != 0) {
+ goto out;
+ }
+
+ /* Enable RX */
+ status = tx_cal_rx_init(dev);
+ if (status != 0) {
+ goto out;
+ }
+
+ /* Initialize calibration state information and resources */
+ status = tx_cal_state_init(dev, &state);
+ if (status != 0) {
+ goto out;
+ }
+
+ for (i = 0; i < num_params && status == 0; i++) {
+ status = perform_tx_cal(&state, &params[i]);
+
+ if (status == 0 && print_status) {
+# ifdef DEBUG_DC_CALIBRATION
+ const char sol = '\n';
+ const char eol = '\n';
+# else
+ const char sol = '\r';
+ const char eol = '\0';
+# endif
+ printf("%cCalibrated @ %10" PRIu64 " Hz: "
+ "I=%4d (Error: %4.2f), "
+ "Q=%4d (Error: %4.2f) %c",
+ sol,
+ params[i].frequency,
+ params[i].corr_i, params[i].error_i,
+ params[i].corr_q, params[i].error_q,
+ eol);
+ fflush(stdout);
+ }
+ }
+
+ if (print_status) {
+ putchar('\n');
+ }
+
+out:
+ retval = status;
+
+ status = bladerf_enable_module(dev, BLADERF_MODULE_RX, false);
+ if (status != 0 && retval == 0) {
+ retval = status;
+ }
+
+ status = bladerf_enable_module(dev, BLADERF_MODULE_TX, false);
+ if (status != 0 && retval == 0) {
+ retval = status;
+ }
+
+ tx_cal_state_deinit(&state);
+
+ status = set_tx_cal_backup(dev, &backup);
+ if (status != 0 && retval == 0) {
+ retval = status;
+ }
+
+ return retval;
+}
+
+int dc_calibration(struct bladerf *dev, bladerf_module module,
+ struct dc_calibration_params *params,
+ size_t num_params, bool show_status)
+{
+ int status;
+
+ switch (module) {
+ case BLADERF_MODULE_RX:
+ status = dc_calibration_rx(dev, params, num_params, show_status);
+ break;
+
+ case BLADERF_MODULE_TX:
+ status = dc_calibration_tx(dev, params, num_params, show_status);
+ break;
+
+ default:
+ status = BLADERF_ERR_INVAL;
+ }
+
+ return status;
+}
diff --git a/Radio/HW/BladeRF/common/src/devcfg.c b/Radio/HW/BladeRF/common/src/devcfg.c
new file mode 100644
index 0000000..497c54b
--- /dev/null
+++ b/Radio/HW/BladeRF/common/src/devcfg.c
@@ -0,0 +1,638 @@
+/*
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (C) 2014-2015 Nuand LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <limits.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+
+#include "devcfg.h"
+#include "conversions.h"
+
+#define DEVCFG_DFLT_TX_FREQ 1000000000
+#define DEVCFG_DFLT_TXVGA1 (-14)
+#define DEVCFG_DFLT_TXVGA2 0
+
+#define DEVCFG_DFLT_RX_FREQ 1000000000
+#define DEVCFG_DFLT_LNAGAIN BLADERF_LNA_GAIN_MAX
+#define DEVCFG_DFLT_RXVGA1 30
+#define DEVCFG_DFLT_RXVGA2 0
+
+#define DEVCFG_DFLT_SAMPLERATE 2000000
+#define DEVCFG_DFLT_BANDWIDTH 1500000
+
+#define DEVCFG_DFLT_SAMPLES_PER_BUF 8192
+#define DEVCFG_DFLT_NUM_BUFFERS 64
+#define DEVCFG_DFLT_NUM_TRANSFERS 16
+#define DEVCFG_DFLT_STREAM_TIMEMOUT_MS 5000
+#define DEVCFG_DFLT_SYNC_TIMEOUT_MS (2 * DEVCFG_DFLT_STREAM_TIMEMOUT_MS)
+
+#define OPTION_HELP 'h'
+#define OPTION_DEVICE 'd'
+#define OPTION_LOOPBACK 'l'
+#define OPTION_VERBOSITY 'v'
+#define OPTION_SAMPLERATE 's'
+#define OPTION_RX_SAMPLERATE 0x80
+#define OPTION_TX_SAMPLERATE 0x81
+#define OPTION_BANDWIDTH 'b'
+#define OPTION_RX_BANDWIDTH 0x82
+#define OPTION_TX_BANDWIDTH 0x83
+#define OPTION_FREQUENCY 'f'
+#define OPTION_RX_FREQUENCY 0x84
+#define OPTION_TX_FREQUENCY 0x85
+#define OPTION_LNAGAIN 0x86
+#define OPTION_RXVGA1 0x87
+#define OPTION_RXVGA2 0x88
+#define OPTION_TXVGA1 0x89
+#define OPTION_TXVGA2 0x8a
+#define OPTION_SAMPLES_PER_BUF 0x91
+#define OPTION_NUM_BUFFERS 0x92
+#define OPTION_NUM_TRANSFERS 0x93
+#define OPTION_STREAM_TIMEOUT 0x94
+#define OPTION_SYNC_TIMEOUT 0x95
+#define OPTION_ENABLE_XB200 0x96
+
+static const numeric_suffix hz_suffixes[] = {
+ { "K", 1000 },
+ { "KHz", 1000 },
+ { "M", 1000000 },
+ { "MHz", 1000000 },
+ { "G", 1000000000 },
+ { "GHz", 1000000000 },
+};
+
+static const struct option devcfg_long_options[] =
+{
+ { "help", no_argument, 0, OPTION_HELP },
+ { "device", required_argument, 0, OPTION_DEVICE },
+ { "verbosity", required_argument, 0, OPTION_VERBOSITY },
+
+ { "samplerate", required_argument, 0, OPTION_SAMPLERATE },
+ { "rx-samplerate", required_argument, 0, OPTION_RX_SAMPLERATE },
+ { "tx-samplerate", required_argument, 0, OPTION_TX_SAMPLERATE },
+
+ { "bandwidth", required_argument, 0, OPTION_BANDWIDTH },
+ { "rx-bandwidth", required_argument, 0, OPTION_RX_BANDWIDTH },
+ { "tx-bandwidth", required_argument, 0, OPTION_TX_BANDWIDTH },
+
+ { "frequency", required_argument, 0, OPTION_FREQUENCY },
+ { "rx-frequency", required_argument, 0, OPTION_RX_FREQUENCY },
+ { "tx-frequency", required_argument, 0, OPTION_TX_FREQUENCY },
+
+ { "lna-gain", required_argument, 0, OPTION_LNAGAIN },
+ { "rxvga1-gain", required_argument, 0, OPTION_RXVGA1 },
+ { "rxvga2-gain", required_argument, 0, OPTION_RXVGA2 },
+
+ { "txvga1-gain", required_argument, 0, OPTION_TXVGA1 },
+ { "txvga2-gain", required_argument, 0, OPTION_TXVGA2 },
+
+ { "loopback", required_argument, 0, OPTION_LOOPBACK },
+
+ { "xb200", no_argument, 0, OPTION_ENABLE_XB200 },
+
+ { "samples-per-buffer", required_argument, 0, OPTION_SAMPLES_PER_BUF },
+ { "num-buffers", required_argument, 0, OPTION_NUM_BUFFERS },
+ { "num-transfers", required_argument, 0, OPTION_NUM_TRANSFERS },
+ { "stream-timeout", required_argument, 0, OPTION_STREAM_TIMEOUT },
+ { "sync-timeout", required_argument, 0, OPTION_SYNC_TIMEOUT },
+};
+
+void devcfg_init(struct devcfg *c)
+{
+ c->device_specifier = NULL;
+
+ c->tx_frequency = DEVCFG_DFLT_TX_FREQ;
+ c->tx_bandwidth = DEVCFG_DFLT_BANDWIDTH;
+ c->tx_samplerate = DEVCFG_DFLT_SAMPLERATE;
+ c->txvga1 = DEVCFG_DFLT_TXVGA1;
+ c->txvga2 = DEVCFG_DFLT_TXVGA2;
+
+ c->rx_frequency = DEVCFG_DFLT_TX_FREQ;
+ c->rx_bandwidth = DEVCFG_DFLT_BANDWIDTH;
+ c->rx_samplerate = DEVCFG_DFLT_SAMPLERATE;
+ c->lnagain = DEVCFG_DFLT_LNAGAIN;
+ c->rxvga1 = DEVCFG_DFLT_RXVGA1;
+ c->rxvga2 = DEVCFG_DFLT_RXVGA2;
+
+ c->loopback = BLADERF_LB_NONE;
+
+ c->verbosity = BLADERF_LOG_LEVEL_INFO;
+
+ c->enable_xb200 = false;
+
+ c->samples_per_buffer = DEVCFG_DFLT_SAMPLES_PER_BUF;
+ c->num_buffers = DEVCFG_DFLT_NUM_BUFFERS;
+ c->num_transfers = DEVCFG_DFLT_NUM_TRANSFERS;
+ c->stream_timeout_ms = DEVCFG_DFLT_STREAM_TIMEMOUT_MS;
+ c->sync_timeout_ms = DEVCFG_DFLT_SYNC_TIMEOUT_MS;
+}
+
+void devcfg_deinit(struct devcfg *c)
+{
+ free(c->device_specifier);
+}
+
+void devcfg_print_common_help(const char *title)
+{
+ if (title != NULL) {
+ printf("%s", title);
+ }
+
+ printf(" -h, --help Show this help text.\n");
+ printf(" -d, --device <str> Open the specified device.\n");
+ printf(" -v, --verbosity <level> Set the libbladeRF verbosity level.\n");
+ printf(" --xb200 Enable the XB-200. This will remain enabled\n");
+ printf(" until the device is power-cycled.\n");
+ printf("\n");
+ printf(" -f, --frequency <freq> Set RX and TX to the specified frequency.\n");
+ printf(" --rx-frequency <freq> Set RX to the specified frequency.\n");
+ printf(" --tx-frequency <freq> Set TX to the specified frequency.\n");
+ printf("\n");
+ printf(" -s, --samplerate <rate> Set RX and TX to the specified sample rate.\n");
+ printf(" --rx-samplerate <rate> Set RX to the specified sample rate.\n");
+ printf(" --tx-samplerate <rate> Set RX to the specified sample rate.\n");
+ printf("\n");
+ printf(" -b, --bandwidth <bw> Set RX and TX to the specified bandwidth.\n");
+ printf(" --rx-bandwidth <bw> Set RX to the specified bandwidth.\n");
+ printf(" --tx-bandwidth <bw> Set TX to the specified bandwidth.\n");
+ printf("\n");
+ printf(" --lna-gain <gain> Set the RX LNA to the specified gain.\n");
+ printf(" Options are: bypass, mid, max\n");
+ printf(" --rxvga1-gain <gain> Set RX VGA1 to the specified gain.\n");
+ printf(" --rxvga2-gain <gain> Set RX VGA2 to the specified gain.\n");
+ printf(" --txvga1-gain <gain> Set TX VGA1 to the specified gain.\n");
+ printf(" --txvga2-gain <gain> Set TX VGA2 to the specified gain.\n");
+ printf("\n");
+ printf(" --num-buffers <n> Allocate <n> sample buffers.\n");
+ printf(" --samples-per-buffer <n> Allocate <n> samples in each sample buffer.\n");
+ printf(" --num-transfers <n> Utilize up to <n> simultaneous USB transfers.\n");
+ printf(" --stream-timeout <n> Set stream timeout to <n> milliseconds.\n");
+ printf(" --sync-timeout <n> Set sync function timeout to <n> milliseconds.\n");
+
+}
+
+struct option * devcfg_get_long_options(const struct option *app_options)
+{
+ struct option *ret;
+ size_t app_size = 0;
+ const size_t devcfg_size = sizeof(devcfg_long_options);
+
+ while (app_options[app_size].name != NULL) {
+ app_size++;
+ }
+
+ /* Account for 0-entry */
+ app_size = (app_size + 1) * sizeof(app_options[0]);
+
+ ret = malloc(devcfg_size + app_size);
+
+ if (ret != NULL) {
+ memcpy(ret, &devcfg_long_options, devcfg_size);
+ memcpy(ret + ARRAY_SIZE(devcfg_long_options) , app_options, app_size);
+ }
+
+ return ret;
+}
+
+int devcfg_handle_args(int argc, char **argv, const char *option_str,
+ const struct option *long_options, struct devcfg *config)
+{
+ int c;
+ bool ok;
+ int status;
+ unsigned int freq_min;
+
+ while ((c = getopt_long(argc, argv, option_str, long_options, NULL)) >= 0) {
+
+ if (config->enable_xb200) {
+ freq_min = BLADERF_FREQUENCY_MIN_XB200;
+ } else {
+ freq_min = BLADERF_FREQUENCY_MIN;
+ }
+
+ switch (c) {
+
+ case OPTION_HELP:
+ return 1;
+ break;
+
+ case OPTION_DEVICE:
+ if (config->device_specifier == NULL) {
+ config->device_specifier = strdup(optarg);
+ if (config->device_specifier == NULL) {
+ perror("strdup");
+ return -1;
+ }
+ }
+ break;
+
+ case OPTION_LOOPBACK:
+ status = str2loopback(optarg, &config->loopback);
+ if (status != 0) {
+ fprintf(stderr, "Invalid loopback mode: %s\n", optarg);
+ return -1;
+ }
+ break;
+
+ case OPTION_VERBOSITY:
+ config->verbosity = str2loglevel(optarg, &ok);
+ if (!ok) {
+ fprintf(stderr, "Invalid verbosity level: %s\n", optarg);
+ return -1;
+ }
+ break;
+
+ case OPTION_ENABLE_XB200:
+ config->enable_xb200 = true;
+ break;
+
+ case OPTION_FREQUENCY:
+ config->rx_frequency =
+ str2uint_suffix(optarg,
+ freq_min,
+ BLADERF_FREQUENCY_MAX,
+ hz_suffixes, ARRAY_SIZE(hz_suffixes),
+ &ok);
+
+ if (!ok) {
+ fprintf(stderr, "Invalid frequency: %s\n", optarg);
+ return -1;
+ } else {
+ config->tx_frequency = config->rx_frequency;
+ }
+ break;
+
+ case OPTION_RX_FREQUENCY:
+ config->rx_frequency =
+ str2uint_suffix(optarg,
+ freq_min,
+ BLADERF_FREQUENCY_MAX,
+ hz_suffixes, ARRAY_SIZE(hz_suffixes),
+ &ok);
+
+ if (!ok) {
+ fprintf(stderr, "Invalid RX frequency: %s\n", optarg);
+ return -1;
+ }
+ break;
+
+ case OPTION_TX_FREQUENCY:
+ config->tx_frequency =
+ str2uint_suffix(optarg,
+ freq_min,
+ BLADERF_FREQUENCY_MAX,
+ hz_suffixes, ARRAY_SIZE(hz_suffixes),
+ &ok);
+
+ if (!ok) {
+ fprintf(stderr, "Invalid TX frequency: %s\n", optarg);
+ return -1;
+ }
+ break;
+
+ case OPTION_SAMPLERATE:
+ config->rx_samplerate =
+ str2uint_suffix(optarg,
+ BLADERF_SAMPLERATE_MIN,
+ BLADERF_SAMPLERATE_REC_MAX,
+ hz_suffixes, ARRAY_SIZE(hz_suffixes),
+ &ok);
+ if (!ok) {
+ fprintf(stderr, "Invalid sample rate: %s\n", optarg);
+ return -1;
+ } else {
+ config->tx_samplerate = config->rx_samplerate;
+ }
+ break;
+
+ case OPTION_RX_SAMPLERATE:
+ config->rx_samplerate =
+ str2uint_suffix(optarg,
+ BLADERF_SAMPLERATE_MIN,
+ BLADERF_SAMPLERATE_REC_MAX,
+ hz_suffixes, ARRAY_SIZE(hz_suffixes),
+ &ok);
+ if (!ok) {
+ fprintf(stderr, "Invalid RX sample rate: %s\n", optarg);
+ return -1;
+ }
+ break;
+
+ case OPTION_TX_SAMPLERATE:
+ config->tx_samplerate =
+ str2uint_suffix(optarg,
+ BLADERF_SAMPLERATE_MIN,
+ BLADERF_SAMPLERATE_REC_MAX,
+ hz_suffixes, ARRAY_SIZE(hz_suffixes),
+ &ok);
+ if (!ok) {
+ fprintf(stderr, "Invalid TX sample rate: %s\n", optarg);
+ return -1;
+ }
+ break;
+
+ case OPTION_BANDWIDTH:
+ config->rx_bandwidth =
+ str2uint_suffix(optarg,
+ BLADERF_BANDWIDTH_MIN,
+ BLADERF_BANDWIDTH_MAX,
+ hz_suffixes, ARRAY_SIZE(hz_suffixes),
+ &ok);
+ if (!ok) {
+ fprintf(stderr, "Invalid bandwidth: %s\n", optarg);
+ return -1;
+ } else {
+ config->tx_bandwidth = config->rx_bandwidth;
+ }
+ break;
+
+ case OPTION_RX_BANDWIDTH:
+ config->rx_bandwidth =
+ str2uint_suffix(optarg,
+ BLADERF_BANDWIDTH_MIN,
+ BLADERF_BANDWIDTH_MAX,
+ hz_suffixes, ARRAY_SIZE(hz_suffixes),
+ &ok);
+ if (!ok) {
+ fprintf(stderr, "Invalid RX bandwidth: %s\n", optarg);
+ return -1;
+ }
+ break;
+
+ case OPTION_TX_BANDWIDTH:
+ config->tx_bandwidth =
+ str2uint_suffix(optarg,
+ BLADERF_BANDWIDTH_MIN,
+ BLADERF_BANDWIDTH_MAX,
+ hz_suffixes, ARRAY_SIZE(hz_suffixes),
+ &ok);
+ if (!ok) {
+ fprintf(stderr, "Invalid TX bandwidth: %s\n", optarg);
+ return -1;
+ }
+ break;
+
+ case OPTION_LNAGAIN:
+ status = str2lnagain(optarg, &config->lnagain);
+ if (status != 0) {
+ fprintf(stderr, "Invalid RX LNA gain: %s\n", optarg);
+ return -1;
+ }
+ break;
+
+ case OPTION_RXVGA1:
+ config->rxvga1 = str2int(optarg,
+ BLADERF_RXVGA1_GAIN_MIN,
+ BLADERF_RXVGA1_GAIN_MAX,
+ &ok);
+
+ if (!ok) {
+ fprintf(stderr, "Invalid RXVGA1 gain: %s\n", optarg);
+ return -1;
+ }
+ break;
+
+ case OPTION_RXVGA2:
+ config->rxvga2 = str2int(optarg,
+ BLADERF_RXVGA2_GAIN_MIN,
+ BLADERF_RXVGA2_GAIN_MAX,
+ &ok);
+
+ if (!ok) {
+ fprintf(stderr, "Invalid RXVGA1 gain: %s\n", optarg);
+ return -1;
+ }
+ break;
+
+ case OPTION_TXVGA1:
+ config->txvga1 = str2int(optarg,
+ BLADERF_TXVGA1_GAIN_MIN,
+ BLADERF_TXVGA1_GAIN_MAX,
+ &ok);
+
+ if (!ok) {
+ fprintf(stderr, "Invalid TXVGA1 gain: %s\n", optarg);
+ return -1;
+ }
+ break;
+
+ case OPTION_TXVGA2:
+ config->txvga2 = str2int(optarg,
+ BLADERF_TXVGA2_GAIN_MIN,
+ BLADERF_TXVGA2_GAIN_MAX,
+ &ok);
+
+ if (!ok) {
+ fprintf(stderr, "Invalid TXVGA2 gain: %s\n", optarg);
+ return -1;
+ }
+ break;
+
+ case OPTION_NUM_BUFFERS:
+ config->num_buffers = str2uint(optarg, 1, UINT_MAX, &ok);
+ if (!ok) {
+ fprintf(stderr, "Invalid buffer count: %s\n", optarg);
+ return -1;
+ }
+ break;
+
+ case OPTION_SAMPLES_PER_BUF:
+ config->samples_per_buffer = str2uint(optarg,
+ 1024, UINT_MAX, &ok);
+ if (!ok) {
+ fprintf(stderr, "Invalid buffer size (in samples): %s\n",
+ optarg);
+ return -1;
+ }
+ break;
+
+ case OPTION_NUM_TRANSFERS:
+ config->num_transfers = str2uint(optarg, 1, UINT_MAX, &ok);
+
+ if (!ok) {
+ fprintf(stderr, "Invalid transfer count: %s\n", optarg);
+ return -1;
+ }
+ break;
+
+ case OPTION_STREAM_TIMEOUT:
+ config->stream_timeout_ms = str2uint(optarg, 0, UINT_MAX, &ok);
+ if (!ok) {
+ fprintf(stderr, "Invalid stream timeout: %s\n", optarg);
+ return -1;
+ }
+ break;
+
+ case OPTION_SYNC_TIMEOUT:
+ config->sync_timeout_ms = str2uint(optarg, 0, UINT_MAX, &ok);
+ if (!ok) {
+ fprintf(stderr, "Invalid sync function timeout: %s\n", optarg);
+ return -1;
+ }
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int devcfg_apply(struct bladerf *dev, const struct devcfg *c)
+{
+ int status;
+ const char *board_name;
+
+ board_name = bladerf_get_board_name(dev);
+
+ bladerf_log_set_verbosity(c->verbosity);
+
+ status = bladerf_set_loopback(dev, c->loopback);
+ if (status != 0) {
+ fprintf(stderr, "Failed to set loopback: %s\n",
+ bladerf_strerror(status));
+ return -1;
+ }
+
+ if (c->enable_xb200) {
+ status = bladerf_expansion_attach(dev, BLADERF_XB_200);
+ if (status != 0) {
+ fprintf(stderr, "Failed to attach XB-200.\n");
+ return -1;
+ }
+ }
+
+ status = bladerf_set_frequency(dev, BLADERF_MODULE_RX, c->rx_frequency);
+ if (status != 0) {
+ fprintf(stderr, "Failed to set RX frequency: %s\n",
+ bladerf_strerror(status));
+ return -1;
+ }
+
+ status = bladerf_set_frequency(dev, BLADERF_MODULE_TX, c->tx_frequency);
+ if (status != 0) {
+ fprintf(stderr, "Failed to set TX frequency: %s\n",
+ bladerf_strerror(status));
+ return -1;
+ }
+
+ status = bladerf_set_sample_rate(dev, BLADERF_MODULE_RX, c->rx_samplerate, NULL);
+ if (status != 0) {
+ fprintf(stderr, "Failed to set RX sample rate:%s\n",
+ bladerf_strerror(status));
+ return -1;
+ }
+
+ status = bladerf_set_sample_rate(dev, BLADERF_MODULE_TX, c->tx_samplerate, NULL);
+ if (status != 0) {
+ fprintf(stderr, "Failed to set TX sample rate: %s\n",
+ bladerf_strerror(status));
+ return -1;
+ }
+
+ status = bladerf_set_bandwidth(dev, BLADERF_MODULE_RX, c->rx_bandwidth, NULL);
+ if (status != 0) {
+ fprintf(stderr, "Failed to set RX bandwidth: %s\n",
+ bladerf_strerror(status));
+ return -1;
+ }
+
+ status = bladerf_set_bandwidth(dev, BLADERF_MODULE_TX, c->tx_bandwidth, NULL);
+ if (status != 0) {
+ fprintf(stderr, "Failed to set RX bandwidth: %s\n",
+ bladerf_strerror(status));
+ return -1;
+ }
+
+ if (strcasecmp(board_name, "bladerf1") == 0) {
+ status = bladerf_set_lna_gain(dev, c->lnagain);
+ if (status != 0) {
+ fprintf(stderr, "Failed to set RX LNA gain: %s\n",
+ bladerf_strerror(status));
+ return -1;
+ }
+
+ status = bladerf_set_rxvga1(dev, c->rxvga1);
+ if (status != 0) {
+ fprintf(stderr, "Failed to set RX VGA1 gain: %s\n",
+ bladerf_strerror(status));
+ return -1;
+ }
+
+ status = bladerf_set_rxvga2(dev, c->rxvga2);
+ if (status != 0) {
+ fprintf(stderr, "Failed to set RX VGA2 gain: %s\n",
+ bladerf_strerror(status));
+ return -1;
+ }
+
+ status = bladerf_set_txvga1(dev, c->txvga1);
+ if (status != 0) {
+ fprintf(stderr, "Failed to set TX VGA1 gain: %s\n",
+ bladerf_strerror(status));
+ return -1;
+ }
+
+ status = bladerf_set_txvga2(dev, c->txvga2);
+ if (status != 0) {
+ fprintf(stderr, "Failed to set TX VGA2 gain: %s\n",
+ bladerf_strerror(status));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int devcfg_perform_sync_config(struct bladerf *dev,
+ bladerf_module module,
+ bladerf_format format,
+ const struct devcfg *config,
+ bool enable_module)
+{
+ int status = bladerf_sync_config(dev, module, format,
+ config->num_buffers,
+ config->samples_per_buffer,
+ config->num_transfers,
+ config->stream_timeout_ms);
+
+ if (status != 0) {
+ fprintf(stderr, "Failed to configure %s: %s\n",
+ module == BLADERF_MODULE_RX ? "RX" : "TX",
+ bladerf_strerror(status));
+ return -1;
+ }
+
+ if (enable_module) {
+ status = bladerf_enable_module(dev, module, true);
+ if (status != 0) {
+ fprintf(stderr, "Failed to enable %s module: %s\n",
+ module == BLADERF_MODULE_RX ? "RX" : "TX",
+ bladerf_strerror(status));
+ }
+ }
+
+ return 0;
+}
diff --git a/Radio/HW/BladeRF/common/src/log.c b/Radio/HW/BladeRF/common/src/log.c
new file mode 100644
index 0000000..2872620
--- /dev/null
+++ b/Radio/HW/BladeRF/common/src/log.c
@@ -0,0 +1,98 @@
+/*
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (c) 2013 Nuand LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifdef LOGGING_ENABLED
+#include <log.h>
+#if !defined(WIN32) && !defined(__CYGWIN__) && defined(LOG_SYSLOG_ENABLED)
+#include <syslog.h>
+#endif
+#include <stdio.h>
+#include <stdarg.h>
+
+static bladerf_log_level filter_level = BLADERF_LOG_LEVEL_INFO;
+
+void log_write(bladerf_log_level level, const char *format, ...)
+{
+ /* Only process this message if its level exceeds the current threshold */
+ if (level >= filter_level)
+ {
+ va_list args;
+
+ /* Write the log message */
+ va_start(args, format);
+#if defined(WIN32) || defined(__CYGWIN__)
+ vfprintf(stderr, format, args);
+#else
+# if defined (LOG_SYSLOG_ENABLED)
+ {
+ int syslog_level;
+
+ switch (level) {
+ case BLADERF_LOG_LEVEL_VERBOSE:
+ case BLADERF_LOG_LEVEL_DEBUG:
+ syslog_level = LOG_DEBUG;
+ break;
+
+ case BLADERF_LOG_LEVEL_INFO:
+ syslog_level = LOG_INFO;
+ break;
+
+ case BLADERF_LOG_LEVEL_WARNING:
+ syslog_level = LOG_WARNING;
+ break;
+
+ case BLADERF_LOG_LEVEL_ERROR:
+ syslog_level = LOG_ERR;
+ break;
+
+ case BLADERF_LOG_LEVEL_CRITICAL:
+ syslog_level = LOG_CRIT;
+ break;
+
+ default:
+ /* Shouldn't be used, so just route it to a low level */
+ syslog_level = LOG_DEBUG;
+ break;
+ }
+
+ vsyslog(syslog_level | LOG_USER, format, args);
+ }
+# else
+ vfprintf(stderr, format, args);
+# endif
+#endif
+ va_end(args);
+ }
+}
+
+void log_set_verbosity(bladerf_log_level level)
+{
+ filter_level = level;
+}
+
+bladerf_log_level log_get_verbosity()
+{
+ return filter_level;
+}
+#endif
diff --git a/Radio/HW/BladeRF/common/src/osx/clock_gettime.c b/Radio/HW/BladeRF/common/src/osx/clock_gettime.c
new file mode 100644
index 0000000..5e7200e
--- /dev/null
+++ b/Radio/HW/BladeRF/common/src/osx/clock_gettime.c
@@ -0,0 +1,59 @@
+/*
+ * clock_gettime() wrapper for OSX based upon jbenet's github "gist":
+ * https://gist.github.com/jbenet/1087739
+ *
+ * Copyright (c) 2011 Juan Batiz-Benet (https://github.com/jbenet)
+ * Copyright (c) 2013-2017 Nuand LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "clock_gettime.h"
+#include <errno.h>
+#include <mach/clock.h>
+#include <mach/mach.h>
+
+int clock_gettime(clockid_t clk_id, struct timespec *tp)
+{
+ kern_return_t ret;
+ clock_serv_t cclock;
+ mach_timespec_t mts;
+
+ ret = host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
+ if (ret != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = clock_get_time(cclock, &mts);
+ if (ret != 0) {
+ goto clock_gettime_out;
+ }
+
+ tp->tv_sec = mts.tv_sec;
+ tp->tv_nsec = mts.tv_nsec;
+
+clock_gettime_out:
+ if (mach_port_deallocate(mach_task_self(), cclock) != 0 || ret != 0) {
+ errno = EINVAL;
+ return -1;
+ } else {
+ return 0;
+ }
+}
diff --git a/Radio/HW/BladeRF/common/src/parse.c b/Radio/HW/BladeRF/common/src/parse.c
new file mode 100644
index 0000000..dd6abe1
--- /dev/null
+++ b/Radio/HW/BladeRF/common/src/parse.c
@@ -0,0 +1,455 @@
+/*
+ * Copyright (c) 2017 Nuand LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "parse.h"
+#include "conversions.h"
+#include "log.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static char **add_arg(
+ char **argv, int argc, const char *buf, int start, int end, int quote_count)
+{
+ char **rv;
+ char *d_ptr;
+ int i;
+ int len;
+
+ char c;
+ char quote_char;
+
+ quote_char = 0;
+
+ rv = (char **)realloc(argv, sizeof(char *) * (argc + 1));
+ if (rv == NULL) {
+ return NULL;
+ }
+
+ rv[argc] = NULL;
+
+ len = end - start + 1;
+
+ d_ptr = (char *)malloc(len + 1 - quote_count * 2);
+ if (d_ptr == NULL) {
+ free(rv);
+ return NULL;
+ }
+
+ rv[argc - 1] = d_ptr;
+
+ for (i = 0; i < len; i++) {
+ c = buf[start + i];
+
+ if (!quote_char) {
+ /* We are not in a quote, copy everything but quote chars */
+ if (c == '"' || c == '\'') {
+ quote_char = c;
+ } else {
+ *d_ptr++ = c;
+ }
+ } else {
+ /* We are in a quote, copy everything but the current quote char */
+ if (c == quote_char) {
+ quote_char = 0;
+ } else {
+ *d_ptr++ = c;
+ }
+ }
+ }
+ *d_ptr = '\0';
+
+ return rv;
+}
+
+int str2args(const char *line, char comment_char, char ***argv)
+{
+ char **rv;
+ int argc;
+
+ unsigned i;
+ size_t len;
+
+ bool in_arg;
+ char c;
+ char quote_char;
+
+ int arg_start;
+ int quote_count;
+
+ rv = NULL;
+ argc = 0;
+
+ quote_char = 0;
+
+ arg_start = 0;
+ quote_count = 0;
+
+ len = strlen(line);
+
+ in_arg = false;
+
+ for (i = 0; i < len; i++) {
+ c = line[i];
+
+ if (in_arg) {
+ /* Found the end of a quote! */
+ if (quote_char) {
+ if (quote_char == c) {
+ quote_char = 0;
+ }
+ continue;
+ }
+
+ /* Found the beginning of a quote! */
+ if (c == '\'' || c == '"') {
+ quote_count++;
+ quote_char = c;
+ continue;
+ }
+
+ /* Found whitespace outside of quote */
+ if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+ in_arg = false;
+ argc++;
+ rv = add_arg(rv, argc, line, arg_start, i - 1, quote_count);
+ if (rv == NULL)
+ return -1;
+ }
+ } else {
+ if (c == comment_char) {
+ break;
+ }
+ /* Enter a new argument */
+ if (c != ' ' && c != '\t' && c != '\r' && c != '\n') {
+ /* If first argument is a tick it means we're in a quote */
+ if (c == '\'' || c == '"') {
+ quote_char = c;
+ } else {
+ quote_char = 0;
+ }
+ quote_count = 0;
+ arg_start = i;
+ in_arg = true;
+ }
+ /* else this is still whitespace */
+ }
+ }
+
+ /* reached the end of the line, check to see if current arg needs to
+ * be closed */
+ if (in_arg) {
+ if (quote_char) {
+ free_args(argc, rv);
+ return -2;
+ } else {
+ argc++;
+ rv = add_arg(rv, argc, line, arg_start, i - 1, quote_count);
+ if (rv == NULL) {
+ return -1;
+ }
+ }
+ }
+
+ *argv = rv;
+
+ return argc;
+}
+
+void free_args(int argc, char **argv)
+{
+ int i;
+ for (i = 0; i < argc; i++) {
+ free(argv[i]);
+ }
+ free(argv);
+}
+
+static struct config_options *add_opt(
+ struct config_options *optv, int optc, char *key, char *val, int lineno)
+{
+ struct config_options *rv;
+ char *ptr1, *ptr2;
+ rv = (struct config_options *)realloc(optv,
+ sizeof(struct config_options) * optc);
+ if (rv == NULL) {
+ return NULL;
+ }
+
+ ptr1 = (char *)malloc(strlen(key) + 1);
+ if (ptr1 == NULL) {
+ free(rv);
+ return NULL;
+ }
+ strcpy(ptr1, key);
+ rv[optc - 1].key = ptr1;
+
+ ptr2 = (char *)malloc(strlen(val) + 1);
+ if (ptr2 == NULL) {
+ free(ptr1);
+ free(rv);
+ return NULL;
+ }
+ strcpy(ptr2, val);
+ rv[optc - 1].value = ptr2;
+
+ rv[optc - 1].lineno = lineno;
+
+ return rv;
+}
+
+bool update_match(struct bladerf *dev, char *str)
+{
+ size_t len;
+ int status;
+ struct bladerf_devinfo info;
+ bladerf_fpga_size fpga_size;
+
+ status = bladerf_get_devinfo(dev, &info);
+ if (status < 0)
+ return false;
+
+ bladerf_get_fpga_size(dev, &fpga_size);
+ if (status < 0)
+ return false;
+
+ str++;
+ len = strlen(str);
+ if (str[len - 1] == ']')
+ str[len - 1] = '\0';
+
+ if (!strcmp(str, "x40")) {
+ return fpga_size == BLADERF_FPGA_40KLE;
+ } else if (!strcmp(str, "x115")) {
+ return fpga_size == BLADERF_FPGA_115KLE;
+ }
+
+ status = bladerf_devstr_matches(str, &info);
+
+ return status == 1;
+}
+
+int str2options(struct bladerf *dev,
+ const char *buf,
+ size_t buf_sz,
+ struct config_options **opts)
+{
+ char *line;
+ char *d_ptr;
+ int line_num;
+ char c;
+ unsigned i;
+
+ struct config_options *optv;
+ int optc;
+
+ char **line_argv;
+ int line_argc;
+
+ bool match;
+
+ match = true;
+
+ optv = NULL;
+ optc = 0;
+
+ line_num = 1;
+
+ line = malloc(buf_sz + 1);
+ if (!line)
+ return BLADERF_ERR_MEM;
+
+ d_ptr = line;
+
+ for (i = 0; i < buf_sz; i++) {
+ c = buf[i];
+ if (c == '\n') {
+ /* deal with the old line */
+ *d_ptr = 0;
+ line_argc = str2args(line, '#', &line_argv);
+ if (line_argc < 0)
+ goto out;
+
+ /* handle line */
+ if (line_argc > 3) {
+ log_error("Too many arguments in bladeRF.conf on line %d\n",
+ line_num);
+ goto out;
+ } else if (match && line_argc == 2) {
+ optc++;
+ optv =
+ add_opt(optv, optc, line_argv[0], line_argv[1], line_num);
+ if (!optv) {
+ optc = -1;
+ goto out;
+ }
+ } else if (line_argc == 1) {
+ if (*line_argv[0] != '[') {
+ log_error("Expecting scoping line (requires [ and ]) on "
+ "line %d\n",
+ line_num);
+ }
+ match = update_match(dev, line_argv[0]);
+ }
+
+ /* free line */
+ free_args(line_argc, line_argv);
+
+ /* setup to capture the next line */
+ line_num++;
+ d_ptr = line;
+ } else {
+ *d_ptr++ = c;
+ }
+ }
+
+ if (opts)
+ *opts = optv;
+
+out:
+ free(line);
+ return optc;
+}
+
+void free_opts(struct config_options *optv, int optc)
+{
+ int i;
+
+ for (i = 0; i < optc; i++) {
+ free(optv[i].key);
+ free(optv[i].value);
+ }
+ free(optv);
+}
+
+int csv2int(const char *line, int ***args)
+{
+ const char delim[] = " \r\n\t,.:"; /* supported delimiters */
+ const size_t MAXLEN = 128; /* max line length (with newline and null) */
+ static size_t arglen = 2; /* tunable: initial expected column count */
+ char *myline = NULL; /* local copy of 'line' */
+ char *parsestr = NULL; /* ptr to 'myline' on first strtok_r */
+ char *saveptr = NULL; /* strtok_r state pointer */
+ int **argout = NULL; /* array of output values */
+ size_t count = 0; /* count of tokens extracted */
+ size_t i;
+
+ // Validity check
+ if (NULL == line) {
+ log_debug("line is null\n");
+ return 0;
+ }
+
+ if (NULL == args) {
+ log_error("args is null\n");
+ goto fail;
+ }
+
+ // strtok_r doesn't respect const, so make a copy of 'line'
+ myline = calloc(MAXLEN, 1);
+ if (NULL == myline) {
+ log_error("could not calloc myline\n");
+ goto fail;
+ }
+
+ myline = strncpy(myline, line, MAXLEN - 1);
+
+ // Initial allocation of argout
+ argout = malloc(arglen * sizeof(int *));
+ if (NULL == argout) {
+ log_error("could not malloc argout\n");
+ goto fail;
+ }
+
+ // Loop over input until strtok_r returns a NULL
+ for (i = 0, parsestr = myline; true; ++i, parsestr = NULL) {
+ char *token = NULL; /* return token from strtok_r */
+ bool ok;
+
+ token = strtok_r(parsestr, delim, &saveptr);
+ if (NULL == token) {
+ break;
+ }
+
+ // Expand argout if necessary
+ if (i >= arglen) {
+ arglen *= 2;
+ log_verbose("expanding allocation to %zu column(s)\n", arglen);
+ int **newargout = realloc(argout, arglen * sizeof(int *));
+ if (NULL == newargout) {
+ log_error("could not realloc(argout,%zu)\n", arglen);
+ goto fail;
+ }
+ argout = newargout;
+ }
+
+ // Allocate memory for this value
+ argout[i] = malloc(sizeof(int));
+ if (NULL == argout[i]) {
+ log_error("could not malloc argout[%zu]\n", i);
+ goto fail;
+ }
+
+ // Update the count now, in case str2int fails and we need to dealloc
+ ++count;
+
+ // Parse token into an integer value
+ *argout[i] = str2int(token, INT32_MIN, INT32_MAX, &ok);
+ if (!ok) {
+ log_error("str2int failed on '%s'\n", token);
+ goto fail;
+ }
+ }
+
+ // Success!
+ *args = argout;
+ free(myline);
+
+ // If arglen is too big, cut it in half next time...
+ if (count <= (arglen / 2)) {
+ arglen /= 2;
+ log_verbose("decreasing future arglen to %zu\n", arglen);
+ }
+
+ return (int)count;
+
+fail:
+ // Deallocate everything...
+ free(myline);
+ free_csv2int((int)count, argout);
+ return -1;
+}
+
+void free_csv2int(int argc, int **args)
+{
+ int i;
+
+ if (NULL == args) {
+ return;
+ }
+
+ for (i = 0; i < argc; ++i) {
+ free(args[i]);
+ }
+
+ free(args);
+}
diff --git a/Radio/HW/BladeRF/common/src/range.c b/Radio/HW/BladeRF/common/src/range.c
new file mode 100644
index 0000000..c16fe22
--- /dev/null
+++ b/Radio/HW/BladeRF/common/src/range.c
@@ -0,0 +1,74 @@
+/*
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (C) 2018 Nuand LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef BLADERF_NIOS_BUILD
+#include "devices.h"
+#endif // BLADERF_NIOS_BUILD
+
+/* Avoid building this in low-memory situations */
+#if !defined(BLADERF_NIOS_BUILD) || defined(BLADERF_NIOS_LIBAD936X)
+
+#include "range.h"
+
+#if !defined(BLADERF_NIOS_BUILD) && !defined(BLADERF_NIOS_PC_SIMULATION)
+#include "log.h"
+#endif
+
+bool is_within_range(struct bladerf_range const *range, int64_t value)
+{
+ if (NULL == range) {
+ log_error("%s: range is null\n", __FUNCTION__);
+ return false;
+ }
+
+ return (__scale(range, value) >= range->min &&
+ __scale(range, value) <= range->max);
+}
+
+int64_t clamp_to_range(struct bladerf_range const *range, int64_t value)
+{
+ if (NULL == range) {
+ log_error("%s: range is null\n", __FUNCTION__);
+ return value;
+ }
+
+ if (__scale(range, value) < range->min) {
+ log_debug("%s: Requested value %" PRIi64
+ " is below range [%g,%g], clamping to %" PRIi64 "\n",
+ __FUNCTION__, value, __unscale(range, range->min),
+ __unscale(range, range->max),
+ __unscale_int64(range, range->min));
+ value = __unscale_int64(range, range->min);
+ }
+
+ if (__scale(range, value) > range->max) {
+ log_debug("%s: Requested value %" PRIi64
+ " is above range [%g,%g], clamping to %" PRIi64 "\n",
+ __FUNCTION__, value, __unscale(range, range->min),
+ __unscale(range, range->max),
+ __unscale_int64(range, range->max));
+ value = __unscale_int64(range, range->max);
+ }
+
+ return value;
+}
+
+#endif // !defined(BLADERF_NIOS_BUILD) || defined(BLADERF_NIOS_LIBAD936X)
diff --git a/Radio/HW/BladeRF/common/src/sha256.c b/Radio/HW/BladeRF/common/src/sha256.c
new file mode 100644
index 0000000..b65c7ff
--- /dev/null
+++ b/Radio/HW/BladeRF/common/src/sha256.c
@@ -0,0 +1,343 @@
+/*-
+ * Copyright 2005 Colin Percival
+ * Copyright 2013 Daniel Gröber
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include "sha256.h"
+
+#if BLADERF_BIG_ENDIAN == 1
+
+/* Copy a vector of big-endian uint32_t into a vector of bytes */
+#define be32enc_vect(dst, src, len) \
+ memcpy((void *)dst, (const void *)src, (size_t)len)
+
+/* Copy a vector of bytes into a vector of big-endian uint32_t */
+#define be32dec_vect(dst, src, len) \
+ memcpy((void *)dst, (const void *)src, (size_t)len)
+
+#else
+
+/* From libbsd/include/bsd/sys/endian.h */
+/*
+ * Copyright © 2011 Guillem Jover <guillem@hadrons.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+static __inline uint32_t
+be32dec(const void *pp)
+{
+ uint8_t const *p = (uint8_t const *)pp;
+
+ return (((unsigned)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
+}
+
+static __inline void
+be32enc(void *pp, uint32_t u)
+{
+ uint8_t *p = (uint8_t *)pp;
+
+ p[0] = (u >> 24) & 0xff;
+ p[1] = (u >> 16) & 0xff;
+ p[2] = (u >> 8) & 0xff;
+ p[3] = u & 0xff;
+}
+/* END from libbsd/include/bsd/sys/endian.h */
+
+/*
+ * Encode a length len/4 vector of (uint32_t) into a length len vector of
+ * (unsigned char) in big-endian form. Assumes len is a multiple of 4.
+ */
+static void
+be32enc_vect(unsigned char *dst, const uint32_t *src, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len / 4; i++)
+ be32enc(dst + i * 4, src[i]);
+}
+
+/*
+ * Decode a big-endian length len vector of (unsigned char) into a length
+ * len/4 vector of (uint32_t). Assumes len is a multiple of 4.
+ */
+static void
+be32dec_vect(uint32_t *dst, const unsigned char *src, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len / 4; i++)
+ dst[i] = be32dec(src + i * 4);
+}
+
+#endif
+
+/* Elementary functions used by SHA256 */
+#define Ch(x, y, z) ((x & (y ^ z)) ^ z)
+#define Maj(x, y, z) ((x & (y | z)) | (y & z))
+#define SHR(x, n) (x >> n)
+#define ROTR(x, n) ((x >> n) | (x << (32 - n)))
+#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
+#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
+#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3))
+#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10))
+
+/* SHA256 round function */
+#define RND(a, b, c, d, e, f, g, h, k) \
+ t0 = h + S1(e) + Ch(e, f, g) + k; \
+ t1 = S0(a) + Maj(a, b, c); \
+ d += t0; \
+ h = t0 + t1;
+
+/* Adjusted round function for rotating state */
+#define RNDr(S, W, i, k) \
+ RND(S[(64 - i) % 8], S[(65 - i) % 8], \
+ S[(66 - i) % 8], S[(67 - i) % 8], \
+ S[(68 - i) % 8], S[(69 - i) % 8], \
+ S[(70 - i) % 8], S[(71 - i) % 8], \
+ W[i] + k)
+
+/*
+ * SHA256 block compression function. The 256-bit state is transformed via
+ * the 512-bit input block to produce a new state.
+ */
+static void
+SHA256_Transform(uint32_t * state, const unsigned char block[64])
+{
+ uint32_t W[64];
+ uint32_t S[8];
+ uint32_t t0, t1;
+ int i;
+
+ /* 1. Prepare message schedule W. */
+ be32dec_vect(W, block, 64);
+ for (i = 16; i < 64; i++)
+ W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16];
+
+ /* 2. Initialize working variables. */
+ memcpy(S, state, 32);
+
+ /* 3. Mix. */
+ RNDr(S, W, 0, 0x428a2f98);
+ RNDr(S, W, 1, 0x71374491);
+ RNDr(S, W, 2, 0xb5c0fbcf);
+ RNDr(S, W, 3, 0xe9b5dba5);
+ RNDr(S, W, 4, 0x3956c25b);
+ RNDr(S, W, 5, 0x59f111f1);
+ RNDr(S, W, 6, 0x923f82a4);
+ RNDr(S, W, 7, 0xab1c5ed5);
+ RNDr(S, W, 8, 0xd807aa98);
+ RNDr(S, W, 9, 0x12835b01);
+ RNDr(S, W, 10, 0x243185be);
+ RNDr(S, W, 11, 0x550c7dc3);
+ RNDr(S, W, 12, 0x72be5d74);
+ RNDr(S, W, 13, 0x80deb1fe);
+ RNDr(S, W, 14, 0x9bdc06a7);
+ RNDr(S, W, 15, 0xc19bf174);
+ RNDr(S, W, 16, 0xe49b69c1);
+ RNDr(S, W, 17, 0xefbe4786);
+ RNDr(S, W, 18, 0x0fc19dc6);
+ RNDr(S, W, 19, 0x240ca1cc);
+ RNDr(S, W, 20, 0x2de92c6f);
+ RNDr(S, W, 21, 0x4a7484aa);
+ RNDr(S, W, 22, 0x5cb0a9dc);
+ RNDr(S, W, 23, 0x76f988da);
+ RNDr(S, W, 24, 0x983e5152);
+ RNDr(S, W, 25, 0xa831c66d);
+ RNDr(S, W, 26, 0xb00327c8);
+ RNDr(S, W, 27, 0xbf597fc7);
+ RNDr(S, W, 28, 0xc6e00bf3);
+ RNDr(S, W, 29, 0xd5a79147);
+ RNDr(S, W, 30, 0x06ca6351);
+ RNDr(S, W, 31, 0x14292967);
+ RNDr(S, W, 32, 0x27b70a85);
+ RNDr(S, W, 33, 0x2e1b2138);
+ RNDr(S, W, 34, 0x4d2c6dfc);
+ RNDr(S, W, 35, 0x53380d13);
+ RNDr(S, W, 36, 0x650a7354);
+ RNDr(S, W, 37, 0x766a0abb);
+ RNDr(S, W, 38, 0x81c2c92e);
+ RNDr(S, W, 39, 0x92722c85);
+ RNDr(S, W, 40, 0xa2bfe8a1);
+ RNDr(S, W, 41, 0xa81a664b);
+ RNDr(S, W, 42, 0xc24b8b70);
+ RNDr(S, W, 43, 0xc76c51a3);
+ RNDr(S, W, 44, 0xd192e819);
+ RNDr(S, W, 45, 0xd6990624);
+ RNDr(S, W, 46, 0xf40e3585);
+ RNDr(S, W, 47, 0x106aa070);
+ RNDr(S, W, 48, 0x19a4c116);
+ RNDr(S, W, 49, 0x1e376c08);
+ RNDr(S, W, 50, 0x2748774c);
+ RNDr(S, W, 51, 0x34b0bcb5);
+ RNDr(S, W, 52, 0x391c0cb3);
+ RNDr(S, W, 53, 0x4ed8aa4a);
+ RNDr(S, W, 54, 0x5b9cca4f);
+ RNDr(S, W, 55, 0x682e6ff3);
+ RNDr(S, W, 56, 0x748f82ee);
+ RNDr(S, W, 57, 0x78a5636f);
+ RNDr(S, W, 58, 0x84c87814);
+ RNDr(S, W, 59, 0x8cc70208);
+ RNDr(S, W, 60, 0x90befffa);
+ RNDr(S, W, 61, 0xa4506ceb);
+ RNDr(S, W, 62, 0xbef9a3f7);
+ RNDr(S, W, 63, 0xc67178f2);
+
+ /* 4. Mix local working variables into global state */
+ for (i = 0; i < 8; i++)
+ state[i] += S[i];
+}
+
+static unsigned char PAD[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* Add padding and terminating bit-count. */
+static void
+SHA256_Pad(SHA256_CTX * ctx)
+{
+ unsigned char len[8];
+ uint32_t r, plen;
+
+ /*
+ * Convert length to a vector of bytes -- we do this now rather
+ * than later because the length will change after we pad.
+ */
+ be32enc_vect(len, ctx->count, 8);
+
+ /* Add 1--64 bytes so that the resulting length is 56 mod 64 */
+ r = (ctx->count[1] >> 3) & 0x3f;
+ plen = (r < 56) ? (56 - r) : (120 - r);
+ SHA256_Update(ctx, PAD, (size_t)plen);
+
+ /* Add the terminating bit-count */
+ SHA256_Update(ctx, len, 8);
+}
+
+/* SHA-256 initialization. Begins a SHA-256 operation. */
+void
+SHA256_Init(SHA256_CTX * ctx)
+{
+
+ /* Zero bits processed so far */
+ ctx->count[0] = ctx->count[1] = 0;
+
+ /* Magic initialization constants */
+ ctx->state[0] = 0x6A09E667;
+ ctx->state[1] = 0xBB67AE85;
+ ctx->state[2] = 0x3C6EF372;
+ ctx->state[3] = 0xA54FF53A;
+ ctx->state[4] = 0x510E527F;
+ ctx->state[5] = 0x9B05688C;
+ ctx->state[6] = 0x1F83D9AB;
+ ctx->state[7] = 0x5BE0CD19;
+}
+
+/* Add bytes into the hash */
+void
+SHA256_Update(SHA256_CTX * ctx, const void *in, size_t len)
+{
+ uint32_t bitlen[2];
+ uint32_t r;
+ const unsigned char *src = in;
+
+ /* Number of bytes left in the buffer from previous updates */
+ r = (ctx->count[1] >> 3) & 0x3f;
+
+ /* Convert the length into a number of bits */
+ bitlen[1] = ((uint32_t)len) << 3;
+ bitlen[0] = (uint32_t)(len >> 29);
+
+ /* Update number of bits */
+ if ((ctx->count[1] += bitlen[1]) < bitlen[1])
+ ctx->count[0]++;
+ ctx->count[0] += bitlen[0];
+
+ /* Handle the case where we don't need to perform any transforms */
+ if (len < 64 - r) {
+ memcpy(&ctx->buf[r], src, len);
+ return;
+ }
+
+ /* Finish the current block */
+ memcpy(&ctx->buf[r], src, 64 - r);
+ SHA256_Transform(ctx->state, ctx->buf);
+ src += 64 - r;
+ len -= 64 - r;
+
+ /* Perform complete blocks */
+ while (len >= 64) {
+ SHA256_Transform(ctx->state, src);
+ src += 64;
+ len -= 64;
+ }
+
+ /* Copy left over data into buffer */
+ memcpy(ctx->buf, src, len);
+}
+
+/*
+ * SHA-256 finalization. Pads the input data, exports the hash value,
+ * and clears the context state.
+ */
+void
+SHA256_Final(unsigned char digest[32], SHA256_CTX * ctx)
+{
+
+ /* Add padding */
+ SHA256_Pad(ctx);
+
+ /* Write the hash */
+ be32enc_vect(digest, ctx->state, 32);
+
+ /* Clear the context state */
+ memset((void *)ctx, 0, sizeof(*ctx));
+}
diff --git a/Radio/HW/BladeRF/common/src/str_queue.c b/Radio/HW/BladeRF/common/src/str_queue.c
new file mode 100644
index 0000000..d5b14cd
--- /dev/null
+++ b/Radio/HW/BladeRF/common/src/str_queue.c
@@ -0,0 +1,193 @@
+/*
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (c) 2014 Nuand LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include <string.h>
+#include <stdlib.h>
+#include "str_queue.h"
+#include "host_config.h"
+
+struct str_queue_entry {
+ char *str;
+ struct str_queue_entry *next;
+};
+
+void str_queue_init(struct str_queue *q)
+{
+ memset(q, 0, sizeof(q[0]));
+}
+
+void str_queue_deinit(struct str_queue *q)
+{
+ char *str;
+
+ do {
+ str = str_queue_deq(q);
+ free(str);
+ } while (str != NULL);
+
+ q->head = NULL;
+ q->tail = NULL;
+}
+
+int str_queue_enq(struct str_queue *q, const char *str)
+{
+ struct str_queue_entry *entry = malloc(sizeof(entry[0]));
+ if (entry == NULL) {
+ return -1;
+ }
+
+ entry->str = strdup(str);
+ if (entry->str == NULL) {
+ free(entry);
+ return -1;
+ }
+ entry->next = NULL;
+
+ if (q->head == NULL) {
+ q->head = entry;
+ }
+
+ if (q->tail != NULL) {
+ q->tail->next = entry;
+ }
+
+ q->tail = entry;
+ return 0;
+}
+
+char * str_queue_deq(struct str_queue *q)
+{
+ char *ret;
+ struct str_queue_entry *entry;
+
+ entry = q->head;
+ if (entry == NULL) {
+ ret = NULL;
+ } else {
+ q->head = entry->next;
+ if (q->head == NULL) {
+ q->tail = NULL;
+ }
+
+ ret = entry->str;
+ free(entry);
+ }
+
+ return ret;
+}
+
+bool str_queue_empty(struct str_queue *q)
+{
+ return q->head == NULL || q->tail == NULL;
+}
+
+#if TEST_STR_QUEUE
+#include <stdio.h>
+
+#define STR_NULL "(null)"
+#define STR_1 "This is test string one."
+#define STR_2 "A second string queue test string"
+#define STR_3 "String thr33, this be"
+
+#define CHECK_EMPTY(q) do { \
+ if (str_queue_empty(q) != true) { \
+ fprintf(stderr, "Queue not empty!\n"); \
+ return EXIT_FAILURE; \
+ } \
+ } while (0)
+
+#define CHECK_NONEMPTY(q) do { \
+ if (str_queue_empty(q) != false) { \
+ fprintf(stderr, "Queue unexpectedly empty!\n"); \
+ return EXIT_FAILURE; \
+ } \
+ } while (0)
+
+#define ENQ(q, str) do { \
+ int status_ = str_queue_enq(q, str); \
+ if (status_ != 0) { \
+ fprintf(stderr, "Failed to enqueue %s\n", str); \
+ return EXIT_FAILURE; \
+ } else { \
+ printf("Enqueued: %s\n", str); \
+ } \
+ } while (0)
+
+#define DEQ(q, exp) do { \
+ char * str_; \
+ bool failed_; \
+ if (!strcmp(exp, STR_NULL)) { \
+ CHECK_EMPTY(q); \
+ } else { \
+ CHECK_NONEMPTY(q); \
+ } \
+ str_ = str_queue_deq(q); \
+ printf("Dequeued: %s\n", str_); \
+ if (str_ == NULL) { \
+ failed_ = strcmp(exp, STR_NULL) != 0; \
+ } else { \
+ failed_ = strcmp(str_, exp) != 0; \
+ } \
+ if (failed_) { \
+ fprintf(stderr, "Dequeue failed.\n"); \
+ return EXIT_FAILURE; \
+ } \
+ } while (0)
+
+int main(void)
+{
+ char *str;
+ struct str_queue q;
+
+ str_queue_init(&q);
+ str = str_queue_deq(&q);
+
+
+ DEQ(&q, STR_NULL);
+ ENQ(&q, STR_1);
+ DEQ(&q, STR_1);
+ DEQ(&q, STR_NULL);
+ DEQ(&q, STR_NULL);
+
+ ENQ(&q, STR_1);
+ ENQ(&q, STR_2);
+ DEQ(&q, STR_1);
+ DEQ(&q, STR_2);
+ DEQ(&q, STR_NULL);
+
+ ENQ(&q, STR_1);
+ ENQ(&q, STR_2);
+ DEQ(&q, STR_1);
+ ENQ(&q, STR_3);
+ DEQ(&q, STR_2);
+ ENQ(&q, STR_1);
+ DEQ(&q, STR_3);
+ DEQ(&q, STR_1);
+ DEQ(&q, STR_NULL);
+ DEQ(&q, STR_NULL);
+
+ str_queue_deinit(&q);
+ return 0;
+}
+#endif
diff --git a/Radio/HW/BladeRF/common/src/windows/clock_gettime.c b/Radio/HW/BladeRF/common/src/windows/clock_gettime.c
new file mode 100644
index 0000000..803799e
--- /dev/null
+++ b/Radio/HW/BladeRF/common/src/windows/clock_gettime.c
@@ -0,0 +1,58 @@
+/*
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (c) 2013 Nuand LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef WIN32
+# error "This file is intended for use with WIN32 systems only."
+#endif
+
+#include <Windows.h>
+#include <errno.h>
+#include "clock_gettime.h"
+#include "ptw32_timespec.h"
+
+int clock_gettime(clockid_t clk_id, struct timespec *tp)
+{
+ BOOL success;
+ FILETIME file_time;
+ SYSTEMTIME system_time;
+
+ if (clk_id != CLOCK_REALTIME) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ GetSystemTime(&system_time);
+ success = SystemTimeToFileTime(&system_time, &file_time);
+
+ if (!success) {
+ /* For lack of a better or more compliant return value... */
+ errno = EINVAL;
+ return -1;
+ }
+
+ ptw32_filetime_to_timespec(&file_time, tp);
+
+ return 0;
+}
+
diff --git a/Radio/HW/BladeRF/common/src/windows/getopt_long.c b/Radio/HW/BladeRF/common/src/windows/getopt_long.c
new file mode 100644
index 0000000..7a683fb
--- /dev/null
+++ b/Radio/HW/BladeRF/common/src/windows/getopt_long.c
@@ -0,0 +1,326 @@
+/** @file getopt_long.c
+ ** @brief getopt_long - Definition
+ ** @author Andrea Vedaldi
+ **/
+
+/*
+Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson.
+All rights reserved.
+
+This file is part of the VLFeat library and is made available under
+the terms of the BSD license (see legal/licenses/LICENSE.BSD.vlfeat).
+
+*/
+
+/**
+@file getopt_long.h
+@brief getopt_long
+@author Andrea Vedaldi
+
+This is a drop-in replacament of GNU getopt_long meant to be used
+on platforms that do not support such functionality.
+**/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "getopt.h"
+
+int opterr = 1 ;
+int optind = 1 ;
+int optopt ;
+char * optarg ;
+int optreset ;
+
+#define BADCH '?'
+#define BADARG ':'
+#define EEND -1
+#define EMSG ""
+
+/** @brief Parse long options (BSD style)
+ ** @param argc number of arguments.
+ ** @param argv pointer to the vector of arguments.
+ ** @param optstring list of abbreviated options
+ ** @param longopts list of long options.
+ ** @param longindex index of current option in @a longopts.
+ ** @return the code of the next option.
+ **
+ ** This function extract long and short options from the argument
+ ** list @a argv of @a argc entries.
+ **
+ ** A short options sequence is introduced by a single dash character
+ ** @c -. Each short option is described by a single character in the
+ ** string @a optstring, possibly followed by a @c : character to
+ ** denote a (mandatory) argument of the short option. A short option
+ ** with an argument cannot appear in the middle of a short option
+ ** sequence, but only at the end.
+ **
+ ** A long option is introduced by a double dash @c --. Each long
+ ** option is described by an instance of the ::option structure in
+ ** the @a longopts table (the last entry must be filled with zeroes
+ ** to denote the end).
+ **
+ ** Illegal options and missing arguments cause the function to skip
+ ** the option and return '?'. If ::opterr is @c true (default), the
+ ** function prints an error message to @a stderr. Finally, if @a
+ ** optstring has a leading @c :, then error messages are suppressed
+ ** and a missing argument causes @a : to be returned.
+ **
+ ** @remark The function is currently <em>not</em> thread safe.
+ **/
+
+VL_EXPORT int
+getopt_long(int argc, char *const argv[],
+ const char *optstring,
+ const struct option * longopts,
+ int *longindex)
+{
+ static char *place = EMSG; /* option letter processing */
+ static int optbegin = 0 ;
+ static int optend = 0 ;
+ const char *oli; /* option letter list index */
+ int has_colon = 0 ;
+ int ret_val = 0 ;
+
+ /*
+ A semicolon at the beginning of optstring has a special meaning.
+ If we find one, we annote and remove it.
+ */
+ has_colon = optstring && optstring[0] == ':' ;
+ if (has_colon) ++ optstring ;
+
+ /*
+ Here we are either processing a short option sequence or
+ we start processing a new option. This is indicated by optreset.
+ */
+
+ if (optreset || *place == '\0') {
+
+ /* ---------------------------------------------------------------
+ * Look for next short/long option
+ * ------------------------------------------------------------ */
+ optreset = 0 ;
+
+ /* no more arguments ? */
+ if (optind >= argc) {
+ place = EMSG ;
+ return -1 ;
+ }
+
+ /* next argument that may hold an option */
+ optbegin = optind ;
+
+ /* ---------------------------------------------------------------
+ * Look for an option to parse
+ * ------------------------------------------------------------ */
+
+ parse_option_at_optbegin :
+
+ /* place points to the candidate option */
+ place = argv [optbegin] ;
+
+ /* an option is introduced by '-' */
+ if (place [0] != '-') {
+ /* this argument is not an option: try next argument */
+ ++ optbegin ;
+ if (optbegin >= argc) {
+ /* no more arguments to look for options */
+ place = EMSG ;
+ return -1 ;
+ }
+ goto parse_option_at_optbegin ;
+ }
+
+ /* consume leading `-' */
+ ++ place ;
+
+ /* assume the option is composed of one argument only */
+ optend = optbegin + 1 ;
+
+ /* assume no argument */
+ optarg = 0 ;
+
+ /* ---------------------------------------------------------------
+ * option `--'
+ * ------------------------------------------------------------ */
+
+ /* this special option (void long option) ends the option processing */
+ if (place[0] &&
+ place[0] == '-' &&
+ place[1] == '\0') {
+
+ optind = optend ;
+ place = EMSG ;
+ ret_val = -1 ;
+ goto done_option ;
+ }
+
+ /* ---------------------------------------------------------------
+ * long option
+ * ------------------------------------------------------------ */
+
+ if (place[0] &&
+ place[0] == '-' &&
+ place[1] ) {
+
+ size_t namelen ;
+ int i ;
+
+ /* consume second `-' */
+ ++ place ;
+
+ /* count characters before `=' */
+ namelen = strcspn(place, "=") ;
+
+ /* scan longopts for this option */
+ for (i = 0 ; longopts[i].name != NULL ; ++ i) {
+
+ if (strlen ( longopts[i].name) == namelen &&
+ strncmp (place, longopts[i].name, namelen) == 0 ) {
+
+ /* save back long option index */
+ if (longindex) *longindex = i ;
+
+ /* process long option argument */
+ if (longopts[i].has_arg == required_argument ||
+ longopts[i].has_arg == optional_argument) {
+
+ /* --option=value style */
+ if (place[namelen] == '=') {
+ optarg = place + namelen + 1 ;
+ }
+
+ /* --option value style (only required_argument) */
+ else if (longopts[i].has_arg == required_argument) {
+ /* missing argument ? */
+ if (optbegin >= argc - 1) {
+ if (! has_colon && opterr)
+ fprintf(stderr,
+ "%s: option requires an argument -- %s\n",
+ argv[0], place);
+ place = EMSG ;
+ ret_val = has_colon ? BADARG : BADCH ;
+ goto done_option ;
+ }
+ optarg = argv [optend] ;
+ ++ optend ;
+ }
+ }
+
+ /* determine return value */
+ if (longopts[i].flag == NULL) {
+ ret_val = longopts[i].val ;
+ }
+ else {
+ *longopts[i].flag = longopts[i].val;
+ ret_val = 0 ;
+ }
+
+ /* mark sequence closed */
+ place = EMSG ;
+ goto done_option ;
+ } /* if match */
+
+ } /* scan longoptions */
+
+ /* no matching option found */
+ if (! has_colon && opterr)
+ fprintf(stderr,
+ "%s: illegal option -- %s\n", argv[0], place) ;
+ place = EMSG ;
+ ret_val = BADCH ;
+ goto done_option ;
+ }
+ } /* end new option */
+
+ /* -----------------------------------------------------------------
+ * Finish short option sequence
+ * -------------------------------------------------------------- */
+ optopt = (int) *place++ ;
+
+ /* search charcater in option list */
+ oli = strchr(optstring, optopt);
+
+ /* short option not found */
+ if (!oli) {
+
+ if (! has_colon && opterr)
+ fprintf(stderr,
+ "%s: illegal option -- %c\n",
+ argv[0], optopt);
+
+ if (*place) {
+ /* more short options in the list */
+ return BADCH ;
+ }
+
+ else {
+ /* error occured as last option in the list */
+ place = EMSG ;
+ ret_val = BADCH ;
+ goto done_option ;
+ }
+ } /* end short option not found */
+
+ if (oli[1] != ':') {
+ /* short option with no argument */
+
+ if (*place) {
+ /* more short options in the list */
+ return optopt ;
+ }
+ else {
+ /* last option in the list */
+ place = EMSG ;
+ ret_val = optopt ;
+ goto done_option ;
+ }
+
+ } else {
+ /* short option with argument */
+
+ /* -ovalue style */
+ if (*place) {
+ optarg = place ;
+ place = EMSG ;
+ ret_val = optopt ;
+ goto done_option ;
+ }
+ /* -o value style: missing argument */
+ else if (optbegin >= argc - 1) {
+ if (! has_colon && opterr)
+ fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ argv[0], optopt);
+ place = EMSG ;
+ ret_val = has_colon ? BADARG : BADCH ;
+ goto done_option ;
+ }
+
+ /* -o value style: process argument */
+ optarg = argv [optend] ;
+ ++ optend ;
+ place = EMSG ;
+ ret_val = optopt ;
+ goto done_option ;
+ } /* short with argument */
+
+ done_option :
+ {
+ int pos = optend - optbegin ; /* n of circular shifts */
+ int c = pos ;
+
+ while (c --) {
+ int i ;
+ char *tmp = argv [optend - 1] ;
+ for (i = optend - 1 ; i > optind ; -- i) {
+ ((char**)argv) [i] = argv [i-1] ;
+ }
+ ((char**)argv) [optind] = tmp ;
+ }
+ optind += pos ;
+ }
+
+ return ret_val ;
+}
diff --git a/Radio/HW/BladeRF/common/src/windows/gettimeofday.c b/Radio/HW/BladeRF/common/src/windows/gettimeofday.c
new file mode 100644
index 0000000..144ee2f
--- /dev/null
+++ b/Radio/HW/BladeRF/common/src/windows/gettimeofday.c
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (c) 2023 Nuand LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef WIN32
+#error "This file is intended for use with WIN32 systems only."
+#endif
+
+#include <windows.h>
+#include <stdint.h>
+int gettimeofday(struct timeval *tp, struct timezone *tzp)
+{
+ // Note: some broken versions only have 8 trailing zero's, the correct epoch
+ // has 9 trailing zero's
+ static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL);
+
+ SYSTEMTIME system_time;
+ FILETIME file_time;
+ uint64_t time;
+
+ GetSystemTime(&system_time);
+ SystemTimeToFileTime(&system_time, &file_time);
+ time = ((uint64_t)file_time.dwLowDateTime);
+ time += ((uint64_t)file_time.dwHighDateTime) << 32;
+
+ tp->tv_sec = (long)((time - EPOCH) / 10000000L);
+ tp->tv_usec = (long)(system_time.wMilliseconds * 1000);
+ return 0;
+}
diff --git a/Radio/HW/BladeRF/common/src/windows/mkdtemp.c b/Radio/HW/BladeRF/common/src/windows/mkdtemp.c
new file mode 100644
index 0000000..0e2f804
--- /dev/null
+++ b/Radio/HW/BladeRF/common/src/windows/mkdtemp.c
@@ -0,0 +1,250 @@
+/*
+ * This file is part of the bladeRF project:
+ * http://www.github.com/Nuand/bladeRF
+ *
+ * Copyright (c) 2018 Nuand LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+// _CRT_RAND_S must be defined before including stdlib.h, to enable rand_s
+#define _CRT_RAND_S
+#include <stdlib.h>
+
+#ifdef WINDOWS_MKDTEMP_TEST_SUITE
+// Running in standalone test mode
+
+#include <stdbool.h>
+#include <stdio.h>
+#define __debug(...) fprintf(stderr, __VA_ARGS__)
+
+#ifndef WIN32
+// Running standalone test on non-Windows OS
+#include <time.h>
+#include <unistd.h>
+#define errno_t int
+errno_t rand_s(unsigned int *randomValue)
+{
+ *randomValue = rand();
+ return 0;
+}
+#endif // WIN32
+
+#else
+// Building as part of a library
+
+#ifndef WIN32
+#error "This file is intended for use with WIN32 systems only."
+#endif // WIN32
+
+#define __debug(...)
+
+#endif // WINDOWS_MKDTEMP_TEST_SUITE
+
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+#include "host_config.h"
+
+// The concepts of F_OK and S_IRWXU do not exist on Win32
+#ifndef F_OK
+#define F_OK 0
+#endif
+
+#ifndef S_IRWXU
+#define S_IRWXU 00700
+#endif
+
+/* h/t https://stackoverflow.com/a/14598879 */
+static int random_number(int min_num, int max_num)
+{
+ int result = 0, low_num = 0, hi_num = 0;
+ unsigned int randomValue;
+
+ if (min_num < max_num) {
+ low_num = min_num;
+ hi_num = max_num + 1; // include max_num in output
+ } else {
+ low_num = max_num + 1; // include max_num in output
+ hi_num = min_num;
+ }
+
+ // Use rand_s() on Windows, so that we don't have to deal with srand()
+ errno_t err = rand_s(&randomValue);
+ if (0 != err) {
+ return -1;
+ }
+
+ result = (randomValue % (hi_num - low_num)) + low_num;
+ return result;
+}
+
+char *mkdtemp(char *template)
+{
+ size_t const TEMPL_LEN = 6;
+ char const TEMPL_CHAR = 'X';
+
+ if (strlen(template) <= TEMPL_LEN) {
+ // template is too short
+ errno = EINVAL;
+ goto error;
+ }
+
+ // Loop through the end of the template, replacing 'X' with random char
+ for (size_t i = strlen(template) - TEMPL_LEN; i < strlen(template); ++i) {
+ // The last TEMPL_LEN characters MUST be 'X'
+ if (template[i] != TEMPL_CHAR) {
+ errno = EINVAL;
+ goto error;
+ }
+
+ // Pick a random letter
+ if (random_number(0, 1)) {
+ template[i] = (char)random_number('A', 'Z');
+ } else {
+ template[i] = (char)random_number('a', 'z');
+ }
+ }
+
+ // Error out if the file already exists
+ if (access(template, F_OK) != -1) {
+ __debug("%s: failed: %s exists\n", __FUNCTION__, template);
+ errno = EEXIST;
+ goto error;
+ }
+
+ // Try to create the directory...
+ if (0 != mkdir(template, S_IRWXU)) {
+ int errsv = errno;
+ __debug("%s: mkdir() failed: %s\n", __FUNCTION__, strerror(errsv));
+ goto error;
+ }
+
+ // Success!
+ errno = 0;
+ return template;
+
+error:
+ return NULL;
+}
+
+#ifdef WINDOWS_MKDTEMP_TEST_SUITE
+/**
+ * These functions are intended to verify proper operation of the test suite.
+ */
+static bool test(char *template, bool expect_success)
+{
+ char *rv = mkdtemp(template);
+
+ if (NULL == rv) {
+ int errsv = errno;
+ printf("%s: mkdtemp failed: %s\n", __FUNCTION__, strerror(errsv));
+ return (false == expect_success);
+ } else {
+ printf("%s: mkdtemp created: %s\n", __FUNCTION__, rv);
+
+ if (0 != rmdir(rv)) {
+ int errsv = errno;
+ printf("%s: rmdir failed: %s\n", __FUNCTION__, strerror(errsv));
+ }
+
+ return (true == expect_success);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+#ifndef WIN32
+ srand(time(NULL));
+#endif // WIN32
+
+ int success = 0, failure = 0;
+
+ // Normal: should pass
+ char template1[] = "/tmp/asdf.XXXXXX";
+ if (test(template1, true)) {
+ printf("*** Test case 1: PASS\n");
+ ++success;
+ } else {
+ printf("*** Test case 1: FAIL\n");
+ ++failure;
+ }
+
+ // Too short: should fail
+ char template2[] = "XXXXXX";
+ if (test(template2, false)) {
+ printf("*** Test case 2: PASS\n");
+ ++success;
+ } else {
+ printf("*** Test case 2: FAIL\n");
+ ++failure;
+ }
+
+ // Not enough replacement Xs: should fail
+ char template3[] = "/tmp/asdf.XXXXX";
+ if (test(template3, false)) {
+ printf("*** Test case 3: PASS\n");
+ ++success;
+ } else {
+ printf("*** Test case 3: FAIL\n");
+ ++failure;
+ }
+
+ // Make sure it only replaces the end: should pass
+ char template4[] = "/tmp/asdfXXXXXX.XXXXXX";
+ if (test(template4, true)) {
+ printf("*** Test case 4: PASS\n");
+ ++success;
+ } else {
+ printf("*** Test case 4: FAIL\n");
+ ++failure;
+ }
+
+ // Really long: should fail
+ char template5[] = "/tmp/asdfaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaXXXXXX";
+ if (test(template5, false)) {
+ printf("*** Test case 5: PASS\n");
+ ++success;
+ } else {
+ printf("*** Test case 5: FAIL\n");
+ ++failure;
+ }
+
+ // Unwriteable path: should fail
+ char template6[] = "/asdfkjavblkjadv/asdf.XXXX";
+ if (test(template6, false)) {
+ printf("*** Test case 6: PASS\n");
+ ++success;
+ } else {
+ printf("*** Test case 6: FAIL\n");
+ ++failure;
+ }
+
+ printf("TEST SUMMARY: Success=%d, Failure=%d\n", success, failure);
+
+ return failure;
+}
+#endif // WINDOWS_MKDTEMP_TEST_SUITE
diff --git a/Radio/HW/BladeRF/common/src/windows/nanosleep.c b/Radio/HW/BladeRF/common/src/windows/nanosleep.c
new file mode 100644
index 0000000..12d470a
--- /dev/null
+++ b/Radio/HW/BladeRF/common/src/windows/nanosleep.c
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the bladeRF project:
+ * http://www.github.com/nuand/bladeRF
+ *
+ * Copyright (c) 2018 Nuand LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef WIN32
+#error "This file is intended for use with WIN32 systems only."
+#endif
+
+#include "nanosleep.h"
+#include <windows.h>
+
+int nanosleep(const struct timespec *req, struct timespec *rem)
+{
+ DWORD sleep_ms;
+
+ sleep_ms = ((DWORD)req->tv_sec * 1000) + ((DWORD)req->tv_nsec / 1000000);
+
+ Sleep(sleep_ms);
+
+ return 0;
+}
diff --git a/Radio/HW/BladeRF/common/src/windows/setenv.c b/Radio/HW/BladeRF/common/src/windows/setenv.c
new file mode 100644
index 0000000..1f7eb8c
--- /dev/null
+++ b/Radio/HW/BladeRF/common/src/windows/setenv.c
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the bladeRF project:
+ * http://www.github.com/Nuand/bladeRF
+ *
+ * Copyright (c) 2018 Nuand LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef WIN32
+#error "This file is intended for use with WIN32 systems only."
+#endif // WIN32
+
+#include <stdlib.h>
+
+int setenv(const char *name, const char *value, int overwrite)
+{
+ errno_t rv = 0;
+ size_t envsize = 0;
+
+ if (!overwrite) {
+ // Test for existence
+ rv = getenv_s(&envsize, NULL, 0, name);
+ if (rv != 0 || envsize != 0) {
+ return rv;
+ }
+ }
+ return _putenv_s(name, value);
+}
+
+int unsetenv(const char *name)
+{
+ return _putenv_s(name, "");
+}
diff --git a/Radio/HW/BladeRF/common/thirdparty/ad936x/ad9361.c b/Radio/HW/BladeRF/common/thirdparty/ad936x/ad9361.c
new file mode 100644
index 0000000..f63ef84
--- /dev/null
+++ b/Radio/HW/BladeRF/common/thirdparty/ad936x/ad9361.c
@@ -0,0 +1,7218 @@
+/***************************************************************************//**
+ * @file ad9361.c
+ * @brief Implementation of AD9361 Driver.
+********************************************************************************
+ * Copyright 2014-2015(c) Analog Devices, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of Analog Devices, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * - The use of this software may or may not infringe the patent rights
+ * of one or more patent holders. This license does not release you
+ * from the requirement that you obtain separate licenses from these
+ * patent holders to use this software.
+ * - Use of the software either in source or binary form, must be run
+ * on or directly connected to an Analog Devices Inc. component.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+/******************************************************************************/
+/***************************** Include Files **********************************/
+/******************************************************************************/
+#include "host_config.h"
+#if !defined(BLADERF_OS_FREEBSD) && !defined(BLADERF_OS_OSX)
+#include <malloc.h>
+#endif // BLADERF_OS_FREEBSD + BLADERF_OS_OSX
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include "ad9361.h"
+#include "platform.h"
+#include "util.h"
+#include "config.h"
+
+/* Used for static code size optimization: please see config.h */
+const bool has_split_gt = HAVE_SPLIT_GAIN_TABLE;
+const bool have_tdd_tables = HAVE_TDD_SYNTH_TABLE;
+
+#define SYNTH_LUT_SIZE 53
+
+static const struct SynthLUT SynthLUT_FDD[LUT_FTDD_ENT][SYNTH_LUT_SIZE] = {
+ {
+ {12605, 13, 1, 4, 2, 15, 12, 7, 14, 6, 14, 5, 15}, /* 40 MHz */
+ {12245, 13, 1, 4, 2, 15, 12, 7, 14, 6, 14, 5, 15},
+ {11906, 13, 1, 4, 2, 15, 12, 7, 15, 6, 14, 5, 15},
+ {11588, 13, 1, 4, 2, 15, 12, 8, 15, 6, 14, 5, 15},
+ {11288, 13, 1, 4, 2, 15, 12, 8, 15, 6, 14, 5, 15},
+ {11007, 13, 1, 4, 2, 15, 12, 9, 15, 6, 14, 5, 15},
+ {10742, 13, 1, 4, 2, 15, 12, 9, 15, 6, 14, 5, 15},
+ {10492, 13, 1, 6, 2, 15, 12, 10, 15, 6, 14, 5, 15},
+ {10258, 13, 1, 6, 2, 15, 12, 10, 15, 6, 14, 5, 15},
+ {10036, 13, 1, 6, 2, 15, 12, 11, 15, 6, 14, 5, 15},
+ {9827, 13, 1, 6, 2, 14, 12, 11, 15, 6, 14, 5, 15},
+ {9631, 13, 1, 6, 2, 13, 12, 12, 15, 6, 14, 5, 15},
+ {9445, 13, 1, 6, 2, 12, 12, 12, 15, 6, 14, 5, 15},
+ {9269, 13, 1, 6, 2, 12, 12, 13, 15, 6, 14, 5, 15},
+ {9103, 13, 1, 6, 2, 12, 12, 13, 15, 6, 14, 5, 15},
+ {8946, 13, 1, 6, 2, 12, 12, 14, 15, 6, 14, 5, 15},
+ {8797, 12, 1, 7, 2, 12, 12, 13, 15, 6, 14, 5, 15},
+ {8655, 12, 1, 7, 2, 12, 12, 14, 15, 6, 14, 5, 15},
+ {8520, 12, 1, 7, 2, 12, 12, 14, 15, 6, 14, 5, 15},
+ {8392, 12, 1, 7, 2, 12, 12, 15, 15, 6, 14, 5, 15},
+ {8269, 12, 1, 7, 2, 12, 12, 15, 15, 6, 14, 5, 15},
+ {8153, 12, 1, 7, 2, 12, 12, 16, 15, 6, 14, 5, 15},
+ {8041, 12, 1, 7, 2, 13, 12, 16, 15, 6, 14, 5, 15},
+ {7934, 11, 1, 7, 2, 12, 12, 16, 15, 6, 14, 5, 15},
+ {7831, 11, 1, 7, 2, 12, 12, 16, 15, 6, 14, 5, 15},
+ {7733, 10, 1, 7, 3, 13, 12, 16, 15, 6, 14, 5, 15},
+ {7638, 10, 1, 7, 2, 12, 12, 16, 15, 6, 14, 5, 15},
+ {7547, 10, 1, 7, 2, 12, 12, 17, 15, 6, 14, 5, 15},
+ {7459, 10, 1, 7, 2, 12, 12, 17, 15, 6, 14, 5, 15},
+ {7374, 10, 2, 7, 3, 14, 13, 14, 15, 6, 14, 5, 15},
+ {7291, 10, 2, 7, 3, 14, 13, 14, 15, 6, 14, 5, 15},
+ {7212, 10, 2, 7, 3, 14, 13, 14, 15, 6, 14, 5, 15},
+ {7135, 10, 2, 7, 3, 14, 13, 15, 15, 7, 14, 5, 15},
+ {7061, 10, 2, 7, 3, 14, 13, 15, 15, 6, 14, 5, 15},
+ {6988, 10, 1, 7, 3, 12, 14, 20, 15, 6, 14, 5, 15},
+ {6918, 9, 2, 7, 3, 14, 13, 15, 15, 6, 14, 5, 15},
+ {6850, 9, 2, 7, 3, 14, 13, 15, 15, 6, 14, 5, 15},
+ {6784, 9, 2, 7, 2, 13, 13, 15, 15, 6, 14, 5, 15},
+ {6720, 9, 2, 7, 2, 13, 13, 16, 15, 6, 14, 5, 15},
+ {6658, 8, 2, 7, 3, 14, 13, 15, 15, 6, 14, 5, 15},
+ {6597, 8, 2, 7, 2, 13, 13, 15, 15, 6, 14, 5, 15},
+ {6539, 8, 2, 7, 2, 13, 13, 15, 15, 6, 14, 5, 15},
+ {6482, 8, 2, 7, 2, 13, 13, 16, 15, 6, 14, 5, 15},
+ {6427, 7, 2, 7, 3, 14, 13, 15, 15, 6, 14, 5, 15},
+ {6373, 7, 2, 7, 3, 15, 13, 15, 15, 6, 14, 5, 15},
+ {6321, 7, 2, 7, 3, 15, 13, 15, 15, 6, 14, 5, 15},
+ {6270, 7, 2, 7, 3, 15, 13, 16, 15, 6, 14, 5, 15},
+ {6222, 7, 2, 7, 3, 15, 13, 16, 15, 6, 14, 5, 15},
+ {6174, 6, 2, 7, 3, 15, 13, 15, 15, 6, 14, 5, 15},
+ {6128, 6, 2, 7, 3, 15, 13, 15, 15, 6, 14, 5, 15},
+ {6083, 6, 2, 7, 3, 15, 13, 16, 15, 6, 14, 5, 15},
+ {6040, 6, 2, 7, 3, 15, 13, 16, 15, 6, 14, 5, 15},
+ {5997, 6, 2, 7, 3, 15, 13, 16, 15, 6, 14, 5, 15},
+ }, {
+ {12605, 13, 1, 4, 2, 15, 12, 13, 15, 12, 12, 5, 14}, /* 60 MHz */
+ {12245, 13, 1, 4, 2, 15, 12, 13, 15, 12, 12, 5, 14},
+ {11906, 13, 1, 4, 2, 15, 12, 13, 15, 13, 12, 5, 13},
+ {11588, 13, 1, 4, 2, 15, 12, 14, 15, 13, 12, 5, 13},
+ {11288, 13, 1, 5, 2, 15, 12, 15, 15, 13, 12, 5, 13},
+ {11007, 13, 1, 5, 2, 15, 12, 16, 15, 13, 12, 5, 13},
+ {10742, 13, 1, 5, 2, 15, 12, 16, 15, 12, 12, 5, 14},
+ {10492, 13, 1, 6, 2, 15, 12, 17, 15, 12, 12, 5, 14},
+ {10258, 13, 1, 6, 2, 15, 12, 18, 15, 13, 12, 5, 13},
+ {10036, 13, 1, 6, 2, 15, 12, 19, 15, 13, 12, 5, 13},
+ {9827, 13, 1, 6, 2, 14, 12, 20, 15, 13, 12, 5, 13},
+ {9631, 13, 1, 6, 2, 13, 12, 21, 15, 13, 12, 5, 13},
+ {9445, 13, 1, 6, 2, 12, 12, 22, 15, 13, 12, 5, 13},
+ {9269, 13, 1, 6, 2, 12, 12, 22, 15, 12, 12, 5, 14},
+ {9103, 13, 1, 6, 2, 12, 12, 23, 15, 13, 12, 5, 13},
+ {8946, 13, 1, 6, 2, 12, 12, 24, 15, 13, 12, 5, 13},
+ {8797, 12, 1, 7, 2, 12, 12, 24, 15, 13, 12, 5, 13},
+ {8655, 12, 1, 7, 2, 12, 12, 25, 15, 13, 12, 5, 13},
+ {8520, 12, 1, 7, 2, 12, 12, 25, 15, 13, 12, 5, 13},
+ {8392, 12, 1, 7, 2, 12, 12, 26, 15, 13, 12, 5, 13},
+ {8269, 12, 1, 7, 2, 12, 12, 27, 15, 13, 12, 5, 13},
+ {8153, 12, 1, 7, 2, 12, 12, 28, 15, 13, 12, 5, 13},
+ {8041, 12, 1, 7, 2, 13, 12, 29, 15, 13, 12, 5, 13},
+ {7934, 11, 1, 7, 2, 12, 12, 28, 15, 13, 12, 5, 13},
+ {7831, 11, 1, 7, 2, 12, 12, 29, 15, 13, 12, 5, 13},
+ {7733, 10, 1, 7, 3, 13, 12, 28, 15, 13, 12, 5, 13},
+ {7638, 10, 1, 7, 2, 12, 12, 29, 15, 13, 12, 5, 13},
+ {7547, 10, 1, 7, 2, 12, 12, 29, 15, 13, 12, 5, 13},
+ {7459, 10, 1, 7, 2, 12, 12, 30, 15, 13, 12, 5, 13},
+ {7374, 10, 2, 7, 3, 14, 13, 24, 15, 13, 12, 5, 13},
+ {7291, 10, 2, 7, 3, 14, 13, 25, 15, 13, 12, 5, 13},
+ {7212, 10, 2, 7, 3, 14, 13, 25, 15, 13, 12, 5, 13},
+ {7135, 10, 2, 7, 3, 14, 13, 26, 15, 13, 12, 5, 13},
+ {7061, 10, 2, 7, 3, 14, 13, 26, 15, 13, 12, 5, 13},
+ {6988, 10, 1, 7, 3, 12, 14, 35, 15, 13, 12, 5, 13},
+ {6918, 9, 1, 7, 3, 12, 14, 33, 15, 13, 12, 5, 13},
+ {6850, 9, 1, 7, 3, 12, 14, 34, 15, 13, 12, 5, 13},
+ {6784, 9, 1, 7, 2, 11, 14, 35, 15, 13, 12, 5, 13},
+ {6720, 9, 1, 7, 2, 11, 14, 35, 15, 13, 12, 5, 13},
+ {6658, 8, 2, 7, 3, 15, 13, 26, 15, 13, 12, 5, 13},
+ {6597, 8, 2, 7, 2, 15, 13, 27, 15, 13, 12, 5, 13},
+ {6539, 8, 2, 7, 2, 15, 13, 27, 15, 13, 12, 5, 13},
+ {6482, 8, 2, 7, 2, 15, 13, 28, 15, 13, 12, 5, 13},
+ {6427, 7, 2, 7, 3, 14, 13, 27, 15, 13, 12, 5, 13},
+ {6373, 7, 2, 7, 3, 15, 13, 27, 15, 13, 12, 5, 13},
+ {6321, 7, 2, 7, 3, 15, 13, 27, 15, 13, 12, 5, 13},
+ {6270, 7, 2, 7, 3, 15, 13, 28, 15, 13, 12, 5, 13},
+ {6222, 7, 2, 7, 3, 15, 13, 28, 15, 13, 12, 5, 13},
+ {6174, 6, 2, 7, 3, 15, 13, 27, 15, 13, 12, 5, 13},
+ {6128, 6, 2, 7, 3, 15, 13, 27, 15, 13, 12, 5, 13},
+ {6083, 6, 2, 7, 3, 15, 13, 28, 15, 13, 12, 5, 13},
+ {6040, 6, 2, 7, 3, 15, 13, 28, 15, 13, 12, 5, 13},
+ {5997, 6, 2, 7, 3, 15, 13, 29, 15, 13, 12, 5, 13},
+ }, {
+ {12605, 13, 1, 4, 2, 15, 12, 7, 15, 6, 13, 5, 14}, /* 80 MHz */
+ {12245, 13, 1, 4, 2, 15, 12, 7, 15, 6, 13, 5, 14},
+ {11906, 13, 1, 4, 2, 15, 12, 7, 15, 6, 13, 5, 14},
+ {11588, 13, 1, 4, 2, 15, 12, 7, 14, 6, 14, 4, 14},
+ {11288, 13, 1, 4, 2, 15, 12, 8, 15, 6, 13, 5, 14},
+ {11007, 13, 1, 4, 2, 15, 12, 8, 14, 6, 13, 5, 14},
+ {10742, 13, 1, 4, 2, 15, 12, 9, 15, 6, 13, 5, 14},
+ {10492, 13, 1, 6, 2, 15, 12, 9, 14, 6, 13, 5, 14},
+ {10258, 13, 1, 6, 2, 15, 12, 10, 15, 6, 13, 5, 14},
+ {10036, 13, 1, 6, 2, 15, 12, 10, 15, 6, 13, 5, 14},
+ {9827, 13, 1, 6, 2, 14, 12, 11, 15, 6, 13, 5, 14},
+ {9631, 13, 1, 6, 2, 13, 12, 11, 15, 6, 13, 5, 14},
+ {9445, 13, 1, 6, 2, 12, 12, 12, 15, 6, 13, 5, 14},
+ {9269, 13, 1, 6, 2, 12, 12, 12, 15, 6, 13, 5, 14},
+ {9103, 13, 1, 6, 2, 12, 12, 13, 15, 6, 13, 5, 14},
+ {8946, 13, 1, 6, 2, 12, 12, 13, 15, 6, 13, 5, 14},
+ {8797, 12, 1, 7, 2, 12, 12, 13, 15, 6, 13, 5, 14},
+ {8655, 12, 1, 7, 2, 12, 12, 14, 15, 6, 13, 5, 14},
+ {8520, 12, 1, 7, 2, 12, 12, 14, 15, 6, 13, 5, 14},
+ {8392, 12, 1, 7, 2, 12, 12, 15, 15, 7, 13, 5, 14},
+ {8269, 12, 1, 7, 2, 12, 12, 15, 15, 6, 13, 5, 14},
+ {8153, 12, 1, 7, 2, 12, 12, 15, 15, 6, 13, 5, 14},
+ {8041, 12, 1, 7, 2, 13, 12, 16, 15, 6, 13, 5, 14},
+ {7934, 11, 1, 7, 2, 12, 12, 15, 15, 6, 13, 5, 14},
+ {7831, 11, 1, 7, 2, 12, 12, 16, 15, 6, 13, 5, 14},
+ {7733, 10, 1, 7, 3, 13, 12, 15, 15, 6, 13, 5, 14},
+ {7638, 10, 1, 7, 2, 12, 12, 16, 15, 6, 13, 5, 14},
+ {7547, 10, 1, 7, 2, 12, 12, 16, 15, 6, 13, 5, 14},
+ {7459, 10, 1, 7, 2, 12, 12, 17, 15, 6, 13, 5, 14},
+ {7374, 10, 2, 7, 3, 14, 13, 13, 15, 6, 13, 5, 14},
+ {7291, 10, 2, 7, 3, 14, 13, 14, 15, 6, 13, 5, 14},
+ {7212, 10, 2, 7, 3, 14, 13, 14, 15, 6, 13, 5, 14},
+ {7135, 10, 2, 7, 3, 14, 13, 14, 15, 6, 13, 5, 14},
+ {7061, 10, 2, 7, 3, 14, 13, 15, 15, 6, 13, 5, 14},
+ {6988, 10, 1, 7, 3, 12, 14, 19, 15, 6, 13, 5, 14},
+ {6918, 9, 2, 7, 3, 14, 13, 14, 15, 6, 13, 5, 14},
+ {6850, 9, 2, 7, 3, 14, 13, 15, 15, 6, 13, 5, 14},
+ {6784, 9, 2, 7, 2, 13, 13, 15, 15, 6, 13, 5, 14},
+ {6720, 9, 2, 7, 2, 13, 13, 15, 15, 6, 13, 5, 14},
+ {6658, 8, 2, 7, 3, 14, 13, 15, 15, 6, 13, 5, 14},
+ {6597, 8, 2, 7, 2, 13, 13, 15, 15, 6, 13, 5, 14},
+ {6539, 8, 2, 7, 2, 13, 13, 15, 15, 6, 13, 5, 14},
+ {6482, 8, 2, 7, 2, 13, 13, 15, 15, 6, 13, 5, 14},
+ {6427, 7, 2, 7, 3, 14, 13, 15, 15, 6, 13, 5, 14},
+ {6373, 7, 2, 7, 3, 15, 13, 15, 15, 6, 13, 5, 14},
+ {6321, 7, 2, 7, 3, 15, 13, 15, 15, 6, 13, 5, 14},
+ {6270, 7, 2, 7, 3, 15, 13, 15, 15, 6, 13, 5, 14},
+ {6222, 7, 2, 7, 3, 15, 13, 16, 15, 6, 13, 5, 14},
+ {6174, 6, 2, 7, 3, 15, 13, 15, 15, 6, 13, 5, 14},
+ {6128, 6, 2, 7, 3, 15, 13, 15, 15, 6, 13, 5, 14},
+ {6083, 6, 2, 7, 3, 15, 13, 15, 15, 6, 13, 5, 14},
+ {6040, 6, 2, 7, 3, 15, 13, 16, 15, 6, 13, 5, 14},
+ {5997, 6, 2, 7, 3, 15, 13, 16, 15, 6, 13, 5, 14},
+ } };
+
+static const struct SynthLUT SynthLUT_TDD[LUT_FTDD_ENT][SYNTH_LUT_SIZE] = {
+ {
+ {12605, 13, 1, 4, 2, 15, 12, 27, 12, 15, 12, 4, 13}, /* 40 MHz */
+ {12245, 13, 1, 4, 2, 15, 12, 27, 12, 15, 12, 4, 13},
+ {11906, 13, 1, 4, 2, 15, 12, 26, 11, 15, 12, 4, 13},
+ {11588, 13, 1, 4, 2, 15, 12, 28, 12, 15, 12, 4, 13},
+ {11288, 13, 1, 4, 2, 15, 12, 30, 12, 15, 12, 4, 13},
+ {11007, 13, 1, 4, 2, 15, 12, 32, 12, 15, 12, 4, 13},
+ {10742, 13, 1, 4, 2, 15, 12, 33, 12, 15, 12, 4, 13},
+ {10492, 13, 1, 6, 2, 15, 12, 35, 12, 15, 12, 4, 13},
+ {10258, 13, 1, 6, 2, 15, 12, 37, 12, 15, 12, 4, 13},
+ {10036, 13, 1, 6, 2, 15, 12, 38, 12, 15, 12, 4, 13},
+ {9827, 13, 1, 6, 2, 14, 12, 40, 12, 15, 12, 4, 13},
+ {9631, 13, 1, 6, 2, 13, 12, 42, 12, 15, 12, 4, 13},
+ {9445, 13, 1, 6, 2, 12, 12, 44, 12, 15, 12, 4, 13},
+ {9269, 13, 1, 6, 2, 12, 12, 45, 12, 15, 12, 4, 13},
+ {9103, 13, 1, 6, 2, 12, 12, 47, 12, 15, 12, 4, 13},
+ {8946, 13, 1, 6, 2, 12, 12, 49, 12, 15, 12, 4, 13},
+ {8797, 12, 1, 7, 2, 12, 12, 48, 12, 15, 12, 4, 13},
+ {8655, 12, 1, 7, 2, 12, 12, 50, 12, 15, 12, 4, 13},
+ {8520, 12, 1, 7, 2, 12, 12, 51, 12, 15, 12, 4, 13},
+ {8392, 12, 1, 7, 2, 12, 12, 53, 12, 15, 12, 4, 13},
+ {8269, 12, 1, 7, 2, 12, 12, 55, 12, 15, 12, 4, 13},
+ {8153, 12, 1, 7, 2, 12, 12, 56, 12, 15, 12, 4, 13},
+ {8041, 12, 1, 7, 2, 13, 12, 58, 12, 15, 12, 4, 13},
+ {7934, 11, 1, 7, 2, 12, 12, 57, 12, 15, 12, 4, 13},
+ {7831, 11, 1, 7, 2, 12, 12, 58, 12, 15, 12, 4, 13},
+ {7733, 10, 1, 7, 3, 13, 12, 56, 12, 15, 12, 4, 13},
+ {7638, 10, 1, 7, 2, 12, 12, 58, 12, 15, 12, 4, 13},
+ {7547, 10, 1, 7, 2, 12, 12, 59, 12, 15, 12, 4, 13},
+ {7459, 10, 1, 7, 2, 12, 12, 61, 12, 15, 12, 4, 13},
+ {7374, 10, 2, 7, 3, 14, 13, 49, 12, 15, 12, 4, 13},
+ {7291, 10, 2, 7, 3, 14, 13, 50, 12, 15, 12, 4, 13},
+ {7212, 10, 2, 7, 3, 14, 13, 51, 12, 15, 12, 4, 13},
+ {7135, 10, 2, 7, 3, 14, 13, 52, 12, 15, 12, 4, 13},
+ {7061, 10, 2, 7, 3, 14, 13, 53, 12, 15, 12, 4, 13},
+ {6988, 10, 1, 7, 3, 12, 14, 63, 11, 14, 12, 3, 13},
+ {6918, 9, 2, 7, 3, 14, 13, 52, 12, 15, 12, 4, 13},
+ {6850, 9, 2, 7, 3, 14, 13, 53, 12, 15, 12, 4, 13},
+ {6784, 9, 2, 7, 2, 13, 13, 54, 12, 15, 12, 4, 13},
+ {6720, 9, 2, 7, 2, 13, 13, 56, 12, 15, 12, 4, 13},
+ {6658, 8, 2, 7, 3, 14, 13, 53, 12, 15, 12, 4, 13},
+ {6597, 8, 2, 7, 2, 13, 13, 54, 12, 15, 12, 4, 13},
+ {6539, 8, 2, 7, 2, 13, 13, 55, 12, 15, 12, 4, 13},
+ {6482, 8, 2, 7, 2, 13, 13, 56, 12, 15, 12, 4, 13},
+ {6427, 7, 2, 7, 3, 14, 13, 54, 12, 15, 12, 4, 13},
+ {6373, 7, 2, 7, 3, 15, 13, 54, 12, 15, 12, 4, 13},
+ {6321, 7, 2, 7, 3, 15, 13, 55, 12, 15, 12, 4, 13},
+ {6270, 7, 2, 7, 3, 15, 13, 56, 12, 15, 12, 4, 13},
+ {6222, 7, 2, 7, 3, 15, 13, 57, 12, 15, 12, 4, 13},
+ {6174, 6, 2, 7, 3, 15, 13, 54, 12, 15, 12, 4, 13},
+ {6128, 6, 2, 7, 3, 15, 13, 55, 12, 15, 12, 4, 13},
+ {6083, 6, 2, 7, 3, 15, 13, 56, 12, 15, 12, 4, 13},
+ {6040, 6, 2, 7, 3, 15, 13, 57, 12, 15, 12, 4, 13},
+ {5997, 6, 2, 7, 3, 15, 13, 58, 12, 15, 12, 4, 13},
+ }, {
+ {12605, 13, 1, 4, 2, 15, 12, 26, 11, 15, 11, 4, 13}, /* 60 MHz */
+ {12245, 13, 1, 4, 2, 15, 12, 26, 11, 15, 11, 4, 13},
+ {11906, 13, 1, 4, 2, 15, 12, 26, 12, 15, 11, 4, 12},
+ {11588, 13, 1, 4, 2, 15, 12, 30, 12, 15, 11, 4, 12},
+ {11288, 13, 1, 4, 2, 15, 12, 32, 12, 15, 10, 4, 12},
+ {11007, 13, 1, 4, 2, 15, 12, 31, 12, 15, 11, 4, 12},
+ {10742, 13, 1, 4, 2, 15, 12, 33, 12, 15, 10, 4, 12},
+ {10492, 13, 1, 6, 2, 15, 12, 37, 12, 15, 10, 4, 12},
+ {10258, 13, 1, 6, 2, 15, 12, 38, 12, 15, 11, 4, 13},
+ {10036, 13, 1, 6, 2, 15, 12, 38, 12, 15, 10, 4, 12},
+ {9827, 13, 1, 6, 2, 14, 12, 42, 12, 15, 11, 4, 12},
+ {9631, 13, 1, 6, 2, 13, 12, 41, 12, 15, 11, 4, 12},
+ {9445, 13, 1, 6, 2, 12, 12, 45, 12, 15, 11, 4, 12},
+ {9269, 13, 1, 6, 2, 12, 12, 47, 12, 15, 11, 4, 12},
+ {9103, 13, 1, 6, 2, 12, 12, 46, 12, 15, 11, 4, 12},
+ {8946, 13, 1, 6, 2, 12, 12, 48, 12, 15, 10, 4, 12},
+ {8797, 12, 1, 7, 2, 12, 12, 49, 12, 15, 11, 4, 13},
+ {8655, 12, 1, 7, 2, 12, 12, 51, 12, 15, 11, 4, 12},
+ {8520, 12, 1, 7, 2, 12, 12, 50, 12, 15, 11, 4, 12},
+ {8392, 12, 1, 7, 2, 12, 12, 52, 12, 15, 10, 4, 12},
+ {8269, 12, 1, 7, 2, 12, 12, 56, 12, 15, 10, 4, 12},
+ {8153, 12, 1, 7, 2, 12, 12, 55, 12, 15, 11, 4, 12},
+ {8041, 12, 1, 7, 2, 13, 12, 57, 12, 15, 10, 4, 12},
+ {7934, 11, 1, 7, 2, 12, 12, 55, 12, 15, 11, 4, 12},
+ {7831, 11, 1, 7, 2, 12, 12, 57, 12, 15, 10, 4, 12},
+ {7733, 10, 1, 7, 3, 13, 12, 55, 12, 15, 11, 4, 12},
+ {7638, 10, 1, 7, 2, 12, 12, 59, 12, 15, 10, 4, 12},
+ {7547, 10, 1, 7, 2, 12, 12, 60, 12, 15, 11, 4, 12},
+ {7459, 10, 1, 7, 2, 12, 12, 48, 12, 15, 11, 4, 12},
+ {7374, 10, 2, 7, 3, 14, 13, 47, 12, 15, 11, 4, 13},
+ {7291, 10, 2, 7, 3, 14, 13, 49, 12, 15, 10, 4, 12},
+ {7212, 10, 2, 7, 3, 14, 13, 50, 12, 15, 10, 4, 12},
+ {7135, 10, 2, 7, 3, 14, 13, 52, 12, 15, 11, 4, 13},
+ {7061, 10, 2, 7, 3, 14, 13, 52, 12, 15, 11, 4, 12},
+ {6988, 10, 1, 7, 3, 12, 14, 63, 11, 15, 11, 4, 13},
+ {6918, 9, 1, 7, 3, 12, 14, 63, 11, 15, 11, 4, 13},
+ {6850, 9, 1, 7, 3, 12, 14, 63, 11, 15, 11, 4, 13},
+ {6784, 9, 1, 7, 2, 11, 14, 63, 11, 15, 11, 4, 13},
+ {6720, 9, 1, 7, 2, 11, 14, 63, 11, 14, 11, 3, 13},
+ {6658, 8, 1, 7, 3, 12, 14, 63, 11, 15, 11, 4, 13},
+ {6597, 8, 1, 7, 2, 11, 14, 63, 11, 14, 11, 3, 13},
+ {6539, 8, 1, 7, 2, 11, 14, 63, 10, 14, 11, 3, 13},
+ {6482, 8, 1, 7, 2, 11, 14, 63, 10, 14, 11, 3, 13},
+ {6427, 7, 2, 7, 3, 14, 13, 54, 12, 15, 10, 4, 12},
+ {6373, 7, 2, 7, 3, 15, 13, 53, 12, 15, 11, 4, 12},
+ {6321, 7, 2, 7, 3, 15, 13, 54, 12, 15, 11, 4, 12},
+ {6270, 7, 2, 7, 3, 15, 13, 55, 12, 15, 11, 4, 12},
+ {6222, 7, 2, 7, 3, 15, 13, 56, 12, 15, 11, 4, 12},
+ {6174, 6, 2, 7, 3, 15, 13, 53, 12, 15, 11, 4, 12},
+ {6128, 6, 2, 7, 3, 15, 13, 55, 12, 15, 11, 4, 12},
+ {6083, 6, 2, 7, 3, 15, 13, 55, 12, 15, 10, 4, 12},
+ {6040, 6, 2, 7, 3, 15, 13, 56, 12, 15, 10, 4, 12},
+ {5997, 6, 2, 7, 3, 15, 13, 57, 12, 15, 10, 4, 12},
+ }, {
+ {12605, 13, 1, 4, 2, 15, 12, 21, 12, 15, 11, 4, 13}, /* 80 MHz */
+ {12245, 13, 1, 4, 2, 15, 12, 21, 12, 15, 11, 4, 13},
+ {11906, 13, 1, 4, 2, 15, 12, 20, 11, 15, 11, 4, 13},
+ {11588, 13, 1, 4, 2, 15, 12, 22, 12, 15, 11, 4, 12},
+ {11288, 13, 1, 5, 2, 15, 12, 23, 12, 15, 11, 4, 13},
+ {11007, 13, 1, 5, 2, 15, 12, 25, 12, 15, 10, 4, 12},
+ {10742, 13, 1, 5, 2, 15, 12, 26, 12, 15, 11, 4, 13},
+ {10492, 13, 1, 6, 2, 15, 12, 27, 11, 15, 11, 4, 13},
+ {10258, 13, 1, 6, 2, 15, 12, 29, 12, 15, 10, 4, 12},
+ {10036, 13, 1, 6, 2, 15, 12, 30, 12, 15, 11, 4, 12},
+ {9827, 13, 1, 6, 2, 14, 12, 31, 12, 15, 11, 4, 13},
+ {9631, 13, 1, 6, 2, 13, 12, 33, 12, 15, 10, 4, 12},
+ {9445, 13, 1, 6, 2, 12, 12, 34, 12, 15, 11, 4, 12},
+ {9269, 13, 1, 6, 2, 12, 12, 35, 12, 15, 11, 4, 13},
+ {9103, 13, 1, 6, 2, 12, 12, 37, 12, 15, 10, 4, 12},
+ {8946, 13, 1, 6, 2, 12, 12, 38, 12, 15, 11, 4, 12},
+ {8797, 12, 1, 7, 2, 12, 12, 37, 12, 15, 11, 4, 13},
+ {8655, 12, 1, 7, 2, 12, 12, 39, 12, 15, 11, 4, 12},
+ {8520, 12, 1, 7, 2, 12, 12, 40, 12, 15, 11, 4, 12},
+ {8392, 12, 1, 7, 2, 12, 12, 41, 12, 15, 11, 4, 13},
+ {8269, 12, 1, 7, 2, 12, 12, 43, 12, 15, 10, 4, 12},
+ {8153, 12, 1, 7, 2, 12, 12, 44, 12, 15, 11, 4, 12},
+ {8041, 12, 1, 7, 2, 13, 12, 45, 12, 15, 11, 4, 12},
+ {7934, 11, 1, 7, 2, 12, 12, 44, 12, 15, 11, 4, 12},
+ {7831, 11, 1, 7, 2, 12, 12, 45, 12, 15, 11, 4, 13},
+ {7733, 10, 1, 7, 3, 13, 12, 44, 12, 15, 11, 4, 12},
+ {7638, 10, 1, 7, 2, 12, 12, 45, 12, 15, 11, 4, 12},
+ {7547, 10, 1, 7, 2, 12, 12, 46, 12, 15, 11, 4, 12},
+ {7459, 10, 1, 7, 2, 12, 12, 47, 12, 15, 11, 4, 13},
+ {7374, 10, 2, 7, 3, 14, 13, 38, 12, 15, 11, 4, 12},
+ {7291, 10, 2, 7, 3, 14, 13, 39, 12, 15, 10, 4, 12},
+ {7212, 10, 2, 7, 3, 14, 13, 40, 12, 15, 10, 4, 12},
+ {7135, 10, 2, 7, 3, 14, 13, 41, 12, 15, 10, 4, 12},
+ {7061, 10, 2, 7, 3, 14, 13, 41, 12, 15, 11, 4, 13},
+ {6988, 10, 1, 7, 3, 12, 14, 54, 12, 15, 11, 4, 12},
+ {6918, 9, 2, 7, 3, 14, 13, 41, 12, 15, 10, 4, 12},
+ {6850, 9, 2, 7, 3, 14, 13, 42, 12, 15, 10, 4, 12},
+ {6784, 9, 2, 7, 2, 13, 13, 42, 12, 15, 11, 4, 13},
+ {6720, 9, 2, 7, 2, 13, 13, 43, 12, 15, 11, 4, 13},
+ {6658, 8, 2, 7, 3, 14, 13, 41, 12, 15, 11, 4, 13},
+ {6597, 8, 2, 7, 2, 13, 13, 42, 12, 15, 11, 4, 12},
+ {6539, 8, 2, 7, 2, 13, 13, 43, 12, 15, 11, 4, 12},
+ {6482, 8, 2, 7, 2, 13, 13, 44, 12, 15, 11, 4, 12},
+ {6427, 7, 2, 7, 3, 14, 13, 42, 12, 15, 10, 4, 12},
+ {6373, 7, 2, 7, 3, 15, 13, 42, 12, 15, 11, 4, 13},
+ {6321, 7, 2, 7, 3, 15, 13, 43, 12, 15, 11, 4, 12},
+ {6270, 7, 2, 7, 3, 15, 13, 44, 12, 15, 11, 4, 12},
+ {6222, 7, 2, 7, 3, 15, 13, 45, 12, 15, 10, 4, 12},
+ {6174, 6, 2, 7, 3, 15, 13, 42, 12, 15, 11, 4, 13},
+ {6128, 6, 2, 7, 3, 15, 13, 43, 12, 15, 11, 4, 12},
+ {6083, 6, 2, 7, 3, 15, 13, 44, 12, 15, 10, 4, 12},
+ {6040, 6, 2, 7, 3, 15, 13, 44, 12, 15, 11, 4, 13},
+ {5997, 6, 2, 7, 3, 15, 13, 45, 12, 15, 11, 4, 12},
+ } };
+
+/* Rx Gain Tables */
+
+#define SIZE_FULL_TABLE 77
+
+static const uint8_t full_gain_table[RXGAIN_TBLS_END][SIZE_FULL_TABLE][3] =
+{ { /* 800 MHz */
+ { 0x00, 0x00, 0x20 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 },
+ { 0x00, 0x01, 0x00 }, { 0x00, 0x02, 0x00 }, { 0x00, 0x03, 0x00 },
+ { 0x00, 0x04, 0x00 }, { 0x00, 0x05, 0x00 }, { 0x01, 0x03, 0x20 },
+ { 0x01, 0x04, 0x00 }, { 0x01, 0x05, 0x00 }, { 0x01, 0x06, 0x00 },
+ { 0x01, 0x07, 0x00 }, { 0x01, 0x08, 0x00 }, { 0x01, 0x09, 0x00 },
+ { 0x01, 0x0A, 0x00 }, { 0x01, 0x0B, 0x00 }, { 0x01, 0x0C, 0x00 },
+ { 0x01, 0x0D, 0x00 }, { 0x01, 0x0E, 0x00 }, { 0x02, 0x09, 0x20 },
+ { 0x02, 0x0A, 0x00 }, { 0x02, 0x0B, 0x00 }, { 0x02, 0x0C, 0x00 },
+ { 0x02, 0x0D, 0x00 }, { 0x02, 0x0E, 0x00 }, { 0x02, 0x0F, 0x00 },
+ { 0x02, 0x10, 0x00 }, { 0x02, 0x2B, 0x20 }, { 0x02, 0x2C, 0x00 },
+ { 0x04, 0x28, 0x20 }, { 0x04, 0x29, 0x00 }, { 0x04, 0x2A, 0x00 },
+ { 0x04, 0x2B, 0x00 }, { 0x24, 0x20, 0x20 }, { 0x24, 0x21, 0x00 },
+ { 0x44, 0x20, 0x20 }, { 0x44, 0x21, 0x00 }, { 0x44, 0x22, 0x00 },
+ { 0x44, 0x23, 0x00 }, { 0x44, 0x24, 0x00 }, { 0x44, 0x25, 0x00 },
+ { 0x44, 0x26, 0x00 }, { 0x44, 0x27, 0x00 }, { 0x44, 0x28, 0x00 },
+ { 0x44, 0x29, 0x00 }, { 0x44, 0x2A, 0x00 }, { 0x44, 0x2B, 0x00 },
+ { 0x44, 0x2C, 0x00 }, { 0x44, 0x2D, 0x00 }, { 0x44, 0x2E, 0x00 },
+ { 0x44, 0x2F, 0x00 }, { 0x44, 0x30, 0x00 }, { 0x44, 0x31, 0x00 },
+ { 0x44, 0x32, 0x00 }, { 0x64, 0x2E, 0x20 }, { 0x64, 0x2F, 0x00 },
+ { 0x64, 0x30, 0x00 }, { 0x64, 0x31, 0x00 }, { 0x64, 0x32, 0x00 },
+ { 0x64, 0x33, 0x00 }, { 0x64, 0x34, 0x00 }, { 0x64, 0x35, 0x00 },
+ { 0x64, 0x36, 0x00 }, { 0x64, 0x37, 0x00 }, { 0x64, 0x38, 0x00 },
+ { 0x65, 0x38, 0x20 }, { 0x66, 0x38, 0x20 }, { 0x67, 0x38, 0x20 },
+ { 0x68, 0x38, 0x20 }, { 0x69, 0x38, 0x20 }, { 0x6A, 0x38, 0x20 },
+ { 0x6B, 0x38, 0x20 }, { 0x6C, 0x38, 0x20 }, { 0x6D, 0x38, 0x20 },
+ { 0x6E, 0x38, 0x20 }, { 0x6F, 0x38, 0x20 }
+}, { /* 2300 MHz */
+ { 0x00, 0x00, 0x20 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 },
+ { 0x00, 0x01, 0x00 }, { 0x00, 0x02, 0x00 }, { 0x00, 0x03, 0x00 },
+ { 0x00, 0x04, 0x00 }, { 0x00, 0x05, 0x00 }, { 0x01, 0x03, 0x20 },
+ { 0x01, 0x04, 0x00 }, { 0x01, 0x05, 0x00 }, { 0x01, 0x06, 0x00 },
+ { 0x01, 0x07, 0x00 }, { 0x01, 0x08, 0x00 }, { 0x01, 0x09, 0x00 },
+ { 0x01, 0x0A, 0x00 }, { 0x01, 0x0B, 0x00 }, { 0x01, 0x0C, 0x00 },
+ { 0x01, 0x0D, 0x00 }, { 0x01, 0x0E, 0x00 }, { 0x02, 0x09, 0x20 },
+ { 0x02, 0x0A, 0x00 }, { 0x02, 0x0B, 0x00 }, { 0x02, 0x0C, 0x00 },
+ { 0x02, 0x0D, 0x00 }, { 0x02, 0x0E, 0x00 }, { 0x02, 0x0F, 0x00 },
+ { 0x02, 0x10, 0x00 }, { 0x02, 0x2B, 0x20 }, { 0x02, 0x2C, 0x00 },
+ { 0x04, 0x27, 0x20 }, { 0x04, 0x28, 0x00 }, { 0x04, 0x29, 0x00 },
+ { 0x04, 0x2A, 0x00 }, { 0x04, 0x2B, 0x00 }, { 0x24, 0x21, 0x20 },
+ { 0x24, 0x22, 0x00 }, { 0x44, 0x20, 0x20 }, { 0x44, 0x21, 0x00 },
+ { 0x44, 0x22, 0x00 }, { 0x44, 0x23, 0x00 }, { 0x44, 0x24, 0x00 },
+ { 0x44, 0x25, 0x00 }, { 0x44, 0x26, 0x00 }, { 0x44, 0x27, 0x00 },
+ { 0x44, 0x28, 0x00 }, { 0x44, 0x29, 0x00 }, { 0x44, 0x2A, 0x00 },
+ { 0x44, 0x2B, 0x00 }, { 0x44, 0x2C, 0x00 }, { 0x44, 0x2D, 0x00 },
+ { 0x44, 0x2E, 0x00 }, { 0x44, 0x2F, 0x00 }, { 0x44, 0x30, 0x00 },
+ { 0x44, 0x31, 0x00 }, { 0x64, 0x2E, 0x20 }, { 0x64, 0x2F, 0x00 },
+ { 0x64, 0x30, 0x00 }, { 0x64, 0x31, 0x00 }, { 0x64, 0x32, 0x00 },
+ { 0x64, 0x33, 0x00 }, { 0x64, 0x34, 0x00 }, { 0x64, 0x35, 0x00 },
+ { 0x64, 0x36, 0x00 }, { 0x64, 0x37, 0x00 }, { 0x64, 0x38, 0x00 },
+ { 0x65, 0x38, 0x20 }, { 0x66, 0x38, 0x20 }, { 0x67, 0x38, 0x20 },
+ { 0x68, 0x38, 0x20 }, { 0x69, 0x38, 0x20 }, { 0x6A, 0x38, 0x20 },
+ { 0x6B, 0x38, 0x20 }, { 0x6C, 0x38, 0x20 }, { 0x6D, 0x38, 0x20 },
+ { 0x6E, 0x38, 0x20 }, { 0x6F, 0x38, 0x20 },
+}, { /* 5500 MHz */
+ { 0x00, 0x00, 0x20 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x01, 0x00 },
+ { 0x00, 0x02, 0x00 }, { 0x00, 0x03, 0x00 }, { 0x01, 0x01, 0x20 },
+ { 0x01, 0x02, 0x00 }, { 0x01, 0x03, 0x00 }, { 0x01, 0x04, 0x20 },
+ { 0x01, 0x05, 0x00 }, { 0x01, 0x06, 0x00 }, { 0x01, 0x07, 0x00 },
+ { 0x01, 0x08, 0x00 }, { 0x01, 0x09, 0x00 }, { 0x01, 0x0A, 0x00 },
+ { 0x01, 0x0B, 0x00 }, { 0x01, 0x0C, 0x00 }, { 0x02, 0x08, 0x20 },
+ { 0x02, 0x09, 0x00 }, { 0x02, 0x0A, 0x00 }, { 0x02, 0x0B, 0x20 },
+ { 0x02, 0x0C, 0x00 }, { 0x02, 0x0D, 0x00 }, { 0x02, 0x0E, 0x00 },
+ { 0x02, 0x0F, 0x00 }, { 0x02, 0x2A, 0x20 }, { 0x02, 0x2B, 0x00 },
+ { 0x04, 0x27, 0x20 }, { 0x04, 0x28, 0x00 }, { 0x04, 0x29, 0x00 },
+ { 0x04, 0x2A, 0x00 }, { 0x04, 0x2B, 0x00 }, { 0x04, 0x2C, 0x00 },
+ { 0x04, 0x2D, 0x00 }, { 0x24, 0x20, 0x20 }, { 0x24, 0x21, 0x00 },
+ { 0x24, 0x22, 0x00 }, { 0x44, 0x20, 0x20 }, { 0x44, 0x21, 0x00 },
+ { 0x44, 0x22, 0x00 }, { 0x44, 0x23, 0x00 }, { 0x44, 0x24, 0x00 },
+ { 0x44, 0x25, 0x00 }, { 0x44, 0x26, 0x00 }, { 0x44, 0x27, 0x00 },
+ { 0x44, 0x28, 0x00 }, { 0x44, 0x29, 0x00 }, { 0x44, 0x2A, 0x00 },
+ { 0x44, 0x2B, 0x00 }, { 0x44, 0x2C, 0x00 }, { 0x44, 0x2D, 0x00 },
+ { 0x44, 0x2E, 0x00 }, { 0x64, 0x2E, 0x20 }, { 0x64, 0x2F, 0x00 },
+ { 0x64, 0x30, 0x00 }, { 0x64, 0x31, 0x00 }, { 0x64, 0x32, 0x00 },
+ { 0x64, 0x33, 0x00 }, { 0x64, 0x34, 0x00 }, { 0x64, 0x35, 0x00 },
+ { 0x64, 0x36, 0x00 }, { 0x64, 0x37, 0x00 }, { 0x64, 0x38, 0x00 },
+ { 0x65, 0x38, 0x20 }, { 0x66, 0x38, 0x20 }, { 0x67, 0x38, 0x20 },
+ { 0x68, 0x38, 0x20 }, { 0x69, 0x38, 0x20 }, { 0x6A, 0x38, 0x20 },
+ { 0x6B, 0x38, 0x20 }, { 0x6C, 0x38, 0x20 }, { 0x6D, 0x38, 0x20 },
+ { 0x6E, 0x38, 0x20 }, { 0x6F, 0x38, 0x20 }
+} };
+
+#define SIZE_SPLIT_TABLE 41
+
+static const uint8_t split_gain_table[RXGAIN_TBLS_END][SIZE_SPLIT_TABLE][3] =
+{ { /* 800 MHz */
+ { 0x00, 0x18, 0x20 }, { 0x00, 0x18, 0x00 }, { 0x00, 0x18, 0x00 },
+ { 0x00, 0x18, 0x00 }, { 0x00, 0x18, 0x00 }, { 0x00, 0x18, 0x00 },
+ { 0x00, 0x18, 0x20 }, { 0x01, 0x18, 0x20 }, { 0x02, 0x18, 0x20 },
+ { 0x04, 0x18, 0x20 }, { 0x04, 0x38, 0x20 }, { 0x05, 0x38, 0x20 },
+ { 0x06, 0x38, 0x20 }, { 0x07, 0x38, 0x20 }, { 0x08, 0x38, 0x20 },
+ { 0x09, 0x38, 0x20 }, { 0x0A, 0x38, 0x20 }, { 0x0B, 0x38, 0x20 },
+ { 0x0C, 0x38, 0x20 }, { 0x0D, 0x38, 0x20 }, { 0x0E, 0x38, 0x20 },
+ { 0x0F, 0x38, 0x20 }, { 0x24, 0x38, 0x20 }, { 0x25, 0x38, 0x20 },
+ { 0x44, 0x38, 0x20 }, { 0x45, 0x38, 0x20 }, { 0x46, 0x38, 0x20 },
+ { 0x47, 0x38, 0x20 }, { 0x48, 0x38, 0x20 }, { 0x64, 0x38, 0x20 },
+ { 0x65, 0x38, 0x20 }, { 0x66, 0x38, 0x20 }, { 0x67, 0x38, 0x20 },
+ { 0x68, 0x38, 0x20 }, { 0x69, 0x38, 0x20 }, { 0x6A, 0x38, 0x20 },
+ { 0x6B, 0x38, 0x20 }, { 0x6C, 0x38, 0x20 }, { 0x6D, 0x38, 0x20 },
+ { 0x6E, 0x38, 0x20 }, { 0x6F, 0x38, 0x20 },
+}, { /* 2300 MHz */
+ { 0x00, 0x18, 0x20 }, { 0x00, 0x18, 0x00 }, { 0x00, 0x18, 0x00 },
+ { 0x00, 0x18, 0x00 }, { 0x00, 0x18, 0x00 }, { 0x00, 0x18, 0x00 },
+ { 0x00, 0x18, 0x00 }, { 0x00, 0x18, 0x20 }, { 0x01, 0x18, 0x20 },
+ { 0x02, 0x18, 0x20 }, { 0x04, 0x18, 0x20 }, { 0x04, 0x38, 0x20 },
+ { 0x05, 0x38, 0x20 }, { 0x06, 0x38, 0x20 }, { 0x07, 0x38, 0x20 },
+ { 0x08, 0x38, 0x20 }, { 0x09, 0x38, 0x20 }, { 0x0A, 0x38, 0x20 },
+ { 0x0B, 0x38, 0x20 }, { 0x0C, 0x38, 0x20 }, { 0x0D, 0x38, 0x20 },
+ { 0x0E, 0x38, 0x20 }, { 0x0F, 0x38, 0x20 }, { 0x25, 0x38, 0x20 },
+ { 0x26, 0x38, 0x20 }, { 0x44, 0x38, 0x20 }, { 0x45, 0x38, 0x20 },
+ { 0x46, 0x38, 0x20 }, { 0x47, 0x38, 0x20 }, { 0x64, 0x38, 0x20 },
+ { 0x65, 0x38, 0x20 }, { 0x66, 0x38, 0x20 }, { 0x67, 0x38, 0x20 },
+ { 0x68, 0x38, 0x20 }, { 0x69, 0x38, 0x20 }, { 0x6A, 0x38, 0x20 },
+ { 0x6B, 0x38, 0x20 }, { 0x6C, 0x38, 0x20 }, { 0x6D, 0x38, 0x20 },
+ { 0x6E, 0x38, 0x20 }, { 0x6F, 0x38, 0x20 },
+}, { /* 5500 MHz */
+ { 0x00, 0x18, 0x20 }, { 0x00, 0x18, 0x00 }, { 0x00, 0x18, 0x00 },
+ { 0x00, 0x18, 0x00 }, { 0x00, 0x18, 0x00 }, { 0x00, 0x18, 0x00 },
+ { 0x00, 0x18, 0x00 }, { 0x00, 0x18, 0x00 }, { 0x00, 0x18, 0x00 },
+ { 0x00, 0x18, 0x00 }, { 0x01, 0x18, 0x20 }, { 0x02, 0x18, 0x20 },
+ { 0x04, 0x18, 0x20 }, { 0x04, 0x38, 0x20 }, { 0x05, 0x38, 0x20 },
+ { 0x06, 0x38, 0x20 }, { 0x07, 0x38, 0x20 }, { 0x08, 0x38, 0x20 },
+ { 0x09, 0x38, 0x20 }, { 0x0A, 0x38, 0x20 }, { 0x0B, 0x38, 0x20 },
+ { 0x0C, 0x38, 0x20 }, { 0x0D, 0x38, 0x20 }, { 0x0E, 0x38, 0x20 },
+ { 0x0F, 0x38, 0x20 }, { 0x62, 0x38, 0x20 }, { 0x25, 0x38, 0x20 },
+ { 0x26, 0x38, 0x20 }, { 0x44, 0x38, 0x20 }, { 0x64, 0x38, 0x20 },
+ { 0x65, 0x38, 0x20 }, { 0x66, 0x38, 0x20 }, { 0x67, 0x38, 0x20 },
+ { 0x68, 0x38, 0x20 }, { 0x69, 0x38, 0x20 }, { 0x6A, 0x38, 0x20 },
+ { 0x6B, 0x38, 0x20 }, { 0x6C, 0x38, 0x20 }, { 0x6D, 0x38, 0x20 },
+ { 0x6E, 0x38, 0x20 }, { 0x6F, 0x38, 0x20 },
+} };
+
+/* Mixer GM Sub-table */
+
+static const uint8_t gm_st_gain[16] = { 0x78, 0x74, 0x70, 0x6C, 0x68, 0x64, 0x60,
+0x5C, 0x58, 0x54, 0x50, 0x4C, 0x48, 0x30, 0x18, 0x0 };
+static const uint8_t gm_st_ctrl[16] = { 0x0, 0xD, 0x15, 0x1B, 0x21, 0x25, 0x29,
+0x2C, 0x2F, 0x31, 0x33, 0x34, 0x35, 0x3A, 0x3D, 0x3E };
+
+static const int8_t lna_table[RXGAIN_TBLS_END][4] = {
+ {5, 17, 19, 24}, {3, 14, 17, 21}, {-4, 10, 13, 14}};
+static const int8_t tia_table[] = { -6, 0 };
+static const int8_t mixer_table[RXGAIN_TBLS_END][16] = {
+ {0, 3, 9, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},
+ {0, 3, 9, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26},
+ {0, 3, 8, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}};
+
+static const uint32_t gain_step_calib_reg_val[4][5] = {
+ {0xC0, 0x2E, 0x10, 0x06, 0x00}, // LO Frequency Range: 600 to 1300 MHz
+ {0xC0, 0x2C, 0x10, 0x06, 0x00}, // LO Frequency Range: 1300 to 3300 MHz
+ {0xB8, 0x2C, 0x10, 0x06, 0x00}, // LO Frequency Range: 2700 to 4100 MHz
+ {0xA0, 0x24, 0x10, 0x06, 0x00}, // LO Frequency Range: 4000 to 6000 MHz
+};
+
+/******************************************************************************/
+/********************** Macros and Constants Definitions **********************/
+/******************************************************************************/
+const char *ad9361_ensm_states[] = {
+ "sleep", "", "", "", "", "alert", "tx", "tx flush",
+ "rx", "rx_flush", "fdd", "fdd_flush"
+};
+
+/**
+ * SPI multiple bytes register read.
+ * @param spi
+ * @param reg The register address.
+ * @param rbuf The data buffer.
+ * @param num The number of bytes to read.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_spi_readm(struct spi_device *spi, uint32_t reg,
+ uint8_t *rbuf, uint32_t num)
+{
+ uint8_t buf[2];
+ int32_t ret;
+ uint16_t cmd;
+
+ if (num > MAX_MBYTE_SPI)
+ return -EINVAL;
+
+ cmd = AD_READ | AD_CNT(num) | AD_ADDR(reg);
+ buf[0] = cmd >> 8;
+ buf[1] = cmd & 0xFF;
+
+#ifdef NUAND_MODIFICATIONS
+ // no-op to clear warning
+ buf[0] = buf[1];
+
+ // use alternate spi_read
+ ret = spi_read(spi, cmd, rbuf, num);
+#else
+ ret = spi_write_then_read(spi, &buf[0], 2, rbuf, num);
+#endif // NUAND_MODIFICATIONS
+ if (ret < 0) {
+ dev_err(&spi->dev, "Read Error %"PRId32, ret);
+ return ret;
+ }
+#ifdef _DEBUG
+ {
+ int32_t i;
+ for (i = 0; i < num; i++)
+ dev_dbg(&spi->dev, "%s: reg 0x%"PRIX32" val 0x%X",
+ __func__, reg--, rbuf[i]);
+ }
+#endif
+
+ return 0;
+}
+
+/**
+ * SPI register read.
+ * @param spi
+ * @param reg The register address.
+ * @return The register value or negative error code in case of failure.
+ */
+int32_t ad9361_spi_read(struct spi_device *spi, uint32_t reg)
+{
+ uint8_t buf;
+ int32_t ret;
+
+ ret = ad9361_spi_readm(spi, reg, &buf, 1);
+ if (ret < 0)
+ return ret;
+
+ return buf;
+}
+
+/**
+ * SPI register bits read.
+ * @param spi
+ * @param reg The register address.
+ * @param mask The bits mask.
+ * @param offset The mask offset.
+ * @return The bits value or negative error code in case of failure.
+ */
+static int32_t __ad9361_spi_readf(struct spi_device *spi, uint32_t reg,
+ uint32_t mask, uint32_t offset)
+{
+ uint8_t buf;
+ int32_t ret;
+
+ if (!mask)
+ return -EINVAL;
+
+ ret = ad9361_spi_readm(spi, reg, &buf, 1);
+ if (ret < 0)
+ return ret;
+
+ buf &= mask;
+ buf >>= offset;
+
+ return buf;
+}
+
+/**
+ * SPI register bits read.
+ * @param spi
+ * @param reg The register address.
+ * @param mask The bits mask.
+ * @return The bits value or negative error code in case of failure.
+ */
+#define ad9361_spi_readf(spi, reg, mask) \
+ __ad9361_spi_readf(spi, reg, mask, find_first_bit(mask))
+
+/**
+ * SPI register write.
+ * @param spi
+ * @param reg The register address.
+ * @param val The value of the register.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_spi_write(struct spi_device *spi,
+ uint32_t reg, uint32_t val)
+{
+ uint8_t buf[3];
+ int32_t ret;
+ uint16_t cmd;
+
+ cmd = AD_WRITE | AD_CNT(1) | AD_ADDR(reg);
+ buf[0] = cmd >> 8;
+ buf[1] = cmd & 0xFF;
+ buf[2] = val;
+
+#ifdef NUAND_MODIFICATIONS
+ // use alternate spi_write
+ ret = spi_write(spi, cmd, &(buf[2]), 1);
+#else
+ ret = spi_write_then_read(spi, buf, 3, NULL, 0);
+#endif // NUAND_MODIFICATIONS
+
+ if (ret < 0) {
+ dev_err(&spi->dev, "Write Error %"PRId32, ret);
+ return ret;
+ }
+
+#ifdef _DEBUG
+ dev_dbg(&spi->dev, "%s: reg 0x%"PRIX32" val 0x%X", __func__, reg, buf[2]);
+#endif
+
+ return 0;
+}
+
+/**
+ * SPI register bits write.
+ * @param spi
+ * @param reg The register address.
+ * @param mask The bits mask.
+ * @param offset The mask offset.
+ * @param val The bits value.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t __ad9361_spi_writef(struct spi_device *spi, uint32_t reg,
+ uint32_t mask, uint32_t offset, uint32_t val)
+{
+ uint8_t buf;
+ int32_t ret;
+
+ if (!mask)
+ return -EINVAL;
+
+ ret = ad9361_spi_readm(spi, reg, &buf, 1);
+ if (ret < 0)
+ return ret;
+
+ buf &= ~mask;
+ buf |= ((val << offset) & mask);
+
+ return ad9361_spi_write(spi, reg, buf);
+}
+
+/**
+ * SPI register bits write.
+ * @param spi
+ * @param reg The register address.
+ * @param mask The bits mask.
+ * @param val The bits value.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+#define ad9361_spi_writef(spi, reg, mask, val) \
+ __ad9361_spi_writef(spi, reg, mask, find_first_bit(mask), val)
+
+/**
+ * SPI multiple bytes register write.
+ * @param spi
+ * @param reg The register address.
+ * @param tbuf The data buffer.
+ * @param num The number of bytes to read.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_spi_writem(struct spi_device *spi,
+ uint32_t reg, uint8_t *tbuf, uint32_t num)
+{
+ uint8_t buf[10];
+ int32_t ret;
+ uint16_t cmd;
+
+ if (num > MAX_MBYTE_SPI)
+ return -EINVAL;
+
+ cmd = AD_WRITE | AD_CNT(num) | AD_ADDR(reg);
+ buf[0] = cmd >> 8;
+ buf[1] = cmd & 0xFF;
+
+#ifndef ALTERA_PLATFORM
+ memcpy(&buf[2], tbuf, num);
+#else
+ int32_t i;
+ for (i = 0; i < num; i++)
+ buf[2 + i] = tbuf[i];
+#endif
+
+#ifdef NUAND_MODIFICATIONS
+ // no-op to clear warning
+ buf[0] = buf[1];
+
+ // use alternate spi_write
+ ret = spi_write(spi, cmd, tbuf, num);
+#else
+ ret = spi_write_then_read(spi, buf, num + 2, NULL, 0);
+#endif // NUAND_MODIFICATIONS
+
+ if (ret < 0) {
+ dev_err(&spi->dev, "Write Error %"PRId32, ret);
+ return ret;
+ }
+
+#ifdef _DEBUG
+ {
+ int32_t i;
+ for (i = 0; i < num; i++)
+ dev_dbg(&spi->dev, "Reg 0x%"PRIX32" val 0x%X", reg--, tbuf[i]);
+ }
+#endif
+
+ return 0;
+}
+
+/**
+ * Validate RF BW frequency.
+ * @param phy The AD9361 state structure.
+ * @param bw The RF BW frequency.
+ * @return The validated RF BW frequency.
+ */
+uint32_t ad9361_validate_rf_bw(struct ad9361_rf_phy *phy, uint32_t bw)
+{
+ switch (phy->dev_sel) {
+ case ID_AD9363A:
+ return clamp_t(uint32_t, bw, 0, 20000000UL);
+ default:
+ return clamp_t(uint32_t, bw, 0, 56000000UL);
+ }
+}
+
+/**
+ * Validate RF PLL frequency.
+ * @param phy The AD9361 state structure.
+ * @param freq The RF PLL frequency.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_validate_rfpll(struct ad9361_rf_phy *phy, uint64_t freq)
+{
+ switch (phy->dev_sel) {
+ case ID_AD9363A:
+ if (freq > AD9363A_MAX_CARRIER_FREQ_HZ ||
+ freq < AD9363A_MIN_CARRIER_FREQ_HZ)
+ return -EINVAL;
+ break;
+ default:
+ if (freq > MAX_CARRIER_FREQ_HZ || freq < MIN_CARRIER_FREQ_HZ)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * Find optimal value.
+ * @param field
+ * @param ret_start
+ * @return The optimal delay in case of success, negative error code otherwise.
+ */
+int32_t ad9361_find_opt(uint8_t *field, uint32_t size, uint32_t *ret_start)
+{
+ int32_t i, cnt = 0, max_cnt = 0, start, max_start = 0;
+
+#ifdef NUAND_MODIFICATIONS
+ // add check for failed optimal value search
+ bool found_0 = false;
+ bool found_1 = false;
+#endif // NUAND_MODIFICATIONS
+
+ for(i = 0, start = -1; i < (int64_t)size; i++) {
+ if (field[i] == 0) {
+ if (start == -1)
+ start = i;
+ cnt++;
+
+#ifdef NUAND_MODIFICATIONS
+ found_0 = true;
+#endif // NUAND_MODIFICATIONS
+
+ } else {
+ if (cnt > max_cnt) {
+ max_cnt = cnt;
+ max_start = start;
+ }
+ start = -1;
+ cnt = 0;
+
+#ifdef NUAND_MODIFICATIONS
+ found_1 = true;
+#endif // NUAND_MODIFICATIONS
+
+ }
+ }
+
+ if (cnt > max_cnt) {
+ max_cnt = cnt;
+ max_start = start;
+ }
+
+ *ret_start = max_start;
+
+#ifdef NUAND_MODIFICATIONS
+ if (!found_0 || !found_1) {
+ // All of the values were the same. This is not a healthy result.
+ return -1;
+ }
+#endif // NUAND_MODIFICATIONS
+
+ return max_cnt;
+}
+
+/**
+ * Select the channel mapping in 1rx1tx mode.
+ * @param phy The AD9361 state structure.
+ * @param map Map
+ * @param channel Channel
+ * @return The channel number.
+ */
+int32_t ad9361_1rx1tx_channel_map(struct ad9361_rf_phy *phy, bool tx, int32_t channel)
+{
+ uint32_t map;
+
+ if (phy->pdata->rx2tx2)
+ return channel;
+
+ if (tx)
+ map = phy->pdata->rx1tx1_mode_use_tx_num;
+ else
+ map = phy->pdata->rx1tx1_mode_use_rx_num;
+
+ if (map == 2)
+ return channel + 1;
+
+ return channel;
+}
+
+/**
+ * AD9361 Device Reset
+ * @param phy The AD9361 state structure.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_reset(struct ad9361_rf_phy *phy)
+{
+#ifdef NUAND_MODIFICATIONS
+ // use alternate gpio accessors
+ if (gpio_is_valid(phy->gpio, phy->pdata->gpio_resetb)) {
+ gpio_set_value(phy->gpio, phy->pdata->gpio_resetb, 0);
+ mdelay(1);
+ gpio_set_value(phy->gpio, phy->pdata->gpio_resetb, 1);
+ mdelay(1);
+ dev_dbg(&phy->spi->dev, "%s: by GPIO", __func__);
+ return 0;
+ }
+#else
+ if (gpio_is_valid(phy->pdata->gpio_resetb)) {
+ gpio_set_value(phy->pdata->gpio_resetb, 0);
+ mdelay(1);
+ gpio_set_value(phy->pdata->gpio_resetb, 1);
+ mdelay(1);
+ dev_dbg(&phy->spi->dev, "%s: by GPIO", __func__);
+ return 0;
+ }
+#endif // NUAND_MODIFICATIONS
+
+ /* SPI Soft Reset was removed from the register map, since it doesn't
+ * work reliably. Without a prober HW reset randomness may happen.
+ * Please specify a RESET GPIO.
+ */
+
+ ad9361_spi_write(phy->spi, REG_SPI_CONF, SOFT_RESET | _SOFT_RESET);
+ ad9361_spi_write(phy->spi, REG_SPI_CONF, 0x0);
+ dev_err(&phy->spi->dev,
+ "%s: by SPI, this may cause unpredicted behavior!", __func__);
+
+ return -ENODEV;
+}
+
+/**
+ * Enable/disable the desired TX channel.
+ * @param phy The AD9361 state structure.
+ * @param tx_if The desired channel number [1, 2].
+ * @param enable Enable/disable option.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_en_dis_tx(struct ad9361_rf_phy *phy, uint32_t tx_if, uint32_t enable)
+{
+ if ((tx_if & enable) > 1 && AD9364_DEVICE && enable)
+ return -EINVAL;
+
+ return ad9361_spi_writef(phy->spi, REG_TX_ENABLE_FILTER_CTRL,
+ TX_CHANNEL_ENABLE(tx_if), enable);
+}
+
+/**
+ * Enable/disable the desired RX channel.
+ * @param phy The AD9361 state structure.
+ * @param tx_if The desired channel number [1, 2].
+ * @param enable Enable/disable option.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_en_dis_rx(struct ad9361_rf_phy *phy, uint32_t rx_if, uint32_t enable)
+{
+ if ((rx_if & enable) > 1 && AD9364_DEVICE && enable)
+ return -EINVAL;
+
+ return ad9361_spi_writef(phy->spi, REG_RX_ENABLE_FILTER_CTRL,
+ RX_CHANNEL_ENABLE(rx_if), enable);
+}
+
+/**
+ * Loopback works only TX1->RX1 or RX2->RX2.
+ * @param phy The AD9361 state structure.
+ * @param enable Enable.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_int_loopback_fix_ch_cross(struct ad9361_rf_phy *phy, bool enable)
+{
+ /* Loopback works only TX1->RX1 or RX2->RX2 */
+ if (!phy->pdata->rx2tx2 && phy->pdata->rx1tx1_mode_use_rx_num !=
+ phy->pdata->rx1tx1_mode_use_tx_num)
+ return ad9361_en_dis_tx(phy, TX_1 | TX_2,
+ enable ? phy->pdata->rx1tx1_mode_use_rx_num :
+ phy->pdata->rx1tx1_mode_use_tx_num);
+
+ return 0;
+}
+
+/**
+ * BIST loopback mode.
+ * @param phy The AD9361 state structure.
+ * @param mode BIST loopback mode.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_bist_loopback(struct ad9361_rf_phy *phy, int32_t mode)
+{
+ uint32_t sp_hd, reg;
+
+ dev_dbg(&phy->spi->dev, "%s: mode %"PRId32, __func__, mode);
+
+ reg = ad9361_spi_read(phy->spi, REG_OBSERVE_CONFIG);
+
+ phy->bist_loopback_mode = mode;
+
+ switch (mode) {
+ case 0:
+ ad9361_hdl_loopback(phy, false);
+ ad9361_int_loopback_fix_ch_cross(phy, false);
+ reg &= ~(DATA_PORT_SP_HD_LOOP_TEST_OE |
+ DATA_PORT_LOOP_TEST_ENABLE);
+ return ad9361_spi_write(phy->spi, REG_OBSERVE_CONFIG, reg);
+ case 1:
+ /* loopback (AD9361 internal) TX->RX */
+ ad9361_hdl_loopback(phy, false);
+ ad9361_int_loopback_fix_ch_cross(phy, true);
+ sp_hd = ad9361_spi_read(phy->spi, REG_PARALLEL_PORT_CONF_3);
+ if ((sp_hd & SINGLE_PORT_MODE) && (sp_hd & HALF_DUPLEX_MODE))
+ reg |= DATA_PORT_SP_HD_LOOP_TEST_OE;
+ else
+ reg &= ~DATA_PORT_SP_HD_LOOP_TEST_OE;
+
+ reg |= DATA_PORT_LOOP_TEST_ENABLE;
+
+ return ad9361_spi_write(phy->spi, REG_OBSERVE_CONFIG, reg);
+ case 2:
+ /* loopback (FPGA internal) RX->TX */
+ ad9361_hdl_loopback(phy, true);
+ ad9361_int_loopback_fix_ch_cross(phy, false);
+ reg &= ~(DATA_PORT_SP_HD_LOOP_TEST_OE |
+ DATA_PORT_LOOP_TEST_ENABLE);
+ return ad9361_spi_write(phy->spi, REG_OBSERVE_CONFIG, reg);
+ default:
+ return -EINVAL;
+ }
+}
+
+/**
+ * Get BIST loopback mode.
+ * @param phy The AD9361 state structure.
+ * @param mode BIST loopback mode.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+void ad9361_get_bist_loopback(struct ad9361_rf_phy *phy, int32_t *mode)
+{
+ *mode = phy->bist_loopback_mode;
+}
+
+/**
+ * BIST mode.
+ * @param phy The AD9361 state structure.
+ * @param mode Bist mode.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_bist_prbs(struct ad9361_rf_phy *phy, enum ad9361_bist_mode mode)
+{
+ uint32_t reg = 0;
+
+ dev_dbg(&phy->spi->dev, "%s: mode %d", __func__, mode);
+
+ phy->bist_prbs_mode = mode;
+
+ switch (mode) {
+ case BIST_DISABLE:
+ reg = 0;
+ break;
+ case BIST_INJ_TX:
+ reg = BIST_CTRL_POINT(0) | BIST_ENABLE;
+ break;
+ case BIST_INJ_RX:
+ reg = BIST_CTRL_POINT(2) | BIST_ENABLE;
+ break;
+ };
+
+ return ad9361_spi_write(phy->spi, REG_BIST_CONFIG, reg);
+}
+
+/**
+ * Get BIST mode settings.
+ * @param phy The AD9361 state structure.
+ * @param mode Bist mode.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+void ad9361_get_bist_prbs(struct ad9361_rf_phy *phy, enum ad9361_bist_mode *mode)
+{
+ *mode = phy->bist_prbs_mode;
+}
+
+/**
+ * BIST tone.
+ * @param phy The AD9361 state structure.
+ * @param mode Bist tone mode.
+ * @param freq_Hz Bist tone frequency.
+ * @param level_dB Bist tone level.
+ * @param mask Bist reg mask.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_bist_tone(struct ad9361_rf_phy *phy,
+ enum ad9361_bist_mode mode, uint32_t freq_Hz,
+ uint32_t level_dB, uint32_t mask)
+{
+ uint32_t clk = 0;
+ uint32_t reg = 0, reg1, reg_mask;
+
+ dev_dbg(&phy->spi->dev, "%s: mode %d", __func__, mode);
+
+ phy->bist_tone_mode = mode;
+ phy->bist_tone_freq_Hz = freq_Hz;
+ phy->bist_tone_level_dB = level_dB;
+ phy->bist_tone_mask = mask;
+
+ switch (mode) {
+ case BIST_DISABLE:
+ reg = 0;
+ break;
+ case BIST_INJ_TX:
+ clk = clk_get_rate(phy, phy->ref_clk_scale[TX_SAMPL_CLK]);
+ reg = BIST_CTRL_POINT(0) | BIST_ENABLE;
+ break;
+ case BIST_INJ_RX:
+ clk = clk_get_rate(phy, phy->ref_clk_scale[RX_SAMPL_CLK]);
+ reg = BIST_CTRL_POINT(2) | BIST_ENABLE;
+ break;
+ };
+
+ reg |= TONE_PRBS;
+ reg |= TONE_LEVEL(level_dB / 6);
+
+ if (freq_Hz < 4) {
+ reg |= TONE_FREQ(freq_Hz);
+ }
+ else {
+ if (clk)
+ reg |= TONE_FREQ(DIV_ROUND_CLOSEST(freq_Hz * 32, clk) - 1);
+ }
+
+ reg_mask = BIST_MASK_CHANNEL_1_I_DATA | BIST_MASK_CHANNEL_1_Q_DATA |
+ BIST_MASK_CHANNEL_2_I_DATA | BIST_MASK_CHANNEL_2_Q_DATA;
+
+ reg1 = ((mask << 2) & reg_mask);
+ ad9361_spi_write(phy->spi, REG_BIST_AND_DATA_PORT_TEST_CONFIG, reg1);
+
+ return ad9361_spi_write(phy->spi, REG_BIST_CONFIG, reg);
+}
+
+/**
+ * Get BIST tone settings.
+ * @param phy The AD9361 state structure.
+ * @param mode Bist tone mode.
+ * @param freq_Hz Bist tone frequency.
+ * @param level_dB Bist tone level.
+ * @param mask Bist reg mask.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+void ad9361_get_bist_tone(struct ad9361_rf_phy *phy,
+ enum ad9361_bist_mode *mode, uint32_t *freq_Hz,
+ uint32_t *level_dB, uint32_t *mask)
+{
+ *mode = phy->bist_tone_mode;
+ *freq_Hz = phy->bist_tone_freq_Hz;
+ *level_dB = phy->bist_tone_level_dB;
+ *mask = phy->bist_tone_mask;
+}
+
+/**
+ * Check the calibration done bit.
+ * @param phy The AD9361 state structure.
+ * @param reg The register address.
+ * @param mask The bit mask.
+ * @param done_state The done state [0,1].
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_check_cal_done(struct ad9361_rf_phy *phy, uint32_t reg,
+ uint32_t mask, uint32_t done_state)
+{
+ uint32_t timeout = 5000; /* RFDC_CAL can take long */
+ uint32_t state;
+
+ do {
+ state = ad9361_spi_readf(phy->spi, reg, mask);
+ if (state == done_state)
+ return 0;
+
+ if (reg == REG_CALIBRATION_CTRL)
+ udelay(1200);
+ else
+ udelay(120);
+ } while (timeout--);
+
+ dev_err(&phy->spi->dev, "Calibration TIMEOUT (0x%"PRIX32", 0x%"PRIX32")", reg, mask);
+
+ return -ETIMEDOUT;
+}
+
+/**
+ * Run an AD9361 calibration and check the calibration done bit.
+ * @param phy The AD9361 state structure.
+ * @param mask The calibration bit mask[RX_BB_TUNE_CAL, TX_BB_TUNE_CAL,
+ * RX_QUAD_CAL, TX_QUAD_CAL, RX_GAIN_STEP_CAL, TXMON_CAL,
+ * RFDC_CAL, BBDC_CAL].
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_run_calibration(struct ad9361_rf_phy *phy, uint32_t mask)
+{
+ int32_t ret = ad9361_spi_write(phy->spi, REG_CALIBRATION_CTRL, mask);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(&phy->spi->dev, "%s: CAL Mask 0x%"PRIx32, __func__, mask);
+
+ return ad9361_check_cal_done(phy, REG_CALIBRATION_CTRL, mask, 0);
+}
+
+/**
+ * Choose the right RX gain table index for the selected frequency.
+ * @param freq The frequency value [Hz].
+ * @return The index to the RX gain table.
+ */
+static enum rx_gain_table_name ad9361_gt_tableindex(uint64_t freq)
+{
+ if (freq <= 1300000000ULL)
+ return TBL_200_1300_MHZ;
+
+ if (freq <= 4000000000ULL)
+ return TBL_1300_4000_MHZ;
+
+ return TBL_4000_6000_MHZ;
+}
+
+/**
+ * Shift the real frequency value, so it fits type unsigned long
+ * Note: PLL operates between 47 .. 6000 MHz which is > 2^32.
+ * @param freq The frequency value [Hz].
+ * @return The shifted frequency value.
+ */
+uint32_t ad9361_to_clk(uint64_t freq)
+{
+ return (uint32_t)(freq >> 1);
+}
+
+/**
+ * Shift back the frequency value, so it reflects the real value.
+ * Note: PLL operates between 47 .. 6000 MHz which is > 2^32.
+ * @param freq The frequency value [Hz].
+ * @return The shifted frequency value.
+ */
+uint64_t ad9361_from_clk(uint32_t freq)
+{
+ return ((uint64_t)freq << 1);
+}
+
+/**
+ * Load the gain table for the selected frequency range and receiver.
+ * @param phy The AD9361 state structure.
+ * @param freq The frequency value [Hz].
+ * @param dest The destination [GT_RX1, GT_RX2].
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_load_gt(struct ad9361_rf_phy *phy, uint64_t freq, uint32_t dest)
+{
+ struct spi_device *spi = phy->spi;
+ const uint8_t(*tab)[3];
+ enum rx_gain_table_name band;
+ uint32_t index_max, i, lna;
+
+ dev_dbg(&phy->spi->dev, "%s: frequency %"PRIu64, __func__, freq);
+
+ band = ad9361_gt_tableindex(freq);
+
+ dev_dbg(&phy->spi->dev, "%s: frequency %"PRIu64" (band %d)",
+ __func__, freq, band);
+
+ /* check if table is present */
+ if (phy->current_table == band)
+ return 0;
+
+ ad9361_spi_writef(spi, REG_AGC_CONFIG_2,
+ AGC_USE_FULL_GAIN_TABLE, !phy->pdata->split_gt);
+
+ if (has_split_gt && phy->pdata->split_gt) {
+ tab = &split_gain_table[band][0];
+ index_max = SIZE_SPLIT_TABLE;
+ }
+ else {
+ tab = &full_gain_table[band][0];
+ index_max = SIZE_FULL_TABLE;
+ }
+
+ lna = phy->pdata->elna_ctrl.elna_in_gaintable_all_index_en ?
+ EXT_LNA_CTRL : 0;
+
+ ad9361_spi_write(spi, REG_GAIN_TABLE_CONFIG, START_GAIN_TABLE_CLOCK |
+ RECEIVER_SELECT(dest)); /* Start Gain Table Clock */
+
+ for (i = 0; i < index_max; i++) {
+ ad9361_spi_write(spi, REG_GAIN_TABLE_ADDRESS, i); /* Gain Table Index */
+ ad9361_spi_write(spi, REG_GAIN_TABLE_WRITE_DATA1, tab[i][0] | lna); /* Ext LNA, Int LNA, & Mixer Gain Word */
+ ad9361_spi_write(spi, REG_GAIN_TABLE_WRITE_DATA2, tab[i][1]); /* TIA & LPF Word */
+ ad9361_spi_write(spi, REG_GAIN_TABLE_WRITE_DATA3, tab[i][2]); /* DC Cal bit & Dig Gain Word */
+ ad9361_spi_write(spi, REG_GAIN_TABLE_CONFIG,
+ START_GAIN_TABLE_CLOCK |
+ WRITE_GAIN_TABLE |
+ RECEIVER_SELECT(dest)); /* Gain Table Index */
+ ad9361_spi_write(spi, REG_GAIN_TABLE_READ_DATA1, 0); /* Dummy Write to delay 3 ADCCLK/16 cycles */
+ ad9361_spi_write(spi, REG_GAIN_TABLE_READ_DATA1, 0); /* Dummy Write to delay ~1u */
+ }
+
+ ad9361_spi_write(spi, REG_GAIN_TABLE_CONFIG, START_GAIN_TABLE_CLOCK |
+ RECEIVER_SELECT(dest)); /* Clear Write Bit */
+ ad9361_spi_write(spi, REG_GAIN_TABLE_READ_DATA1, 0); /* Dummy Write to delay ~1u */
+ ad9361_spi_write(spi, REG_GAIN_TABLE_READ_DATA1, 0); /* Dummy Write to delay ~1u */
+ ad9361_spi_write(spi, REG_GAIN_TABLE_CONFIG, 0); /* Stop Gain Table Clock */
+
+ phy->current_table = band;
+
+ return 0;
+}
+
+/**
+ * Setup the external low-noise amplifier (LNA).
+ * @param phy The AD9361 state structure.
+ * @param ctrl Pointer to eLNA control structure.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_setup_ext_lna(struct ad9361_rf_phy *phy,
+struct elna_control *ctrl)
+{
+ ad9361_spi_writef(phy->spi, REG_EXTERNAL_LNA_CTRL, EXTERNAL_LNA1_CTRL,
+ ctrl->elna_1_control_en);
+
+ ad9361_spi_writef(phy->spi, REG_EXTERNAL_LNA_CTRL, EXTERNAL_LNA2_CTRL,
+ ctrl->elna_2_control_en);
+
+ ad9361_spi_write(phy->spi, REG_EXT_LNA_HIGH_GAIN,
+ EXT_LNA_HIGH_GAIN(ctrl->gain_mdB / 500));
+
+ return ad9361_spi_write(phy->spi, REG_EXT_LNA_LOW_GAIN,
+ EXT_LNA_LOW_GAIN(ctrl->bypass_loss_mdB / 500));
+}
+
+/**
+ * Set the clock output mode.
+ * @param phy The AD9361 state structure.
+ * @param mode The clock output mode [].
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_clkout_control(struct ad9361_rf_phy *phy,
+enum ad9361_clkout mode)
+{
+ if (mode == CLKOUT_DISABLE)
+ return ad9361_spi_writef(phy->spi, REG_BBPLL, CLKOUT_ENABLE, 0);
+
+ return ad9361_spi_writef(phy->spi, REG_BBPLL,
+ CLKOUT_ENABLE | CLKOUT_SELECT(~0),
+ ((mode - 1) << 1) | 0x1);
+}
+
+/**
+ * Load the Gm Sub Table.
+ * @param phy The AD9361 state structure.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_load_mixer_gm_subtable(struct ad9361_rf_phy *phy)
+{
+ int32_t i, addr;
+ dev_dbg(&phy->spi->dev, "%s", __func__);
+
+ ad9361_spi_write(phy->spi, REG_GM_SUB_TABLE_CONFIG,
+ START_GM_SUB_TABLE_CLOCK); /* Start Clock */
+
+ for (i = 0, addr = ARRAY_SIZE(gm_st_ctrl); i < (int64_t)ARRAY_SIZE(gm_st_ctrl); i++) {
+ ad9361_spi_write(phy->spi, REG_GM_SUB_TABLE_ADDRESS, --addr); /* Gain Table Index */
+ ad9361_spi_write(phy->spi, REG_GM_SUB_TABLE_BIAS_WRITE, 0); /* Bias */
+ ad9361_spi_write(phy->spi, REG_GM_SUB_TABLE_GAIN_WRITE, gm_st_gain[i]); /* Gain */
+ ad9361_spi_write(phy->spi, REG_GM_SUB_TABLE_CTRL_WRITE, gm_st_ctrl[i]); /* Control */
+ ad9361_spi_write(phy->spi, REG_GM_SUB_TABLE_CONFIG,
+ WRITE_GM_SUB_TABLE | START_GM_SUB_TABLE_CLOCK); /* Write Words */
+ ad9361_spi_write(phy->spi, REG_GM_SUB_TABLE_GAIN_READ, 0); /* Dummy Delay */
+ ad9361_spi_write(phy->spi, REG_GM_SUB_TABLE_GAIN_READ, 0); /* Dummy Delay */
+ }
+
+ ad9361_spi_write(phy->spi, REG_GM_SUB_TABLE_CONFIG, START_GM_SUB_TABLE_CLOCK); /* Clear Write */
+ ad9361_spi_write(phy->spi, REG_GM_SUB_TABLE_GAIN_READ, 0); /* Dummy Delay */
+ ad9361_spi_write(phy->spi, REG_GM_SUB_TABLE_GAIN_READ, 0); /* Dummy Delay */
+ ad9361_spi_write(phy->spi, REG_GM_SUB_TABLE_CONFIG, 0); /* Stop Clock */
+
+ return 0;
+}
+
+/**
+ * Set the attenuation for the selected TX channels.
+ * @param phy The AD9361 state structure.
+ * @param atten_mdb Attenuation value [mdB].
+ * @param tx1 Set true, the attenuation of the TX1 will be affected.
+ * @param tx2 Set true, the attenuation of the TX2 will be affected.
+ * @param immed Set true, an immediate update will take place.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_set_tx_atten(struct ad9361_rf_phy *phy, uint32_t atten_mdb,
+ bool tx1, bool tx2, bool immed)
+{
+ uint8_t buf[2];
+ int32_t ret = 0;
+
+ dev_dbg(&phy->spi->dev, "%s : attenuation %"PRIu32" mdB tx1=%d tx2=%d",
+ __func__, atten_mdb, tx1, tx2);
+
+ if (atten_mdb > 89750) /* 89.75 dB */
+ return -EINVAL;
+
+ atten_mdb /= 250; /* Scale to 0.25dB / LSB */
+
+ buf[0] = atten_mdb >> 8;
+ buf[1] = atten_mdb & 0xFF;
+
+ ad9361_spi_writef(phy->spi, REG_TX2_DIG_ATTEN,
+ IMMEDIATELY_UPDATE_TPC_ATTEN, 0);
+
+ if (tx1)
+ ret = ad9361_spi_writem(phy->spi, REG_TX1_ATTEN_1, buf, 2);
+
+ if (tx2)
+ ret = ad9361_spi_writem(phy->spi, REG_TX2_ATTEN_1, buf, 2);
+
+ if (immed)
+ ad9361_spi_writef(phy->spi, REG_TX2_DIG_ATTEN,
+ IMMEDIATELY_UPDATE_TPC_ATTEN, 1);
+
+ return ret;
+}
+
+/**
+ * Get the attenuation for the selected TX channel.
+ * @param phy The AD9361 state structure.
+ * @param tx_num The selected channel [1, 2].
+ * @return The attenuation value [mdB] or negative error code in case of failure.
+ */
+int32_t ad9361_get_tx_atten(struct ad9361_rf_phy *phy, uint32_t tx_num)
+{
+ uint8_t buf[2];
+ int32_t ret = 0;
+ uint32_t code;
+
+ ret = ad9361_spi_readm(phy->spi, (tx_num == 1) ?
+ REG_TX1_ATTEN_1 : REG_TX2_ATTEN_1, buf, 2);
+
+ if (ret < 0)
+ return ret;
+
+ code = (buf[0] << 8) | buf[1];
+
+ code *= 250;
+
+ return code;
+}
+
+/**
+ * Mute TX.
+ * @param phy The AD9361 state structure.
+ * @param state The state - 0 mute; 1 - unmute.
+ * @return 0 in case of success
+ */
+int32_t ad9361_tx_mute(struct ad9361_rf_phy *phy, uint32_t state)
+{
+ int32_t ret;
+
+ if (state) {
+ phy->tx1_atten_cached = ad9361_get_tx_atten(phy, 1);
+ phy->tx2_atten_cached = ad9361_get_tx_atten(phy, 2);
+
+ return ad9361_set_tx_atten(phy, 89750, true, true, true);
+ } else {
+ if (phy->tx1_atten_cached == phy->tx2_atten_cached)
+ return ad9361_set_tx_atten(phy, phy->tx1_atten_cached,
+ true, true, true);
+
+ ret = ad9361_set_tx_atten(phy, phy->tx1_atten_cached,
+ true, false, true);
+ ret |= ad9361_set_tx_atten(phy, phy->tx2_atten_cached,
+ false, true, true);
+
+ return ret;
+ }
+}
+
+/**
+ * Choose the right RF VCO table index for the selected frequency.
+ * @param freq The frequency value [Hz].
+ * @return The index from the RF VCO table.
+ */
+static uint32_t ad9361_rfvco_tableindex(uint32_t freq)
+{
+ if (freq < 50000000UL)
+ return LUT_FTDD_40;
+
+ if (freq <= 70000000UL)
+ return LUT_FTDD_60;
+
+ return LUT_FTDD_80;
+}
+
+/**
+ * Initialize the RFPLL VCO.
+ * @param phy The AD9361 state structure.
+ * @param tx Set true for TX_RFPLL.
+ * @param vco_freq The VCO frequency [Hz].
+ * @param ref_clk The reference clock frequency [Hz].
+ * @return 0 in case of success
+ */
+static int32_t ad9361_rfpll_vco_init(struct ad9361_rf_phy *phy,
+ bool tx, uint64_t vco_freq,
+ uint32_t ref_clk)
+{
+ struct spi_device *spi = phy->spi;
+ const struct SynthLUT(*tab);
+ int32_t i = 0;
+ uint32_t range, offs = 0;
+
+ range = ad9361_rfvco_tableindex(ref_clk);
+
+ dev_dbg(&phy->spi->dev, "%s : vco_freq %"PRIu64" : ref_clk %"PRIu32" : range %"PRIu32,
+ __func__, vco_freq, ref_clk, range);
+
+ do_div(&vco_freq, 1000000UL); /* vco_freq in MHz */
+
+ if ((phy->pdata->fdd && !phy->pdata->fdd_independent_mode)
+ && (phy->current_tx_lo_freq != phy->current_rx_lo_freq)) {
+ tab = &SynthLUT_FDD[range][0];
+ if (tx)
+ phy->current_tx_use_tdd_table = false;
+ else
+ phy->current_rx_use_tdd_table = false;
+ } else {
+ tab = &SynthLUT_TDD[range][0];
+ if (tx)
+ phy->current_tx_use_tdd_table = true;
+ else
+ phy->current_rx_use_tdd_table = true;
+ }
+
+ if (tx)
+ offs = REG_TX_VCO_OUTPUT - REG_RX_VCO_OUTPUT;
+
+ while (i < SYNTH_LUT_SIZE && tab[i].VCO_MHz > vco_freq)
+ i++;
+
+ dev_dbg(&phy->spi->dev, "%s : freq %d MHz : index %"PRId32,
+ __func__, tab[i].VCO_MHz, i);
+
+ ad9361_spi_write(spi, REG_RX_VCO_OUTPUT + offs,
+ VCO_OUTPUT_LEVEL(tab[i].VCO_Output_Level) |
+ PORB_VCO_LOGIC);
+ ad9361_spi_writef(spi, REG_RX_ALC_VARACTOR + offs,
+ VCO_VARACTOR(~0), tab[i].VCO_Varactor);
+ ad9361_spi_write(spi, REG_RX_VCO_BIAS_1 + offs,
+ VCO_BIAS_REF(tab[i].VCO_Bias_Ref) |
+ VCO_BIAS_TCF(tab[i].VCO_Bias_Tcf));
+
+ ad9361_spi_write(spi, REG_RX_FORCE_VCO_TUNE_1 + offs,
+ VCO_CAL_OFFSET(tab[i].VCO_Cal_Offset));
+ ad9361_spi_write(spi, REG_RX_VCO_VARACTOR_CTRL_1 + offs,
+ VCO_VARACTOR_REFERENCE(
+ tab[i].VCO_Varactor_Reference));
+
+ ad9361_spi_write(spi, REG_RX_VCO_CAL_REF + offs, VCO_CAL_REF_TCF(0));
+
+ ad9361_spi_write(spi, REG_RX_VCO_VARACTOR_CTRL_0 + offs,
+ VCO_VARACTOR_OFFSET(0) |
+ VCO_VARACTOR_REFERENCE_TCF(7));
+
+ ad9361_spi_writef(spi, REG_RX_CP_CURRENT + offs, CHARGE_PUMP_CURRENT(~0),
+ tab[i].Charge_Pump_Current);
+ ad9361_spi_write(spi, REG_RX_LOOP_FILTER_1 + offs,
+ LOOP_FILTER_C2(tab[i].LF_C2) |
+ LOOP_FILTER_C1(tab[i].LF_C1));
+ ad9361_spi_write(spi, REG_RX_LOOP_FILTER_2 + offs,
+ LOOP_FILTER_R1(tab[i].LF_R1) |
+ LOOP_FILTER_C3(tab[i].LF_C3));
+ ad9361_spi_write(spi, REG_RX_LOOP_FILTER_3 + offs,
+ LOOP_FILTER_R3(tab[i].LF_R3));
+
+ return 0;
+}
+
+/**
+ * Get the current gain in Split Gain Table Mode
+ * @param phy The AD9361 state structure.
+ * @param idx_reg Register base address for the selected receiver
+ * @param rx_gain A rf_rx_gain struct to store the RF gain.
+ * @return 0 in case of success,
+ */
+static int32_t ad9361_get_split_table_gain(struct ad9361_rf_phy *phy, uint32_t idx_reg,
+struct rf_rx_gain *rx_gain)
+{
+ struct spi_device *spi = phy->spi;
+ uint32_t val, tbl_addr;
+ int32_t rc = 0;
+
+ rx_gain->fgt_lmt_index = ad9361_spi_readf(spi, idx_reg,
+ FULL_TABLE_GAIN_INDEX(~0));
+ tbl_addr = ad9361_spi_read(spi, REG_GAIN_TABLE_ADDRESS);
+
+ ad9361_spi_write(spi, REG_GAIN_TABLE_ADDRESS, rx_gain->fgt_lmt_index);
+
+ val = ad9361_spi_read(spi, REG_GAIN_TABLE_READ_DATA1);
+ rx_gain->lna_index = TO_LNA_GAIN(val);
+ rx_gain->mixer_index = TO_MIXER_GM_GAIN(val);
+
+ rx_gain->tia_index = ad9361_spi_readf(spi, REG_GAIN_TABLE_READ_DATA2, TIA_GAIN);
+
+ rx_gain->lmt_gain = lna_table[phy->current_table][rx_gain->lna_index] +
+ mixer_table[phy->current_table][rx_gain->mixer_index] +
+ tia_table[rx_gain->tia_index];
+
+ ad9361_spi_write(spi, REG_GAIN_TABLE_ADDRESS, tbl_addr);
+
+ /* Read LPF Index */
+ rx_gain->lpf_gain = ad9361_spi_readf(spi, idx_reg + 1, LPF_GAIN_RX(~0));
+
+ /* Read Digital Gain */
+ rx_gain->digital_gain = ad9361_spi_readf(spi, idx_reg + 2,
+ DIGITAL_GAIN_RX(~0));
+
+ rx_gain->gain_db = rx_gain->lmt_gain + rx_gain->lpf_gain +
+ rx_gain->digital_gain;
+ return rc;
+}
+
+/**
+ * Get the current gain in Full Gain Table Mode
+ * @param phy The AD9361 state structure.
+ * @param idx_reg Register base address for the selected receiver
+ * @param rx_gain A rf_rx_gain struct to store the RF gain.
+ * @return 0 in case of success
+ */
+static int32_t ad9361_get_full_table_gain(struct ad9361_rf_phy *phy, uint32_t idx_reg,
+struct rf_rx_gain *rx_gain)
+{
+ struct spi_device *spi = phy->spi;
+ int32_t val;
+ enum rx_gain_table_name tbl;
+ struct rx_gain_info *gain_info;
+ int32_t rc = 0, rx_gain_db;
+
+ tbl = ad9361_gt_tableindex(
+ ad9361_from_clk(clk_get_rate(phy, phy->ref_clk_scale[RX_RFPLL])));
+
+ rx_gain->fgt_lmt_index = val = ad9361_spi_readf(spi, idx_reg,
+ FULL_TABLE_GAIN_INDEX(~0));
+ gain_info = &phy->rx_gain[tbl];
+ if (val > gain_info->idx_step_offset) {
+ val = val - gain_info->idx_step_offset;
+ rx_gain_db = gain_info->starting_gain_db +
+ ((val)* gain_info->gain_step_db);
+ }
+ else {
+ rx_gain_db = gain_info->starting_gain_db;
+ }
+
+ /* Read Digital Gain */
+ rx_gain->digital_gain = ad9361_spi_readf(spi, idx_reg + 2,
+ DIGITAL_GAIN_RX(~0));
+
+ rx_gain->gain_db = rx_gain_db;
+
+ return rc;
+}
+
+/**
+ * Get current RX gain for the selected channel.
+ * @param phy The AD9361 state structure.
+ * @param rx_id The desired channel number (0, 1).
+ * @param rx_gain A rf_rx_gain struct to store the RF gain.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_rx_gain(struct ad9361_rf_phy *phy,
+ uint32_t rx_id, struct rf_rx_gain *rx_gain)
+{
+ struct spi_device *spi = phy->spi;
+ uint32_t val, idx_reg;
+ uint8_t gain_ctl_shift, rx_enable_mask;
+ uint8_t fast_atk_shift;
+ int32_t rc = 0;
+
+ if (rx_id == 1) {
+ gain_ctl_shift = RX1_GAIN_CTRL_SHIFT;
+ idx_reg = REG_GAIN_RX1;
+ rx_enable_mask = RX_CHANNEL_ENABLE(RX_1);
+ fast_atk_shift = RX1_FAST_ATK_SHIFT;
+
+ }
+ else if (rx_id == 2) {
+ gain_ctl_shift = RX2_GAIN_CTRL_SHIFT;
+ idx_reg = REG_GAIN_RX2;
+ rx_enable_mask = RX_CHANNEL_ENABLE(RX_2);
+ fast_atk_shift = RX2_FAST_ATK_SHIFT;
+ }
+ else {
+ dev_err(dev, "Unknown Rx path %"PRIu32, rx_id);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ val = ad9361_spi_readf(spi, REG_RX_ENABLE_FILTER_CTRL, rx_enable_mask);
+
+ if (!val) {
+ dev_dbg(dev, "Rx%"PRIu32" is not enabled", rx_gain->ant);
+ rc = -EAGAIN;
+ goto out;
+ }
+
+ val = ad9361_spi_read(spi, REG_AGC_CONFIG_1);
+
+ val = (val >> gain_ctl_shift) & RX_GAIN_CTL_MASK;
+
+ if (val == RX_GAIN_CTL_AGC_FAST_ATK) {
+ /* In fast attack mode check whether Fast attack state machine
+ * has locked gain, if not then we can not read gain.
+ */
+ val = ad9361_spi_read(spi, REG_FAST_ATTACK_STATE);
+ val = (val >> fast_atk_shift) & FAST_ATK_MASK;
+ if (val != FAST_ATK_GAIN_LOCKED) {
+ dev_warn(dev, "Failed to read gain, state m/c at %"PRIx32,
+ val);
+ rc = -EAGAIN;
+ goto out;
+ }
+ }
+
+ if (has_split_gt && phy->pdata->split_gt)
+ rc = ad9361_get_split_table_gain(phy, idx_reg, rx_gain);
+ else
+ rc = ad9361_get_full_table_gain(phy, idx_reg, rx_gain);
+
+out:
+ return rc;
+}
+
+/**
+ * Force Enable State Machine (ENSM) to the desired state (internally used only).
+ * @param phy The AD9361 state structure.
+ * @param ensm_state The ENSM state [ENSM_STATE_SLEEP_WAIT, ENSM_STATE_ALERT,
+ * ENSM_STATE_TX, ENSM_STATE_TX_FLUSH, ENSM_STATE_RX,
+ * ENSM_STATE_RX_FLUSH, ENSM_STATE_FDD, ENSM_STATE_FDD_FLUSH].
+ * @return None.
+ */
+void ad9361_ensm_force_state(struct ad9361_rf_phy *phy, uint8_t ensm_state)
+{
+ struct spi_device *spi = phy->spi;
+ uint8_t dev_ensm_state;
+ int32_t rc;
+ uint32_t val;
+
+ dev_ensm_state = ad9361_spi_readf(spi, REG_STATE, ENSM_STATE(~0));
+
+ phy->prev_ensm_state = dev_ensm_state;
+
+ if (dev_ensm_state == ensm_state) {
+ dev_dbg(dev, "Nothing to do, device is already in %d state",
+ ensm_state);
+ goto out;
+ }
+
+ dev_dbg(dev, "Device is in %x state, forcing to %x", dev_ensm_state,
+ ensm_state);
+
+ val = ad9361_spi_read(spi, REG_ENSM_CONFIG_1);
+
+ /* Enable control through SPI writes, and take out from
+ * Alert
+ */
+ if (val & ENABLE_ENSM_PIN_CTRL) {
+ val &= ~ENABLE_ENSM_PIN_CTRL;
+ phy->ensm_pin_ctl_en = true;
+ }
+ else {
+ phy->ensm_pin_ctl_en = false;
+ }
+
+ if (dev_ensm_state)
+ val &= ~(TO_ALERT);
+
+ switch (ensm_state) {
+
+ case ENSM_STATE_TX:
+ case ENSM_STATE_FDD:
+ val |= FORCE_TX_ON;
+ break;
+ case ENSM_STATE_RX:
+ val |= FORCE_RX_ON;
+ break;
+ case ENSM_STATE_ALERT:
+ val &= ~(FORCE_TX_ON | FORCE_RX_ON);
+ val |= TO_ALERT | FORCE_ALERT_STATE;
+ break;
+ default:
+ dev_err(dev, "No handling for forcing %d ensm state",
+ ensm_state);
+ goto out;
+ }
+
+ ad9361_spi_write(spi, REG_ENSM_CONFIG_1, TO_ALERT | FORCE_ALERT_STATE);
+
+ rc = ad9361_spi_write(spi, REG_ENSM_CONFIG_1, val);
+ if (rc)
+ dev_err(dev, "Failed to restore state");
+
+out:
+ return;
+
+}
+
+/**
+ * Restore the previous Enable State Machine (ENSM) state.
+ * @param phy The AD9361 state structure.
+ * @return None.
+ */
+void ad9361_ensm_restore_prev_state(struct ad9361_rf_phy *phy)
+{
+ struct spi_device *spi = phy->spi;
+ int32_t rc;
+ uint32_t val;
+
+ val = ad9361_spi_read(spi, REG_ENSM_CONFIG_1);
+
+ /* We are restoring state only, so clear State bits first
+ * which might have set while forcing a particular state
+ */
+ val &= ~(FORCE_TX_ON | FORCE_RX_ON |
+ TO_ALERT | FORCE_ALERT_STATE);
+
+ switch (phy->prev_ensm_state) {
+
+ case ENSM_STATE_TX:
+ case ENSM_STATE_FDD:
+ val |= FORCE_TX_ON;
+ break;
+ case ENSM_STATE_RX:
+ val |= FORCE_RX_ON;
+ break;
+ case ENSM_STATE_ALERT:
+ val |= TO_ALERT;
+ break;
+ case ENSM_STATE_INVALID:
+ dev_dbg(dev, "No need to restore, ENSM state wasn't saved");
+ goto out;
+ default:
+ dev_dbg(dev, "Could not restore to %d ENSM state",
+ phy->prev_ensm_state);
+ goto out;
+ }
+
+ ad9361_spi_write(spi, REG_ENSM_CONFIG_1, TO_ALERT | FORCE_ALERT_STATE);
+
+ rc = ad9361_spi_write(spi, REG_ENSM_CONFIG_1, val);
+ if (rc) {
+ dev_err(dev, "Failed to write ENSM_CONFIG_1");
+ goto out;
+ }
+
+ if (phy->ensm_pin_ctl_en) {
+ val |= ENABLE_ENSM_PIN_CTRL;
+ rc = ad9361_spi_write(spi, REG_ENSM_CONFIG_1, val);
+ if (rc)
+ dev_err(dev, "Failed to write ENSM_CONFIG_1");
+ }
+
+out:
+ return;
+}
+
+/**
+ * Set gain in Split Gain Table Mode (used only in Manual Gain Control Mode).
+ * @param phy The AD9361 state structure.
+ * @param idx_reg Register base address for the selected receiver
+ * @param rx_gain The rf_rx_gain struct containing the RF gain.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t set_split_table_gain(struct ad9361_rf_phy *phy, uint32_t idx_reg,
+struct rf_rx_gain *rx_gain)
+{
+ struct spi_device *spi = phy->spi;
+ int32_t rc = 0;
+
+ if ((rx_gain->fgt_lmt_index > MAX_LMT_INDEX) ||
+ (rx_gain->lpf_gain > MAX_LPF_GAIN) ||
+ (rx_gain->digital_gain > MAX_DIG_GAIN)) {
+ dev_err(dev, "LMT_INDEX missing or greater than max value %d",
+ MAX_LMT_INDEX);
+ dev_err(dev, "LPF_GAIN missing or greater than max value %d",
+ MAX_LPF_GAIN);
+ dev_err(dev, "DIGITAL_GAIN cannot be more than %d",
+ MAX_DIG_GAIN);
+ rc = -EINVAL;
+ goto out;
+ }
+ if (rx_gain->gain_db > 0)
+ dev_dbg(dev, "Ignoring rx_gain value in split table mode.");
+ if (rx_gain->fgt_lmt_index == 0 && rx_gain->lpf_gain == 0 &&
+ rx_gain->digital_gain == 0) {
+ dev_err(dev,
+ "In split table mode, All LMT/LPF/digital gains cannot be 0");
+ rc = -EINVAL;
+ goto out;
+ }
+
+ ad9361_spi_writef(spi, idx_reg, RX_FULL_TBL_IDX_MASK, rx_gain->fgt_lmt_index);
+ ad9361_spi_writef(spi, idx_reg + 1, RX_LPF_IDX_MASK, rx_gain->lpf_gain);
+
+ if (phy->pdata->gain_ctrl.dig_gain_en) {
+ ad9361_spi_writef(spi, idx_reg + 2, RX_DIGITAL_IDX_MASK, rx_gain->digital_gain);
+
+ }
+ else if (rx_gain->digital_gain > 0) {
+ dev_err(dev, "Digital gain is disabled and cannot be set");
+ }
+out:
+ return rc;
+}
+
+/**
+ * Set gain in Full Gain Table Mode (used only in Manual Gain Control Mode).
+ * @param phy The AD9361 state structure.
+ * @param idx_reg Register base address for the selected receiver
+ * @param rx_gain The rf_rx_gain struct containing the RF gain.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t set_full_table_gain(struct ad9361_rf_phy *phy, uint32_t idx_reg,
+struct rf_rx_gain *rx_gain)
+{
+ struct spi_device *spi = phy->spi;
+ enum rx_gain_table_name tbl;
+ struct rx_gain_info *gain_info;
+ uint32_t val;
+ int32_t rc = 0;
+
+ if (rx_gain->fgt_lmt_index != (uint32_t)~0 || (int64_t)rx_gain->lpf_gain != (uint32_t)~0 ||
+ rx_gain->digital_gain > 0)
+ dev_dbg(dev,
+ "Ignoring lmt/lpf/digital gains in Single Table mode");
+
+ tbl = ad9361_gt_tableindex(
+ ad9361_from_clk(clk_get_rate(phy, phy->ref_clk_scale[RX_RFPLL])));
+
+ gain_info = &phy->rx_gain[tbl];
+ if ((rx_gain->gain_db < gain_info->starting_gain_db) ||
+ (rx_gain->gain_db > gain_info->max_gain_db)) {
+
+ dev_err(dev, "Invalid gain %"PRId32", supported range [%"PRId32" - %"PRId32"]",
+ rx_gain->gain_db, gain_info->starting_gain_db,
+ gain_info->max_gain_db);
+ rc = -EINVAL;
+ goto out;
+
+ }
+
+ val = ((rx_gain->gain_db - gain_info->starting_gain_db) /
+ gain_info->gain_step_db) + gain_info->idx_step_offset;
+ ad9361_spi_writef(spi, idx_reg, RX_FULL_TBL_IDX_MASK, val);
+
+out:
+ return rc;
+}
+
+/**
+ * Set the RX gain for the selected channel.
+ * @param phy The AD9361 state structure.
+ * @param rx_id The desired channel number (0, 1).
+ * @param rx_gain The rf_rx_gain struct containing the RF gain.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_set_rx_gain(struct ad9361_rf_phy *phy,
+ uint32_t rx_id, struct rf_rx_gain *rx_gain)
+{
+ struct spi_device *spi = phy->spi;
+ uint32_t val, idx_reg;
+ uint8_t gain_ctl_shift;
+ int32_t rc = 0;
+
+ if (rx_id == 1) {
+ gain_ctl_shift = RX1_GAIN_CTRL_SHIFT;
+ idx_reg = REG_RX1_MANUAL_LMT_FULL_GAIN;
+
+ }
+ else if (rx_id == 2) {
+ gain_ctl_shift = RX2_GAIN_CTRL_SHIFT;
+ idx_reg = REG_RX2_MANUAL_LMT_FULL_GAIN;
+ }
+ else {
+ dev_err(dev, "Unknown Rx path %"PRIu32, rx_id);
+ rc = -EINVAL;
+ goto out;
+
+ }
+
+ val = ad9361_spi_read(spi, REG_AGC_CONFIG_1);
+ val = (val >> gain_ctl_shift) & RX_GAIN_CTL_MASK;
+
+ if (val != RX_GAIN_CTL_MGC) {
+ dev_dbg(dev, "Rx gain can be set in MGC mode only");
+ goto out;
+ }
+
+ if (has_split_gt && phy->pdata->split_gt)
+ rc = set_split_table_gain(phy, idx_reg, rx_gain);
+ else
+ rc = set_full_table_gain(phy, idx_reg, rx_gain);
+
+ if (rc) {
+ dev_err(dev, "Unable to write gain tbl idx reg: %"PRIu32, idx_reg);
+ goto out;
+ }
+
+out:
+ return rc;
+
+}
+
+/**
+ * Initialize the rx_gain_info structure.
+ * @param rx_gain The rx_gain_info structure pointer.
+ * @param type Either Full or Split Table
+ * @param starting_gain The starting gain value.
+ * @param max_gain The maximum gain value.
+ * @param gain_step The gain step.
+ * @param max_idx The max table size.
+ * @param idx_offset Offset in the table where linear progression starts
+ * @return None
+ */
+static void ad9361_init_gain_info(struct rx_gain_info *rx_gain,
+enum rx_gain_table_type type, int32_t starting_gain,
+ int32_t max_gain, int32_t gain_step, int32_t max_idx, int32_t idx_offset)
+{
+ rx_gain->tbl_type = type;
+ rx_gain->starting_gain_db = starting_gain;
+ rx_gain->max_gain_db = max_gain;
+ rx_gain->gain_step_db = gain_step;
+ rx_gain->max_idx = max_idx;
+ rx_gain->idx_step_offset = idx_offset;
+}
+
+/**
+ * Initialize the gain table information.
+ * @param phy The AD9361 state structure.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_init_gain_tables(struct ad9361_rf_phy *phy)
+{
+ struct rx_gain_info *rx_gain;
+
+ /* Intialize Meta data according to default gain tables
+ * of AD9631. Changing/Writing of gain tables is not
+ * supported yet.
+ */
+ rx_gain = &phy->rx_gain[TBL_200_1300_MHZ];
+ ad9361_init_gain_info(rx_gain, RXGAIN_FULL_TBL, 1, 77, 1,
+ SIZE_FULL_TABLE, 0);
+
+ rx_gain = &phy->rx_gain[TBL_1300_4000_MHZ];
+ ad9361_init_gain_info(rx_gain, RXGAIN_FULL_TBL, -4, 71, 1,
+ SIZE_FULL_TABLE, 1);
+
+ rx_gain = &phy->rx_gain[TBL_4000_6000_MHZ];
+ ad9361_init_gain_info(rx_gain, RXGAIN_FULL_TBL, -10, 62, 1,
+ SIZE_FULL_TABLE, 4);
+
+ return 0;
+}
+
+/**
+ * Update the Gain Control.
+ * @param phy The AD9361 state structure.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_gc_update(struct ad9361_rf_phy *phy)
+{
+ struct spi_device *spi = phy->spi;
+ uint32_t clkrf;
+ uint32_t reg, delay_lna, settling_delay, dec_pow_meas_dur;
+ int32_t ret;
+ uint32_t fir_div;
+
+ clkrf = clk_get_rate(phy, phy->ref_clk_scale[CLKRF_CLK]);
+ delay_lna = phy->pdata->elna_ctrl.settling_delay_ns;
+
+ /*
+ * AGC Attack Delay (us)=ceiling((((0.2+Delay_LNA)*ClkRF+14))/(2*ClkRF))+1
+ * ClkRF in MHz, delay in us
+ */
+
+ reg = (200 * delay_lna) / 2 + (14000000UL / (clkrf / 500U));
+ reg = DIV_ROUND_UP(reg, 1000UL) +
+ phy->pdata->gain_ctrl.agc_attack_delay_extra_margin_us;
+ reg = clamp_t(uint8_t, reg, 0U, 31U);
+ ret = ad9361_spi_writef(spi, REG_AGC_ATTACK_DELAY,
+ AGC_ATTACK_DELAY(~0), reg);
+
+ /*
+ * Peak Overload Wait Time (ClkRF cycles)=ceiling((0.1+Delay_LNA) *clkRF+1)
+ */
+
+ reg = (delay_lna + 100UL) * (clkrf / 1000UL);
+ reg = DIV_ROUND_UP(reg, 1000000UL) + 1;
+ reg = clamp_t(uint8_t, reg, 0U, 31U);
+ ret |= ad9361_spi_writef(spi, REG_PEAK_WAIT_TIME,
+ PEAK_OVERLOAD_WAIT_TIME(~0), reg);
+
+ /*
+ * Settling Delay in 0x111. Applies to all gain control modes:
+ * 0x111[D4:D0]= ceiling(((0.2+Delay_LNA)*clkRF
+ dodebug = false;+14)/2)
+ */
+
+ reg = (delay_lna + 200UL) * (clkrf / 2000UL);
+ reg = DIV_ROUND_UP(reg, 1000000UL) + 7;
+ reg = settling_delay = clamp_t(uint8_t, reg, 0U, 31U);
+ ret |= ad9361_spi_writef(spi, REG_FAST_CONFIG_2_SETTLING_DELAY,
+ SETTLING_DELAY(~0), reg);
+
+ /*
+ * Gain Update Counter [15:0]= round((((time*ClkRF-0x111[D4:D0]*2)-2))/2)
+ */
+ reg = phy->pdata->gain_ctrl.gain_update_interval_us * (clkrf / 1000UL) -
+ settling_delay * 2000UL - 2000UL;
+
+ reg = DIV_ROUND_CLOSEST(reg, 2000UL);
+ reg = clamp_t(uint32_t, reg, 0U, 131071UL);
+
+ if (phy->agc_mode[0] == RF_GAIN_FASTATTACK_AGC ||
+ phy->agc_mode[1] == RF_GAIN_FASTATTACK_AGC) {
+ dec_pow_meas_dur =
+ phy->pdata->gain_ctrl.f_agc_dec_pow_measuremnt_duration;
+ } else {
+ fir_div = DIV_ROUND_CLOSEST(clkrf,
+ clk_get_rate(phy, phy->ref_clk_scale[RX_SAMPL_CLK]));
+ dec_pow_meas_dur = phy->pdata->gain_ctrl.dec_pow_measuremnt_duration;
+
+ if (((reg * 2 / fir_div) / dec_pow_meas_dur) < 2) {
+ dec_pow_meas_dur = reg / fir_div;
+ }
+ }
+
+ /* Power Measurement Duration */
+ ad9361_spi_writef(spi, REG_DEC_POWER_MEASURE_DURATION_0,
+ DEC_POWER_MEASUREMENT_DURATION(~0),
+ ilog2(dec_pow_meas_dur / 16));
+
+
+ ret |= ad9361_spi_writef(spi, REG_DIGITAL_SAT_COUNTER,
+ DOUBLE_GAIN_COUNTER, reg > 65535);
+
+ if (reg > 65535)
+ reg /= 2;
+
+ ret |= ad9361_spi_write(spi, REG_GAIN_UPDATE_COUNTER1, reg & 0xFF);
+ ret |= ad9361_spi_write(spi, REG_GAIN_UPDATE_COUNTER2, reg >> 8);
+
+ /*
+ * Fast AGC State Wait Time - Energy Detect Count
+ */
+
+ reg = DIV_ROUND_CLOSEST(phy->pdata->gain_ctrl.f_agc_state_wait_time_ns *
+ (clkrf / 1000UL), 1000000UL);
+ reg = clamp_t(uint32_t, reg, 0U, 31U);
+ ret |= ad9361_spi_writef(spi, REG_FAST_ENERGY_DETECT_COUNT,
+ ENERGY_DETECT_COUNT(~0), reg);
+
+ return ret;
+}
+
+/**
+ * Set the gain control mode.
+ * @param phy The AD9361 state structure.
+ * @param rf_gain_ctrl A rf_gain_ctrl struct that contains the the desired
+ * channel information and the gain control mode.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_set_gain_ctrl_mode(struct ad9361_rf_phy *phy,
+ struct rf_gain_ctrl *gain_ctrl)
+{
+ struct spi_device *spi = phy->spi;
+ int32_t rc = 0;
+ uint32_t gain_ctl_shift, mode;
+ uint8_t val;
+
+ rc = ad9361_spi_readm(spi, REG_AGC_CONFIG_1, &val, 1);
+ if (rc) {
+ dev_err(dev, "Unable to read AGC config1 register: %x",
+ REG_AGC_CONFIG_1);
+ goto out;
+ }
+
+ switch (gain_ctrl->mode) {
+ case RF_GAIN_MGC:
+ mode = RX_GAIN_CTL_MGC;
+ break;
+ case RF_GAIN_FASTATTACK_AGC:
+ mode = RX_GAIN_CTL_AGC_FAST_ATK;
+ break;
+ case RF_GAIN_SLOWATTACK_AGC:
+ mode = RX_GAIN_CTL_AGC_SLOW_ATK;
+ break;
+ case RF_GAIN_HYBRID_AGC:
+ mode = RX_GAIN_CTL_AGC_SLOW_ATK_HYBD;
+ break;
+ default:
+ rc = -EINVAL;
+ goto out;
+ }
+
+ if (gain_ctrl->ant == 1) {
+ gain_ctl_shift = RX1_GAIN_CTRL_SHIFT;
+ }
+ else if (gain_ctrl->ant == 2) {
+ gain_ctl_shift = RX2_GAIN_CTRL_SHIFT;
+ }
+ else {
+ dev_err(dev, "Unknown Rx path %"PRIu32, gain_ctrl->ant);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = ad9361_en_dis_rx(phy, gain_ctrl->ant, RX_DISABLE);
+ if (rc) {
+ dev_err(dev, "Unable to disable rx%"PRIu32, gain_ctrl->ant);
+ goto out;
+ }
+
+ val &= ~(RX_GAIN_CTL_MASK << gain_ctl_shift);
+ val |= mode << gain_ctl_shift;
+ if (mode == RX_GAIN_CTL_AGC_SLOW_ATK_HYBD)
+ val |= SLOW_ATTACK_HYBRID_MODE;
+ else
+ val &= ~SLOW_ATTACK_HYBRID_MODE;
+
+ rc = ad9361_spi_write(spi, REG_AGC_CONFIG_1, val);
+ if (rc) {
+ dev_err(dev, "Unable to write AGC config1 register: %x",
+ REG_AGC_CONFIG_1);
+ goto out;
+ }
+
+ ad9361_en_dis_rx(phy, gain_ctrl->ant, RX_ENABLE);
+ rc = ad9361_gc_update(phy);
+out:
+ return rc;
+}
+
+/**
+ * Get the RSSI.
+ * @param phy The AD9361 state structure.
+ * @param rssi A rf_rssi struct to store the RSSI.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_read_rssi(struct ad9361_rf_phy *phy, struct rf_rssi *rssi)
+{
+ struct spi_device *spi = phy->spi;
+ uint8_t reg_val_buf[6];
+ int32_t rc;
+
+ rc = ad9361_spi_readm(spi, REG_PREAMBLE_LSB,
+ reg_val_buf, ARRAY_SIZE(reg_val_buf));
+ if (rssi->ant == 1) {
+ rssi->symbol = RSSI_RESOLUTION *
+ ((reg_val_buf[5] << RSSI_LSB_SHIFT) +
+ (reg_val_buf[1] & RSSI_LSB_MASK1));
+ rssi->preamble = RSSI_RESOLUTION *
+ ((reg_val_buf[4] << RSSI_LSB_SHIFT) +
+ (reg_val_buf[0] & RSSI_LSB_MASK1));
+ }
+ else if (rssi->ant == 2) {
+ rssi->symbol = RSSI_RESOLUTION *
+ ((reg_val_buf[3] << RSSI_LSB_SHIFT) +
+ ((reg_val_buf[1] & RSSI_LSB_MASK2) >> 1));
+ rssi->preamble = RSSI_RESOLUTION *
+ ((reg_val_buf[2] << RSSI_LSB_SHIFT) +
+ ((reg_val_buf[0] & RSSI_LSB_MASK2) >> 1));
+ }
+ else
+ rc = -EFAULT;
+
+ rssi->multiplier = RSSI_MULTIPLIER;
+
+ return rc;
+}
+
+/**
+ * Setup the RX ADC.
+ * @param phy The AD9361 state structure.
+ * @param bbpll_freq The BBPLL frequency [Hz].
+ * @param adc_sampl_freq_Hz The ADC sampling frequency [Hz].
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_rx_adc_setup(struct ad9361_rf_phy *phy, uint32_t bbpll_freq,
+ uint32_t adc_sampl_freq_Hz)
+{
+
+ uint32_t scale_snr_1e3, maxsnr, sqrt_inv_rc_tconst_1e3, tmp_1e3,
+ scaled_adc_clk_1e6, inv_scaled_adc_clk_1e3, sqrt_term_1e3,
+ min_sqrt_term_1e3, bb_bw_Hz;
+ uint64_t tmp, invrc_tconst_1e6;
+ uint8_t data[40];
+ uint32_t i;
+ int32_t ret;
+
+ uint8_t c3_msb = ad9361_spi_read(phy->spi, REG_RX_BBF_C3_MSB);
+ uint8_t c3_lsb = ad9361_spi_read(phy->spi, REG_RX_BBF_C3_LSB);
+ uint8_t r2346 = ad9361_spi_read(phy->spi, REG_RX_BBF_R2346);
+
+ /*
+ * BBBW = (BBPLL / RxTuneDiv) * ln(2) / (1.4 * 2PI )
+ * We assume ad9361_rx_bb_analog_filter_calib() is always run prior
+ */
+
+ tmp = bbpll_freq * 10000ULL;
+ do_div(&tmp, 126906UL * phy->rxbbf_div);
+ bb_bw_Hz = tmp;
+
+ dev_dbg(&phy->spi->dev, "%s : BBBW %"PRIu32" : ADCfreq %"PRIu32,
+ __func__, bb_bw_Hz, adc_sampl_freq_Hz);
+
+ dev_dbg(&phy->spi->dev, "c3_msb 0x%X : c3_lsb 0x%X : r2346 0x%X : ",
+ c3_msb, c3_lsb, r2346);
+
+ bb_bw_Hz = clamp(bb_bw_Hz, 200000UL, 28000000UL);
+
+ if (adc_sampl_freq_Hz < 80000000)
+ scale_snr_1e3 = 1000;
+ else
+ scale_snr_1e3 = 1585; /* pow(10, scale_snr_dB/10); */
+
+ if (bb_bw_Hz >= 18000000) {
+ invrc_tconst_1e6 = (160975ULL * r2346 *
+ (160 * c3_msb + 10 * c3_lsb + 140) *
+ (bb_bw_Hz)* (1000 + (10 * (bb_bw_Hz - 18000000) / 1000000)));
+
+ do_div(&invrc_tconst_1e6, 1000UL);
+
+ }
+ else {
+ invrc_tconst_1e6 = (160975ULL * r2346 *
+ (160 * c3_msb + 10 * c3_lsb + 140) *
+ (bb_bw_Hz));
+ }
+
+ do_div(&invrc_tconst_1e6, 1000000000UL);
+
+ if (invrc_tconst_1e6 > ULONG_MAX)
+ dev_err(&phy->spi->dev, "invrc_tconst_1e6 > ULONG_MAX");
+
+ sqrt_inv_rc_tconst_1e3 = int_sqrt((uint32_t)invrc_tconst_1e6);
+ maxsnr = 640 / 160;
+ scaled_adc_clk_1e6 = DIV_ROUND_CLOSEST(adc_sampl_freq_Hz, 640);
+ inv_scaled_adc_clk_1e3 = DIV_ROUND_CLOSEST(640000000,
+ DIV_ROUND_CLOSEST(adc_sampl_freq_Hz, 1000));
+ tmp_1e3 = DIV_ROUND_CLOSEST(980000 + 20 * max_t(uint32_t, 1000U,
+ DIV_ROUND_CLOSEST(inv_scaled_adc_clk_1e3, maxsnr)), 1000);
+ sqrt_term_1e3 = int_sqrt(scaled_adc_clk_1e6);
+ min_sqrt_term_1e3 = min_t(uint32_t, 1000U,
+ int_sqrt(maxsnr * scaled_adc_clk_1e6));
+
+ dev_dbg(&phy->spi->dev, "invrc_tconst_1e6 %"PRIu64", sqrt_inv_rc_tconst_1e3 %"PRIu32,
+ invrc_tconst_1e6, sqrt_inv_rc_tconst_1e3);
+ dev_dbg(&phy->spi->dev, "scaled_adc_clk_1e6 %"PRIu32", inv_scaled_adc_clk_1e3 %"PRIu32,
+ scaled_adc_clk_1e6, inv_scaled_adc_clk_1e3);
+ dev_dbg(&phy->spi->dev, "tmp_1e3 %"PRIu32", sqrt_term_1e3 %"PRIu32", min_sqrt_term_1e3 %"PRIu32,
+ tmp_1e3, sqrt_term_1e3, min_sqrt_term_1e3);
+
+ data[0] = 0;
+ data[1] = 0;
+ data[2] = 0;
+ data[3] = 0x24;
+ data[4] = 0x24;
+ data[5] = 0;
+ data[6] = 0;
+
+ tmp = -50000000 + 8ULL * scale_snr_1e3 * sqrt_inv_rc_tconst_1e3 *
+ min_sqrt_term_1e3;
+ do_div(&tmp, 100000000UL);
+ data[7] = min_t(uint64_t, 124U, tmp);
+
+ tmp = (invrc_tconst_1e6 >> 1) + 20 * inv_scaled_adc_clk_1e3 *
+ data[7] / 80 * 1000ULL;
+ do_div(&tmp, invrc_tconst_1e6);
+ data[8] = min_t(uint64_t, 255U, tmp);
+
+ tmp = (-500000 + 77ULL * sqrt_inv_rc_tconst_1e3 * min_sqrt_term_1e3);
+ do_div(&tmp, 1000000UL);
+ data[10] = min_t(uint64_t, 127U, tmp);
+
+ data[9] = min_t(uint32_t, 127U, ((800 * data[10]) / 1000));
+ tmp = ((invrc_tconst_1e6 >> 1) + (20 * inv_scaled_adc_clk_1e3 *
+ data[10] * 1000ULL));
+ do_div(&tmp, invrc_tconst_1e6 * 77);
+ data[11] = min_t(uint64_t, 255U, tmp);
+ data[12] = min_t(uint32_t, 127U, (-500000 + 80 * sqrt_inv_rc_tconst_1e3 *
+ min_sqrt_term_1e3) / 1000000UL);
+
+ tmp = -3 * (long)(invrc_tconst_1e6 >> 1) + inv_scaled_adc_clk_1e3 *
+ data[12] * (1000ULL * 20 / 80);
+ do_div(&tmp, invrc_tconst_1e6);
+ data[13] = min_t(uint64_t, 255, tmp);
+
+ data[14] = 21 * (inv_scaled_adc_clk_1e3 / 10000);
+ data[15] = min_t(uint32_t, 127U, (500 + 1025 * data[7]) / 1000);
+ data[16] = min_t(uint32_t, 127U, (data[15] * tmp_1e3) / 1000);
+ data[17] = data[15];
+ data[18] = min_t(uint32_t, 127U, (500 + 975 * data[10]) / 1000);
+ data[19] = min_t(uint32_t, 127U, (data[18] * tmp_1e3) / 1000);
+ data[20] = data[18];
+ data[21] = min_t(uint32_t, 127U, (500 + 975 * data[12]) / 1000);
+ data[22] = min_t(uint32_t, 127, (data[21] * tmp_1e3) / 1000);
+ data[23] = data[21];
+ data[24] = 0x2E;
+ data[25] = (128 + min_t(uint32_t, 63000U, DIV_ROUND_CLOSEST(63 *
+ scaled_adc_clk_1e6, 1000)) / 1000);
+ data[26] = min_t(uint32_t, 63U, 63 * scaled_adc_clk_1e6 / 1000000 *
+ (920 + 80 * inv_scaled_adc_clk_1e3 / 1000) / 1000);
+ data[27] = min_t(uint32_t, 63, (32 * sqrt_term_1e3) / 1000);
+ data[28] = data[25];
+ data[29] = data[26];
+ data[30] = data[27];
+ data[31] = data[25];
+ data[32] = data[26];
+ data[33] = min_t(uint32_t, 63U, 63 * sqrt_term_1e3 / 1000);
+ data[34] = min_t(uint32_t, 127U, 64 * sqrt_term_1e3 / 1000);
+ data[35] = 0x40;
+ data[36] = 0x40;
+ data[37] = 0x2C;
+ data[38] = 0x00;
+ data[39] = 0x00;
+
+ for (i = 0; i < 40; i++) {
+ ret = ad9361_spi_write(phy->spi, 0x200 + i, data[i]);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * Perform a RX TIA calibration.
+ * @param phy The AD9361 state structure.
+ * @param bb_bw_Hz The baseband bandwidth [Hz].
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_rx_tia_calib(struct ad9361_rf_phy *phy, uint32_t bb_bw_Hz)
+{
+ uint32_t Cbbf, R2346;
+ uint64_t CTIA_fF;
+
+ uint8_t reg1EB = ad9361_spi_read(phy->spi, REG_RX_BBF_C3_MSB);
+ uint8_t reg1EC = ad9361_spi_read(phy->spi, REG_RX_BBF_C3_LSB);
+ uint8_t reg1E6 = ad9361_spi_read(phy->spi, REG_RX_BBF_R2346);
+ uint8_t reg1DB, reg1DF, reg1DD, reg1DC, reg1DE, temp;
+
+ dev_dbg(&phy->spi->dev, "%s : bb_bw_Hz %"PRIu32,
+ __func__, bb_bw_Hz);
+
+ bb_bw_Hz = clamp(bb_bw_Hz, 200000UL, 20000000UL);
+
+ Cbbf = (reg1EB * 160) + (reg1EC * 10) + 140; /* fF */
+ R2346 = 18300 * RX_BBF_R2346(reg1E6);
+
+ CTIA_fF = Cbbf * R2346 * 560ULL;
+ do_div(&CTIA_fF, 3500000UL);
+
+ if (bb_bw_Hz <= 3000000UL)
+ reg1DB = 0xE0;
+ else if (bb_bw_Hz <= 10000000UL)
+ reg1DB = 0x60;
+ else
+ reg1DB = 0x20;
+
+ if (CTIA_fF > 2920ULL) {
+ reg1DC = 0x40;
+ reg1DE = 0x40;
+ temp = min(127U, DIV_ROUND_CLOSEST((uint32_t)CTIA_fF - 400, 320U));
+ reg1DD = temp;
+ reg1DF = temp;
+ }
+ else {
+ temp = DIV_ROUND_CLOSEST((uint32_t)CTIA_fF - 400, 40U) + 0x40;
+ reg1DC = temp;
+ reg1DE = temp;
+ reg1DD = 0;
+ reg1DF = 0;
+ }
+
+ ad9361_spi_write(phy->spi, REG_RX_TIA_CONFIG, reg1DB);
+ ad9361_spi_write(phy->spi, REG_TIA1_C_LSB, reg1DC);
+ ad9361_spi_write(phy->spi, REG_TIA1_C_MSB, reg1DD);
+ ad9361_spi_write(phy->spi, REG_TIA2_C_LSB, reg1DE);
+ ad9361_spi_write(phy->spi, REG_TIA2_C_MSB, reg1DF);
+
+ return 0;
+}
+
+/**
+ * Perform a baseband RX analog filter calibration.
+ * @param phy The AD9361 state structure.
+ * @param rx_bb_bw The baseband bandwidth [Hz].
+ * @param bbpll_freq The BBPLL frequency [Hz].
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_rx_bb_analog_filter_calib(struct ad9361_rf_phy *phy,
+ uint32_t rx_bb_bw,
+ uint32_t bbpll_freq)
+{
+ uint32_t target;
+ uint8_t tmp;
+ int32_t ret;
+
+ dev_dbg(&phy->spi->dev, "%s : rx_bb_bw %"PRIu32" bbpll_freq %"PRIu32,
+ __func__, rx_bb_bw, bbpll_freq);
+
+ rx_bb_bw = clamp(rx_bb_bw, 200000UL, 28000000UL);
+
+ /* 1.4 * BBBW * 2PI / ln(2) */
+ target = 126906UL * (rx_bb_bw / 10000UL);
+ phy->rxbbf_div = min_t(uint32_t, 511UL, DIV_ROUND_UP(bbpll_freq, target));
+
+ /* Set RX baseband filter divide value */
+ ad9361_spi_write(phy->spi, REG_RX_BBF_TUNE_DIVIDE, phy->rxbbf_div);
+ ad9361_spi_writef(phy->spi, REG_RX_BBF_TUNE_CONFIG, BIT(0), phy->rxbbf_div >> 8);
+
+ /* Write the BBBW into registers 0x1FB and 0x1FC */
+ ad9361_spi_write(phy->spi, REG_RX_BBBW_MHZ, rx_bb_bw / 1000000UL);
+
+ tmp = DIV_ROUND_CLOSEST((rx_bb_bw % 1000000UL) * 128, 1000000UL);
+ ad9361_spi_write(phy->spi, REG_RX_BBBW_KHZ, min_t(uint8_t, 127, tmp));
+
+ ad9361_spi_write(phy->spi, REG_RX_MIX_LO_CM, RX_MIX_LO_CM(0x3F)); /* Set Rx Mix LO CM */
+ ad9361_spi_write(phy->spi, REG_RX_MIX_GM_CONFIG, RX_MIX_GM_PLOAD(3)); /* Set GM common mode */
+
+ /* Enable the RX BBF tune circuit by writing 0x1E2=0x02 and 0x1E3=0x02 */
+ ad9361_spi_write(phy->spi, REG_RX1_TUNE_CTRL, RX1_TUNE_RESAMPLE);
+ ad9361_spi_write(phy->spi, REG_RX2_TUNE_CTRL, RX2_TUNE_RESAMPLE);
+
+ /* Start the RX Baseband Filter calibration in register 0x016[7] */
+ /* Calibration is complete when register 0x016[7] self clears */
+ ret = ad9361_run_calibration(phy, RX_BB_TUNE_CAL);
+
+ /* Disable the RX baseband filter tune circuit, write 0x1E2=3, 0x1E3=3 */
+ ad9361_spi_write(phy->spi, REG_RX1_TUNE_CTRL,
+ RX1_TUNE_RESAMPLE | RX1_PD_TUNE);
+ ad9361_spi_write(phy->spi, REG_RX2_TUNE_CTRL,
+ RX2_TUNE_RESAMPLE | RX2_PD_TUNE);
+
+ return ret;
+}
+
+/**
+ * Perform a baseband TX analog filter calibration.
+ * @param phy The AD9361 state structure.
+ * @param tx_bb_bw The baseband bandwidth [Hz].
+ * @param bbpll_freq The BBPLL frequency [Hz].
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_tx_bb_analog_filter_calib(struct ad9361_rf_phy *phy,
+ uint32_t tx_bb_bw,
+ uint32_t bbpll_freq)
+{
+ uint32_t target, txbbf_div;
+ int32_t ret;
+
+ dev_dbg(&phy->spi->dev, "%s : tx_bb_bw %"PRIu32" bbpll_freq %"PRIu32,
+ __func__, tx_bb_bw, bbpll_freq);
+
+ tx_bb_bw = clamp(tx_bb_bw, 625000UL, 20000000UL);
+
+ /* 1.6 * BBBW * 2PI / ln(2) */
+ target = 145036 * (tx_bb_bw / 10000UL);
+ txbbf_div = min_t(uint32_t, 511UL, DIV_ROUND_UP(bbpll_freq, target));
+
+ /* Set TX baseband filter divide value */
+ ad9361_spi_write(phy->spi, REG_TX_BBF_TUNE_DIVIDER, txbbf_div);
+ ad9361_spi_writef(phy->spi, REG_TX_BBF_TUNE_MODE,
+ TX_BBF_TUNE_DIVIDER, txbbf_div >> 8);
+
+ /* Enable the TX baseband filter tune circuit by setting 0x0CA=0x22. */
+ ad9361_spi_write(phy->spi, REG_TX_TUNE_CTRL, TUNER_RESAMPLE | TUNE_CTRL(1));
+
+ /* Start the TX Baseband Filter calibration in register 0x016[6] */
+ /* Calibration is complete when register 0x016[] self clears */
+ ret = ad9361_run_calibration(phy, TX_BB_TUNE_CAL);
+
+ /* Disable the TX baseband filter tune circuit by writing 0x0CA=0x26. */
+ ad9361_spi_write(phy->spi, REG_TX_TUNE_CTRL,
+ TUNER_RESAMPLE | TUNE_CTRL(1) | PD_TUNE);
+
+ return ret;
+}
+
+/**
+ * Perform a baseband TX secondary filter calibration.
+ * @param phy The AD9361 state structure.
+ * @param tx_rf_bw The RF bandwidth [Hz].
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_tx_bb_second_filter_calib(struct ad9361_rf_phy *phy,
+ uint32_t tx_bb_bw)
+{
+ uint64_t cap;
+ uint32_t corner, res, div;
+ uint32_t reg_conf, reg_res;
+ int32_t ret, i;
+
+ dev_dbg(&phy->spi->dev, "%s : tx_bb_bw %"PRIu32,
+ __func__, tx_bb_bw);
+
+ tx_bb_bw = clamp(tx_bb_bw, 530000UL, 20000000UL);
+
+ /* BBBW * 5PI */
+ corner = 15708 * (tx_bb_bw / 10000UL);
+
+ for (i = 0, res = 1; i < 4; i++) {
+ div = corner * res;
+ cap = (500000000ULL) + (div >> 1);
+ do_div(&cap, div);
+ cap -= 12ULL;
+ if (cap < 64ULL)
+ break;
+
+ res <<= 1;
+ }
+
+ if (cap > 63ULL)
+ cap = 63ULL;
+
+ if (tx_bb_bw <= 4500000UL)
+ reg_conf = 0x59;
+ else if (tx_bb_bw <= 12000000UL)
+ reg_conf = 0x56;
+ else
+ reg_conf = 0x57;
+
+ switch (res) {
+ case 1:
+ reg_res = 0x0C;
+ break;
+ case 2:
+ reg_res = 0x04;
+ break;
+ case 4:
+ reg_res = 0x03;
+ break;
+ case 8:
+ reg_res = 0x01;
+ break;
+ default:
+ reg_res = 0x01;
+ }
+
+ ret = ad9361_spi_write(phy->spi, REG_CONFIG0, reg_conf);
+ ret |= ad9361_spi_write(phy->spi, REG_RESISTOR, reg_res);
+ ret |= ad9361_spi_write(phy->spi, REG_CAPACITOR, (uint8_t)cap);
+
+ return ret;
+}
+
+/**
+ * Perform a RF synthesizer charge pump calibration.
+ * @param phy The AD9361 state structure.
+ * @param ref_clk_hz The reference clock rate [Hz].
+ * @param tx The Synthesizer TX = 1, RX = 0.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_txrx_synth_cp_calib(struct ad9361_rf_phy *phy,
+ uint32_t ref_clk_hz, bool tx)
+{
+ uint32_t offs = tx ? 0x40 : 0;
+ uint32_t vco_cal_cnt;
+ dev_dbg(&phy->spi->dev, "%s : ref_clk_hz %"PRIu32" : is_tx %d",
+ __func__, ref_clk_hz, tx);
+
+ /* REVIST: */
+ ad9361_spi_write(phy->spi, REG_RX_CP_LEVEL_DETECT + offs, 0x17);
+
+ ad9361_spi_write(phy->spi, REG_RX_DSM_SETUP_1 + offs, 0x0);
+
+ ad9361_spi_write(phy->spi, REG_RX_LO_GEN_POWER_MODE + offs, 0x00);
+ ad9361_spi_write(phy->spi, REG_RX_VCO_LDO + offs, 0x0B);
+ ad9361_spi_write(phy->spi, REG_RX_VCO_PD_OVERRIDES + offs, 0x02);
+ ad9361_spi_write(phy->spi, REG_RX_CP_CURRENT + offs, 0x80);
+ ad9361_spi_write(phy->spi, REG_RX_CP_CONFIG + offs, 0x00);
+
+ /* see Table 70 Example Calibration Times for RF VCO Cal */
+ if (phy->pdata->fdd) {
+ vco_cal_cnt = VCO_CAL_EN | VCO_CAL_COUNT(3) | FB_CLOCK_ADV(2);
+ }
+ else {
+ if (ref_clk_hz > 40000000UL)
+ vco_cal_cnt = VCO_CAL_EN | VCO_CAL_COUNT(1) |
+ FB_CLOCK_ADV(2);
+ else
+ vco_cal_cnt = VCO_CAL_EN | VCO_CAL_COUNT(0) |
+ FB_CLOCK_ADV(2);
+ }
+
+ ad9361_spi_write(phy->spi, REG_RX_VCO_CAL + offs, vco_cal_cnt);
+
+ /* Enable FDD mode during calibrations */
+
+ if (!phy->pdata->fdd) {
+ ad9361_spi_writef(phy->spi, REG_PARALLEL_PORT_CONF_3,
+ HALF_DUPLEX_MODE, 0);
+ }
+
+ ad9361_spi_write(phy->spi, REG_ENSM_CONFIG_2, DUAL_SYNTH_MODE);
+ ad9361_spi_write(phy->spi, REG_ENSM_CONFIG_1,
+ FORCE_ALERT_STATE |
+ TO_ALERT);
+ ad9361_spi_write(phy->spi, REG_ENSM_MODE, FDD_MODE);
+
+ ad9361_spi_write(phy->spi, REG_RX_CP_CONFIG + offs, CP_CAL_ENABLE);
+
+ return ad9361_check_cal_done(phy, REG_RX_CAL_STATUS + offs,
+ CP_CAL_VALID, 1);
+}
+
+/**
+ * Perform a baseband DC offset calibration.
+ * @param phy The AD9361 state structure.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_bb_dc_offset_calib(struct ad9361_rf_phy *phy)
+{
+ dev_dbg(&phy->spi->dev, "%s", __func__);
+
+ ad9361_spi_write(phy->spi, REG_BB_DC_OFFSET_COUNT, 0x3F);
+ ad9361_spi_write(phy->spi, REG_BB_DC_OFFSET_SHIFT, BB_DC_M_SHIFT(0xF));
+ ad9361_spi_write(phy->spi, REG_BB_DC_OFFSET_ATTEN, BB_DC_OFFSET_ATTEN(1));
+
+ return ad9361_run_calibration(phy, BBDC_CAL);
+}
+
+/**
+ * Perform a RF DC offset calibration.
+ * @param phy The AD9361 state structure.
+ * @param ref_clk_hz The RX LO frequency [Hz].
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_rf_dc_offset_calib(struct ad9361_rf_phy *phy,
+ uint64_t rx_freq)
+{
+ struct spi_device *spi = phy->spi;
+
+ dev_dbg(&phy->spi->dev, "%s : rx_freq %"PRIu64,
+ __func__, rx_freq);
+
+ ad9361_spi_write(spi, REG_WAIT_COUNT, 0x20);
+
+ if (rx_freq <= 4000000000ULL) {
+ ad9361_spi_write(spi, REG_RF_DC_OFFSET_COUNT,
+ phy->pdata->rf_dc_offset_count_low);
+ ad9361_spi_write(spi, REG_RF_DC_OFFSET_CONFIG_1,
+ RF_DC_CALIBRATION_COUNT(4) | DAC_FS(2));
+ ad9361_spi_write(spi, REG_RF_DC_OFFSET_ATTEN,
+ RF_DC_OFFSET_ATTEN(
+ phy->pdata->dc_offset_attenuation_low));
+ }
+ else {
+ ad9361_spi_write(spi, REG_RF_DC_OFFSET_COUNT,
+ phy->pdata->rf_dc_offset_count_high);
+ ad9361_spi_write(spi, REG_RF_DC_OFFSET_CONFIG_1,
+ RF_DC_CALIBRATION_COUNT(4) | DAC_FS(3));
+ ad9361_spi_write(spi, REG_RF_DC_OFFSET_ATTEN,
+ RF_DC_OFFSET_ATTEN(
+ phy->pdata->dc_offset_attenuation_high));
+ }
+
+ ad9361_spi_write(spi, REG_DC_OFFSET_CONFIG2,
+ USE_WAIT_COUNTER_FOR_RF_DC_INIT_CAL |
+ DC_OFFSET_UPDATE(3));
+
+ if (phy->pdata->rx1rx2_phase_inversion_en ||
+ (phy->pdata->port_ctrl.pp_conf[1] & INVERT_RX2)) {
+ ad9361_spi_write(spi, REG_INVERT_BITS,
+ INVERT_RX1_RF_DC_CGOUT_WORD);
+ } else {
+ ad9361_spi_write(spi, REG_INVERT_BITS,
+ INVERT_RX1_RF_DC_CGOUT_WORD |
+ INVERT_RX2_RF_DC_CGOUT_WORD);
+ }
+
+ return ad9361_run_calibration(phy, RFDC_CAL);
+}
+
+/**
+ * Update RF bandwidth.
+ * @param phy The AD9361 state structure.
+ * @param rf_rx_bw RF RX bandwidth [Hz].
+ * @param rf_tx_bw RF TX bandwidth [Hz].
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t __ad9361_update_rf_bandwidth(struct ad9361_rf_phy *phy,
+ uint32_t rf_rx_bw, uint32_t rf_tx_bw)
+{
+ uint32_t real_rx_bandwidth = rf_rx_bw / 2;
+ uint32_t real_tx_bandwidth = rf_tx_bw / 2;
+ uint32_t bbpll_freq;
+ int32_t ret;
+
+ dev_dbg(&phy->spi->dev, "%s: %"PRIu32" %"PRIu32,
+ __func__, rf_rx_bw, rf_tx_bw);
+
+ bbpll_freq = clk_get_rate(phy, phy->ref_clk_scale[BBPLL_CLK]);
+
+ ret = ad9361_rx_bb_analog_filter_calib(phy,
+ real_rx_bandwidth,
+ bbpll_freq);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9361_tx_bb_analog_filter_calib(phy,
+ real_tx_bandwidth,
+ bbpll_freq);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9361_rx_tia_calib(phy, real_rx_bandwidth);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9361_tx_bb_second_filter_calib(phy, real_tx_bandwidth);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9361_rx_adc_setup(phy,
+ bbpll_freq,
+ clk_get_rate(phy, phy->ref_clk_scale[ADC_CLK]));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/**
+ * TX Quad Calib.
+ * @param phy The AD9361 state structure.
+ * @param phase phase
+ * @param rxnco_word Rx NCO word.
+ * @param decim decim
+ * @param res res
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t __ad9361_tx_quad_calib(struct ad9361_rf_phy *phy, uint32_t phase,
+ uint32_t rxnco_word, uint32_t decim, uint8_t *res)
+{
+ int32_t ret;
+
+ ad9361_spi_write(phy->spi, REG_QUAD_CAL_NCO_FREQ_PHASE_OFFSET,
+ RX_NCO_FREQ(rxnco_word) | RX_NCO_PHASE_OFFSET(phase));
+ ad9361_spi_write(phy->spi, REG_QUAD_CAL_CTRL,
+ SETTLE_MAIN_ENABLE | DC_OFFSET_ENABLE | QUAD_CAL_SOFT_RESET |
+ GAIN_ENABLE | PHASE_ENABLE | M_DECIM(decim));
+ ad9361_spi_write(phy->spi, REG_QUAD_CAL_CTRL,
+ SETTLE_MAIN_ENABLE | DC_OFFSET_ENABLE |
+ GAIN_ENABLE | PHASE_ENABLE | M_DECIM(decim));
+
+ ret = ad9361_run_calibration(phy, TX_QUAD_CAL);
+ if (ret < 0)
+ return ret;
+
+ if (res)
+ *res = ad9361_spi_read(phy->spi,
+ (phy->pdata->rx1tx1_mode_use_tx_num == 2) ?
+ REG_QUAD_CAL_STATUS_TX2 : REG_QUAD_CAL_STATUS_TX1) &
+ (TX1_LO_CONV | TX1_SSB_CONV);
+
+ return 0;
+}
+
+/**
+ * Loop through all possible phase offsets in case the QUAD CAL doesn't converge.
+ * @param phy The AD9361 state structure.
+ * @param rxnco_word Rx NCO word.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_tx_quad_phase_search(struct ad9361_rf_phy *phy, uint32_t rxnco_word, uint8_t decim)
+{
+ int32_t i, ret;
+ uint8_t field[64], val;
+ uint32_t start;
+
+ dev_dbg(&phy->spi->dev, "%s", __func__);
+
+ for (i = 0; i < (int64_t)(ARRAY_SIZE(field) / 2); i++) {
+ ret = __ad9361_tx_quad_calib(phy, i, rxnco_word, decim, &val);
+ if (ret < 0)
+ return ret;
+
+ /* Handle 360/0 wrap around */
+ field[i] = field[i + 32] = !((val & TX1_LO_CONV) && (val & TX1_SSB_CONV));
+ }
+
+ ret = ad9361_find_opt(field, ARRAY_SIZE(field), &start);
+
+ phy->last_tx_quad_cal_phase = (start + ret / 2) & 0x1F;
+
+#ifdef _DEBUG
+ for (i = 0; i < 64; i++) {
+ printk("%c", (field[i] ? '#' : 'o'));
+ }
+#ifdef WIN32
+ printk(" RX_NCO_PHASE_OFFSET(%d, 0x%X) \n", phy->last_tx_quad_cal_phase,
+ phy->last_tx_quad_cal_phase);
+#else
+ printk(" RX_NCO_PHASE_OFFSET(%"PRIu32", 0x%"PRIX32") \n", phy->last_tx_quad_cal_phase,
+ phy->last_tx_quad_cal_phase);
+#endif
+#endif
+
+ ret = __ad9361_tx_quad_calib(phy, phy->last_tx_quad_cal_phase, rxnco_word, decim, NULL);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/**
+ * Perform a TX quadrature calibration.
+ * @param phy The AD9361 state structure.
+ * @param bw The bandwidth [Hz].
+ * @param rx_phase The optional RX phase value overwrite (set to zero).
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_tx_quad_calib(struct ad9361_rf_phy *phy,
+ uint32_t bw_rx, uint32_t bw_tx,
+ int32_t rx_phase)
+{
+ struct spi_device *spi = phy->spi;
+ uint32_t clktf, clkrf;
+ int32_t txnco_word, rxnco_word, txnco_freq, ret;
+ uint8_t __rx_phase = 0, reg_inv_bits = 0, val, decim;
+ const uint8_t(*tab)[3];
+ uint32_t index_max, i, lpf_tia_mask;
+
+ /*
+ * Find NCO frequency that matches this equation:
+ * BW / 4 = Rx NCO freq = Tx NCO freq:
+ * Rx NCO = ClkRF * (rxNCO <1:0> + 1) / 32
+ * Tx NCO = ClkTF * (txNCO <1:0> + 1) / 32
+ */
+
+ clkrf = clk_get_rate(phy, phy->ref_clk_scale[CLKRF_CLK]);
+ clktf = clk_get_rate(phy, phy->ref_clk_scale[CLKTF_CLK]);
+
+ dev_dbg(&phy->spi->dev, "%s : bw_tx %"PRIu32" clkrf %"PRIu32" clktf %"PRIu32,
+ __func__, bw_tx, clkrf, clktf);
+
+ txnco_word = DIV_ROUND_CLOSEST(bw_tx * 8, clktf) - 1;
+ txnco_word = clamp_t(int, txnco_word, 0, 3);
+ rxnco_word = txnco_word;
+
+ dev_dbg(dev, "Tx NCO frequency: %"PRIu32" (BW/4: %"PRIu32") txnco_word %"PRId32,
+ clktf * (txnco_word + 1) / 32, bw_tx / 4, txnco_word);
+
+ if (clktf <= 4000000UL)
+ decim = 2;
+ else
+ decim = 3;
+
+ if (clkrf == (2 * clktf)) {
+ __rx_phase = 0x0E;
+ switch (txnco_word) {
+ case 0:
+ txnco_word++;
+ break;
+ case 1:
+ rxnco_word--;
+ break;
+ case 2:
+ rxnco_word -= 2;
+ txnco_word--;
+ break;
+ case 3:
+ rxnco_word -= 2; /* REVISIT */
+ __rx_phase = 0x08;
+ break;
+ }
+ }
+ else if (clkrf == clktf) {
+ switch (txnco_word) {
+ case 0:
+ case 3:
+ __rx_phase = 0x15;
+ break;
+ case 2:
+ __rx_phase = 0x1F;
+ break;
+ case 1:
+ if (ad9361_spi_readf(spi,
+ REG_TX_ENABLE_FILTER_CTRL, 0x3F) == 0x22)
+ __rx_phase = 0x15; /* REVISIT */
+ else
+ __rx_phase = 0x1A;
+ break;
+ }
+ }
+ else
+ dev_err(dev, "Unhandled case in %s line %d clkrf %"PRIu32" clktf %"PRIu32,
+ __func__, __LINE__, clkrf, clktf);
+
+
+ if (rx_phase >= 0)
+ __rx_phase = rx_phase;
+
+ txnco_freq = clktf * (txnco_word + 1) / 32;
+
+ if (txnco_freq > (int64_t)(bw_rx / 4) || txnco_freq > (int64_t)(bw_tx / 4)) {
+ /* Make sure the BW during calibration is wide enough */
+ ret = __ad9361_update_rf_bandwidth(phy, txnco_freq * 8, txnco_freq * 8);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (phy->pdata->rx1rx2_phase_inversion_en ||
+ (phy->pdata->port_ctrl.pp_conf[1] & INVERT_RX2)) {
+
+ ad9361_spi_writef(spi, REG_PARALLEL_PORT_CONF_2, INVERT_RX2, 0);
+
+ reg_inv_bits = ad9361_spi_read(spi, REG_INVERT_BITS);
+
+ ad9361_spi_write(spi, REG_INVERT_BITS,
+ INVERT_RX1_RF_DC_CGOUT_WORD |
+ INVERT_RX2_RF_DC_CGOUT_WORD);
+ }
+
+ ad9361_spi_writef(spi, REG_KEXP_2, TX_NCO_FREQ(~0), txnco_word);
+ ad9361_spi_write(spi, REG_QUAD_CAL_COUNT, 0xFF);
+ ad9361_spi_write(spi, REG_KEXP_1, KEXP_TX(1) | KEXP_TX_COMP(3) |
+ KEXP_DC_I(3) | KEXP_DC_Q(3));
+ ad9361_spi_write(spi, REG_MAG_FTEST_THRESH, 0x01);
+ ad9361_spi_write(spi, REG_MAG_FTEST_THRESH_2, 0x01);
+
+ if (has_split_gt && phy->pdata->split_gt) {
+ tab = &split_gain_table[phy->current_table][0];
+ index_max = SIZE_SPLIT_TABLE;
+ lpf_tia_mask = 0x20;
+ }
+ else {
+ tab = &full_gain_table[phy->current_table][0];
+ index_max = SIZE_FULL_TABLE;
+ lpf_tia_mask = 0x3F;
+ }
+
+ for (i = 0; i < index_max; i++)
+ if ((tab[i][1] & lpf_tia_mask) == 0x20) {
+ ad9361_spi_write(spi, REG_TX_QUAD_FULL_LMT_GAIN, i);
+ break;
+ }
+
+ if (i >= index_max)
+ dev_err(dev, "failed to find suitable LPF TIA value in gain table");
+
+ ad9361_spi_write(spi, REG_QUAD_SETTLE_COUNT, 0xF0);
+ ad9361_spi_write(spi, REG_TX_QUAD_LPF_GAIN, 0x00);
+
+ ret = __ad9361_tx_quad_calib(phy, __rx_phase, rxnco_word, decim, &val);
+
+ dev_dbg(dev, "LO leakage: %d Quadrature Calibration: %d : rx_phase %d",
+ !!(val & TX1_LO_CONV), !!(val & TX1_SSB_CONV), __rx_phase);
+
+ /* Calibration failed -> try last phase offset */
+ if (val != (TX1_LO_CONV | TX1_SSB_CONV)) {
+ if (phy->last_tx_quad_cal_phase < 31)
+ ret = __ad9361_tx_quad_calib(phy, phy->last_tx_quad_cal_phase,
+ rxnco_word, decim, &val);
+ } else {
+ phy->last_tx_quad_cal_phase = __rx_phase;
+ }
+
+ /* Calibration failed -> loop through all 32 phase offsets */
+ if (val != (TX1_LO_CONV | TX1_SSB_CONV))
+ ret = ad9361_tx_quad_phase_search(phy, rxnco_word, decim);
+
+ if (phy->pdata->rx1rx2_phase_inversion_en ||
+ (phy->pdata->port_ctrl.pp_conf[1] & INVERT_RX2)) {
+ ad9361_spi_writef(spi, REG_PARALLEL_PORT_CONF_2, INVERT_RX2, 1);
+ ad9361_spi_write(spi, REG_INVERT_BITS, reg_inv_bits);
+ }
+
+ if (phy->pdata->rx1rx2_phase_inversion_en ||
+ (phy->pdata->port_ctrl.pp_conf[1] & INVERT_RX2)) {
+ ad9361_spi_writef(spi, REG_PARALLEL_PORT_CONF_2, INVERT_RX2, 1);
+ ad9361_spi_write(spi, REG_INVERT_BITS, reg_inv_bits);
+ }
+
+ if (txnco_freq > (int64_t)(bw_rx / 4) || txnco_freq > (int64_t)(bw_tx / 4)) {
+ __ad9361_update_rf_bandwidth(phy,
+ phy->current_rx_bw_Hz,
+ phy->current_tx_bw_Hz);
+ }
+
+ return ret;
+}
+
+/**
+ * Setup RX tracking calibrations.
+ * @param phy The AD9361 state structure.
+ * @param bbdc_track Set true, will enable the BBDC tracking.
+ * @param rfdc_track Set true, will enable the RFDC tracking.
+ * @param rxquad_track Set true, will enable the RXQUAD tracking.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_tracking_control(struct ad9361_rf_phy *phy, bool bbdc_track,
+ bool rfdc_track, bool rxquad_track)
+{
+ struct spi_device *spi = phy->spi;
+ uint32_t qtrack = 0;
+
+ dev_dbg(&spi->dev, "%s : bbdc_track=%d, rfdc_track=%d, rxquad_track=%d",
+ __func__, bbdc_track, rfdc_track, rxquad_track);
+
+ ad9361_spi_write(spi, REG_CALIBRATION_CONFIG_2,
+ CALIBRATION_CONFIG2_DFLT | K_EXP_PHASE(0x15));
+ ad9361_spi_write(spi, REG_CALIBRATION_CONFIG_3,
+ PREVENT_POS_LOOP_GAIN | K_EXP_AMPLITUDE(0x15));
+
+ ad9361_spi_write(spi, REG_DC_OFFSET_CONFIG2,
+ USE_WAIT_COUNTER_FOR_RF_DC_INIT_CAL |
+ DC_OFFSET_UPDATE(phy->pdata->dc_offset_update_events) |
+ (bbdc_track ? ENABLE_BB_DC_OFFSET_TRACKING : 0) |
+ (rfdc_track ? ENABLE_RF_OFFSET_TRACKING : 0));
+
+ ad9361_spi_writef(spi, REG_RX_QUAD_GAIN2,
+ CORRECTION_WORD_DECIMATION_M(~0),
+ phy->pdata->qec_tracking_slow_mode_en ? 4 : 0);
+
+ if (rxquad_track) {
+ if (phy->pdata->rx2tx2)
+ qtrack = ENABLE_TRACKING_MODE_CH1 | ENABLE_TRACKING_MODE_CH2;
+ else
+ qtrack = (phy->pdata->rx1tx1_mode_use_rx_num == 1) ?
+ ENABLE_TRACKING_MODE_CH1 : ENABLE_TRACKING_MODE_CH2;
+ }
+
+ ad9361_spi_write(spi, REG_CALIBRATION_CONFIG_1,
+ ENABLE_PHASE_CORR | ENABLE_GAIN_CORR |
+ FREE_RUN_MODE | ENABLE_CORR_WORD_DECIMATION |
+ qtrack);
+
+ return 0;
+}
+
+/**
+ * Enable/disable the VCO cal.
+ * @param phy The AD9361 state structure.
+ * @param rx Set true for rx.
+ * @param enable Set true to enable.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_trx_vco_cal_control(struct ad9361_rf_phy *phy,
+ bool tx, bool enable)
+{
+ dev_dbg(&phy->spi->dev, "%s : state %d",
+ __func__, enable);
+
+ return ad9361_spi_writef(phy->spi,
+ tx ? REG_TX_PFD_CONFIG : REG_RX_PFD_CONFIG,
+ BYPASS_LD_SYNTH, !enable);
+}
+
+/**
+ * Enable/disable the ext. LO.
+ * @param phy The AD9361 state structure.
+ * @param rx Set true for rx.
+ * @param enable Set true to enable.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_trx_ext_lo_control(struct ad9361_rf_phy *phy,
+ bool tx, bool enable)
+{
+ int32_t val = enable ? ~0 : 0;
+ int32_t ret;
+
+ /* REVIST:
+ * POWER_DOWN_TRX_SYNTH and MCS_RF_ENABLE somehow conflict
+ */
+
+ bool mcs_rf_enable = ad9361_spi_readf(phy->spi,
+ REG_MULTICHIP_SYNC_AND_TX_MON_CTRL, MCS_RF_ENABLE);
+
+ dev_dbg(&phy->spi->dev, "%s : %s state %d",
+ __func__, tx ? "TX" : "RX", enable);
+
+ if (tx) {
+ ret = ad9361_spi_writef(phy->spi, REG_ENSM_CONFIG_2,
+ POWER_DOWN_TX_SYNTH, mcs_rf_enable ? 0 : enable);
+
+ ret |= ad9361_spi_writef(phy->spi, REG_RFPLL_DIVIDERS,
+ TX_VCO_DIVIDER(~0), enable ? 7 :
+ phy->cached_tx_rfpll_div);
+
+ ret |= ad9361_spi_write(phy->spi, REG_TX_SYNTH_POWER_DOWN_OVERRIDE,
+ enable ? TX_SYNTH_VCO_ALC_POWER_DOWN |
+ TX_SYNTH_PTAT_POWER_DOWN |
+ TX_SYNTH_VCO_POWER_DOWN : 0);
+
+ ret |= ad9361_spi_writef(phy->spi, REG_ANALOG_POWER_DOWN_OVERRIDE,
+ TX_EXT_VCO_BUFFER_POWER_DOWN, !enable);
+
+ ret |= ad9361_spi_write(phy->spi, REG_TX_LO_GEN_POWER_MODE,
+ TX_LO_GEN_POWER_MODE(val));
+ }
+ else {
+ ret = ad9361_spi_writef(phy->spi, REG_ENSM_CONFIG_2,
+ POWER_DOWN_RX_SYNTH, mcs_rf_enable ? 0 : enable);
+
+ ret |= ad9361_spi_writef(phy->spi, REG_RFPLL_DIVIDERS,
+ RX_VCO_DIVIDER(~0), enable ? 7 :
+ phy->cached_rx_rfpll_div);
+
+ ret |= ad9361_spi_write(phy->spi, REG_RX_SYNTH_POWER_DOWN_OVERRIDE,
+ enable ? RX_SYNTH_VCO_ALC_POWER_DOWN |
+ RX_SYNTH_PTAT_POWER_DOWN |
+ RX_SYNTH_VCO_POWER_DOWN : 0);
+
+ ret |= ad9361_spi_writef(phy->spi, REG_ANALOG_POWER_DOWN_OVERRIDE,
+ RX_EXT_VCO_BUFFER_POWER_DOWN, !enable);
+
+ ret |= ad9361_spi_write(phy->spi, REG_RX_LO_GEN_POWER_MODE,
+ RX_LO_GEN_POWER_MODE(val));
+ }
+
+ return ret;
+}
+
+/**
+ * Setup the reference clock delay unit counter register.
+ * @param phy The AD9361 state structure.
+ * @param ref_clk_hz The reference clock frequency [Hz].
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_set_ref_clk_cycles(struct ad9361_rf_phy *phy,
+ uint32_t ref_clk_hz)
+{
+ dev_dbg(&phy->spi->dev, "%s : ref_clk_hz %"PRIu32,
+ __func__, ref_clk_hz);
+
+ return ad9361_spi_write(phy->spi, REG_REFERENCE_CLOCK_CYCLES,
+ REFERENCE_CLOCK_CYCLES_PER_US((ref_clk_hz / 1000000UL) - 1));
+}
+
+/**
+ * Setup the DCXO tune.
+ * @param phy The AD9361 state structure.
+ * @param coarse The DCXO tune coarse.
+ * @param fine The DCXO tune fine.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_set_dcxo_tune(struct ad9361_rf_phy *phy,
+ uint32_t coarse, uint32_t fine)
+{
+ dev_dbg(&phy->spi->dev, "%s : coarse %"PRIu32" fine %"PRIu32,
+ __func__, coarse, fine);
+
+ ad9361_spi_write(phy->spi, REG_DCXO_COARSE_TUNE,
+ DCXO_TUNE_COARSE(coarse));
+ ad9361_spi_write(phy->spi, REG_DCXO_FINE_TUNE_LOW,
+ DCXO_TUNE_FINE_LOW(fine));
+ return ad9361_spi_write(phy->spi, REG_DCXO_FINE_TUNE_HIGH,
+ DCXO_TUNE_FINE_HIGH(fine));
+}
+
+/**
+ * Setup TXMON.
+ * @param phy The AD9361 state structure.
+ * @param ctrl The TXMON settings.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_txmon_setup(struct ad9361_rf_phy *phy,
+ struct tx_monitor_control *ctrl)
+{
+ struct spi_device *spi = phy->spi;
+
+ dev_dbg(&phy->spi->dev, "%s", __func__);
+
+ ad9361_spi_write(spi, REG_TPM_MODE_ENABLE,
+ (ctrl->one_shot_mode_en ? ONE_SHOT_MODE : 0) |
+ TX_MON_DURATION(ilog2(ctrl->tx_mon_duration / 16)));
+
+ ad9361_spi_write(spi, REG_TX_MON_DELAY, ctrl->tx_mon_delay);
+
+ ad9361_spi_write(spi, REG_TX_MON_1_CONFIG,
+ TX_MON_1_LO_CM(ctrl->tx1_mon_lo_cm) |
+ TX_MON_1_GAIN(ctrl->tx1_mon_front_end_gain));
+ ad9361_spi_write(spi, REG_TX_MON_2_CONFIG,
+ TX_MON_2_LO_CM(ctrl->tx2_mon_lo_cm) |
+ TX_MON_2_GAIN(ctrl->tx2_mon_front_end_gain));
+
+ ad9361_spi_write(spi, REG_TX_ATTEN_THRESH,
+ ctrl->low_high_gain_threshold_mdB / 250);
+
+ ad9361_spi_write(spi, REG_TX_MON_HIGH_GAIN,
+ TX_MON_HIGH_GAIN(ctrl->high_gain_dB));
+
+ ad9361_spi_write(spi, REG_TX_MON_LOW_GAIN,
+ (ctrl->tx_mon_track_en ? TX_MON_TRACK : 0) |
+ TX_MON_LOW_GAIN(ctrl->low_gain_dB));
+
+ return 0;
+}
+
+/**
+ * Enable TXMON.
+ * @param phy The AD9361 state structure.
+ * @param en_mask The enable mask.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_txmon_control(struct ad9361_rf_phy *phy,
+ int32_t en_mask)
+{
+ dev_dbg(&phy->spi->dev, "%s: mask 0x%"PRIx32, __func__, en_mask);
+
+#if 0
+ if (!phy->pdata->fdd && en_mask) {
+ ad9361_spi_writef(phy->spi, REG_ENSM_CONFIG_1,
+ ENABLE_RX_DATA_PORT_FOR_CAL, 1);
+ phy->txmon_tdd_en = true;
+ } else {
+ ad9361_spi_writef(phy->spi, REG_ENSM_CONFIG_1,
+ ENABLE_RX_DATA_PORT_FOR_CAL, 0);
+ phy->txmon_tdd_en = false;
+ }
+#endif
+
+ ad9361_spi_writef(phy->spi, REG_ANALOG_POWER_DOWN_OVERRIDE,
+ TX_MONITOR_POWER_DOWN(~0), ~en_mask);
+
+ ad9361_spi_writef(phy->spi, REG_TPM_MODE_ENABLE,
+ TX1_MON_ENABLE, !!(en_mask & TX_1));
+
+ return ad9361_spi_writef(phy->spi, REG_TPM_MODE_ENABLE,
+ TX2_MON_ENABLE, !!(en_mask & TX_2));
+}
+
+/**
+* Setup the RF port.
+* Note:
+* val
+* 0 (RX1A_N & RX1A_P) and (RX2A_N & RX2A_P) enabled; balanced
+* 1 (RX1B_N & RX1B_P) and (RX2B_N & RX2B_P) enabled; balanced
+* 2 (RX1C_N & RX1C_P) and (RX2C_N & RX2C_P) enabled; balanced
+*
+* 3 RX1A_N and RX2A_N enabled; unbalanced
+* 4 RX1A_P and RX2A_P enabled; unbalanced
+* 5 RX1B_N and RX2B_N enabled; unbalanced
+* 6 RX1B_P and RX2B_P enabled; unbalanced
+* 7 RX1C_N and RX2C_N enabled; unbalanced
+* 8 RX1C_P and RX2C_P enabled; unbalanced
+* 9 TX_MON1
+* 10 TX_MON2
+* 11 TX_MON1 & TX_MON2
+* @param phy The AD9361 state structure.
+* @param rx_inputs RX input option identifier
+* @param txb TX output option identifier
+* @return 0 in case of success, negative error code otherwise.
+*/
+int32_t ad9361_rf_port_setup(struct ad9361_rf_phy *phy, bool is_out,
+ uint32_t rx_inputs, uint32_t txb)
+{
+ uint32_t val;
+
+ if (rx_inputs > 11)
+ return -EINVAL;
+
+ if (!is_out) {
+ if (rx_inputs > 8)
+ return ad9361_txmon_control(phy, rx_inputs & (TX_1 | TX_2));
+ else
+ ad9361_txmon_control(phy, 0);
+ }
+
+ if (rx_inputs < 3)
+ val = 3 << (rx_inputs * 2);
+ else
+ val = 1 << (rx_inputs - 3);
+
+ if (txb)
+ val |= TX_OUTPUT; /* Select TX1B, TX2B */
+
+ dev_dbg(&phy->spi->dev, "%s : INPUT_SELECT 0x%"PRIx32,
+ __func__, val);
+
+ return ad9361_spi_write(phy->spi, REG_INPUT_SELECT, val);
+}
+
+/**
+ * Setup the Parallel Port (Digital Data Interface).
+ * @param phy The AD9361 state structure.
+ * @param restore_c3 Set true, will restore the Parallel Port Configuration 3
+ * register.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_pp_port_setup(struct ad9361_rf_phy *phy, bool restore_c3)
+{
+ struct spi_device *spi = phy->spi;
+ struct ad9361_phy_platform_data *pd = phy->pdata;
+
+ dev_dbg(&phy->spi->dev, "%s", __func__);
+
+ if (restore_c3) {
+ return ad9361_spi_write(spi, REG_PARALLEL_PORT_CONF_3,
+ pd->port_ctrl.pp_conf[2]);
+ }
+
+ /* Sanity check */
+ if (pd->port_ctrl.pp_conf[2] & LVDS_MODE)
+ pd->port_ctrl.pp_conf[2] &=
+ ~(HALF_DUPLEX_MODE | SINGLE_DATA_RATE | SINGLE_PORT_MODE);
+
+ if (pd->port_ctrl.pp_conf[2] & FULL_PORT)
+ pd->port_ctrl.pp_conf[2] &= ~(HALF_DUPLEX_MODE | SINGLE_PORT_MODE);
+
+ ad9361_spi_write(spi, REG_PARALLEL_PORT_CONF_1, pd->port_ctrl.pp_conf[0]);
+ ad9361_spi_write(spi, REG_PARALLEL_PORT_CONF_2, pd->port_ctrl.pp_conf[1]);
+ ad9361_spi_write(spi, REG_PARALLEL_PORT_CONF_3, pd->port_ctrl.pp_conf[2]);
+ ad9361_spi_write(spi, REG_RX_CLOCK_DATA_DELAY, pd->port_ctrl.rx_clk_data_delay);
+ ad9361_spi_write(spi, REG_TX_CLOCK_DATA_DELAY, pd->port_ctrl.tx_clk_data_delay);
+
+#ifdef NUAND_MODIFICATIONS
+ // set up digital interface slew and drive strength
+ ad9361_spi_write(spi, REG_LVDS_BIAS_CTRL, pd->port_ctrl.lvds_bias_ctrl | CLK_OUT_SLEW(pd->port_ctrl.clk_out_slew));
+ ad9361_spi_write(spi, REG_DIGITAL_IO_CTRL, DATACLK_SLEW(pd->port_ctrl.dataclk_slew) | DATA_PORT_SLEW(pd->port_ctrl.data_port_slew));
+ ad9361_spi_writef(spi, REG_DIGITAL_IO_CTRL, DATACLK_DRIVE, pd->port_ctrl.dataclk_drive);
+ ad9361_spi_writef(spi, REG_DIGITAL_IO_CTRL, DATA_PORT_DRIVE, pd->port_ctrl.data_port_drive);
+ ad9361_spi_writef(spi, REG_DIGITAL_IO_CTRL, CLK_OUT_DRIVE, pd->port_ctrl.clk_out_drive);
+#else
+ ad9361_spi_write(spi, REG_LVDS_BIAS_CTRL, pd->port_ctrl.lvds_bias_ctrl);
+#endif // NUAND_MODIFICATIONS
+
+ // ad9361_spi_write(spi, REG_DIGITAL_IO_CTRL, pd->port_ctrl.digital_io_ctrl);
+ ad9361_spi_write(spi, REG_LVDS_INVERT_CTRL1, pd->port_ctrl.lvds_invert[0]);
+ ad9361_spi_write(spi, REG_LVDS_INVERT_CTRL2, pd->port_ctrl.lvds_invert[1]);
+
+ if (pd->rx1rx2_phase_inversion_en ||
+ (pd->port_ctrl.pp_conf[1] & INVERT_RX2)) {
+
+ ad9361_spi_writef(spi, REG_PARALLEL_PORT_CONF_2, INVERT_RX2, 1);
+ ad9361_spi_writef(spi, REG_INVERT_BITS,
+ INVERT_RX2_RF_DC_CGOUT_WORD, 0);
+ }
+
+ return 0;
+}
+
+/**
+ * Setup the Gain Control Blocks (common function for MGC, AGC modes)
+ * @param phy The AD9361 state structure.
+ * @param ctrl The gain control settings.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_gc_setup(struct ad9361_rf_phy *phy, struct gain_control *ctrl)
+{
+ struct spi_device *spi = phy->spi;
+ uint32_t reg, tmp1, tmp2;
+
+ dev_dbg(&phy->spi->dev, "%s", __func__);
+
+ reg = DEC_PWR_FOR_GAIN_LOCK_EXIT | DEC_PWR_FOR_LOCK_LEVEL |
+ DEC_PWR_FOR_LOW_PWR;
+
+ if (ctrl->rx1_mode == RF_GAIN_HYBRID_AGC ||
+ ctrl->rx2_mode == RF_GAIN_HYBRID_AGC)
+ reg |= SLOW_ATTACK_HYBRID_MODE;
+
+ reg |= RX1_GAIN_CTRL_SETUP(ctrl->rx1_mode) |
+ RX2_GAIN_CTRL_SETUP(ctrl->rx2_mode);
+
+ phy->agc_mode[0] = ctrl->rx1_mode;
+ phy->agc_mode[1] = ctrl->rx2_mode;
+
+ ad9361_spi_write(spi, REG_AGC_CONFIG_1, reg); // Gain Control Mode Select
+
+ /* AGC_USE_FULL_GAIN_TABLE handled in ad9361_load_gt() */
+ ad9361_spi_writef(spi, REG_AGC_CONFIG_2, MAN_GAIN_CTRL_RX1,
+ ctrl->mgc_rx1_ctrl_inp_en);
+ ad9361_spi_writef(spi, REG_AGC_CONFIG_2, MAN_GAIN_CTRL_RX2,
+ ctrl->mgc_rx2_ctrl_inp_en);
+ ad9361_spi_writef(spi, REG_AGC_CONFIG_2, DIG_GAIN_EN,
+ ctrl->dig_gain_en);
+
+ ctrl->adc_ovr_sample_size = clamp_t(uint8_t, ctrl->adc_ovr_sample_size, 1U, 8U);
+ reg = ADC_OVERRANGE_SAMPLE_SIZE(ctrl->adc_ovr_sample_size - 1);
+
+ if (has_split_gt && phy->pdata->split_gt &&
+ (ctrl->mgc_rx1_ctrl_inp_en || ctrl->mgc_rx2_ctrl_inp_en)) {
+ switch (ctrl->mgc_split_table_ctrl_inp_gain_mode) {
+ case 1:
+ reg &= ~INCDEC_LMT_GAIN;
+ break;
+ case 2:
+ reg |= INCDEC_LMT_GAIN;
+ break;
+ default:
+ case 0:
+ reg |= USE_AGC_FOR_LMTLPF_GAIN;
+ break;
+ }
+ }
+
+ ctrl->mgc_inc_gain_step = clamp_t(uint8_t, ctrl->mgc_inc_gain_step, 1U, 8U);
+ reg |= MANUAL_INCR_STEP_SIZE(ctrl->mgc_inc_gain_step - 1);
+ ad9361_spi_write(spi, REG_AGC_CONFIG_3, reg); // Incr Step Size, ADC Overrange Size
+
+ if (has_split_gt && phy->pdata->split_gt) {
+ reg = SIZE_SPLIT_TABLE - 1;
+ }
+ else {
+ reg = SIZE_FULL_TABLE - 1;
+ }
+ ad9361_spi_write(spi, REG_MAX_LMT_FULL_GAIN, reg); // Max Full/LMT Gain Table Index
+ ad9361_spi_write(spi, REG_RX1_MANUAL_LMT_FULL_GAIN, reg); // Rx1 Full/LMT Gain Index
+ ad9361_spi_write(spi, REG_RX2_MANUAL_LMT_FULL_GAIN, reg); // Rx2 Full/LMT Gain Index
+
+ ctrl->mgc_dec_gain_step = clamp_t(uint8_t, ctrl->mgc_dec_gain_step, 1U, 8U);
+ reg = MANUAL_CTRL_IN_DECR_GAIN_STP_SIZE(ctrl->mgc_dec_gain_step);
+ ad9361_spi_write(spi, REG_PEAK_WAIT_TIME, reg); // Decr Step Size, Peak Overload Time
+
+ if (ctrl->dig_gain_en)
+ ad9361_spi_write(spi, REG_DIGITAL_GAIN,
+ MAXIMUM_DIGITAL_GAIN(ctrl->max_dig_gain) |
+ DIG_GAIN_STP_SIZE(ctrl->dig_gain_step_size));
+
+ if (ctrl->adc_large_overload_thresh >= ctrl->adc_small_overload_thresh) {
+ ad9361_spi_write(spi, REG_ADC_SMALL_OVERLOAD_THRESH,
+ ctrl->adc_small_overload_thresh); // ADC Small Overload Threshold
+ ad9361_spi_write(spi, REG_ADC_LARGE_OVERLOAD_THRESH,
+ ctrl->adc_large_overload_thresh); // ADC Large Overload Threshold
+ }
+ else {
+ ad9361_spi_write(spi, REG_ADC_SMALL_OVERLOAD_THRESH,
+ ctrl->adc_large_overload_thresh); // ADC Small Overload Threshold
+ ad9361_spi_write(spi, REG_ADC_LARGE_OVERLOAD_THRESH,
+ ctrl->adc_small_overload_thresh); // ADC Large Overload Threshold
+ }
+
+ reg = (ctrl->lmt_overload_high_thresh / 16) - 1;
+ reg = clamp(reg, 0U, 63U);
+ ad9361_spi_write(spi, REG_LARGE_LMT_OVERLOAD_THRESH, reg);
+ reg = (ctrl->lmt_overload_low_thresh / 16) - 1;
+ reg = clamp(reg, 0U, 63U);
+ ad9361_spi_writef(spi, REG_SMALL_LMT_OVERLOAD_THRESH,
+ SMALL_LMT_OVERLOAD_THRESH(~0), reg);
+
+ if (has_split_gt && phy->pdata->split_gt) {
+ /* REVIST */
+ ad9361_spi_write(spi, REG_RX1_MANUAL_LPF_GAIN, 0x58); // Rx1 LPF Gain Index
+ ad9361_spi_write(spi, REG_RX2_MANUAL_LPF_GAIN, 0x18); // Rx2 LPF Gain Index
+ ad9361_spi_write(spi, REG_FAST_INITIAL_LMT_GAIN_LIMIT, 0x27); // Initial LMT Gain Limit
+ }
+
+ ad9361_spi_write(spi, REG_RX1_MANUAL_DIGITALFORCED_GAIN, 0x00); // Rx1 Digital Gain Index
+ ad9361_spi_write(spi, REG_RX2_MANUAL_DIGITALFORCED_GAIN, 0x00); // Rx2 Digital Gain Index
+
+ reg = clamp_t(uint8_t, ctrl->low_power_thresh, 0U, 64U) * 2;
+ ad9361_spi_write(spi, REG_FAST_LOW_POWER_THRESH, reg); // Low Power Threshold
+ ad9361_spi_write(spi, REG_TX_SYMBOL_ATTEN_CONFIG, 0x00); // Tx Symbol Gain Control
+
+ ad9361_spi_writef(spi, REG_DEC_POWER_MEASURE_DURATION_0,
+ USE_HB1_OUT_FOR_DEC_PWR_MEAS, 1); // Power Measurement Duration
+
+ ad9361_spi_writef(spi, REG_DEC_POWER_MEASURE_DURATION_0,
+ ENABLE_DEC_PWR_MEAS, 1); // Power Measurement Duration
+
+ if (ctrl->rx1_mode == RF_GAIN_FASTATTACK_AGC ||
+ ctrl->rx2_mode == RF_GAIN_FASTATTACK_AGC)
+ reg = ilog2(ctrl->f_agc_dec_pow_measuremnt_duration / 16);
+ else
+ reg = ilog2(ctrl->dec_pow_measuremnt_duration / 16);
+
+ ad9361_spi_writef(spi, REG_DEC_POWER_MEASURE_DURATION_0,
+ DEC_POWER_MEASUREMENT_DURATION(~0), reg); // Power Measurement Duration
+
+ /* AGC */
+
+ tmp1 = reg = clamp_t(uint8_t, ctrl->agc_inner_thresh_high, 0U, 127U);
+ ad9361_spi_writef(spi, REG_AGC_LOCK_LEVEL,
+ AGC_LOCK_LEVEL_FAST_AGC_INNER_HIGH_THRESH_SLOW(~0),
+ reg);
+
+ tmp2 = reg = clamp_t(uint8_t, ctrl->agc_inner_thresh_low, 0U, 127U);
+ reg |= (ctrl->adc_lmt_small_overload_prevent_gain_inc ?
+ PREVENT_GAIN_INC : 0);
+ ad9361_spi_write(spi, REG_AGC_INNER_LOW_THRESH, reg);
+
+ reg = AGC_OUTER_HIGH_THRESH(tmp1 - ctrl->agc_outer_thresh_high) |
+ AGC_OUTER_LOW_THRESH(ctrl->agc_outer_thresh_low - tmp2);
+ ad9361_spi_write(spi, REG_OUTER_POWER_THRESHS, reg);
+
+ reg = AGC_OUTER_HIGH_THRESH_EXED_STP_SIZE(ctrl->agc_outer_thresh_high_dec_steps) |
+ AGC_OUTER_LOW_THRESH_EXED_STP_SIZE(ctrl->agc_outer_thresh_low_inc_steps);
+ ad9361_spi_write(spi, REG_GAIN_STP_2, reg);
+
+ reg = ((ctrl->immed_gain_change_if_large_adc_overload) ?
+ IMMED_GAIN_CHANGE_IF_LG_ADC_OVERLOAD : 0) |
+ ((ctrl->immed_gain_change_if_large_lmt_overload) ?
+ IMMED_GAIN_CHANGE_IF_LG_LMT_OVERLOAD : 0) |
+ AGC_INNER_HIGH_THRESH_EXED_STP_SIZE(ctrl->agc_inner_thresh_high_dec_steps) |
+ AGC_INNER_LOW_THRESH_EXED_STP_SIZE(ctrl->agc_inner_thresh_low_inc_steps);
+ ad9361_spi_write(spi, REG_GAIN_STP1, reg);
+
+ reg = LARGE_ADC_OVERLOAD_EXED_COUNTER(ctrl->adc_large_overload_exceed_counter) |
+ SMALL_ADC_OVERLOAD_EXED_COUNTER(ctrl->adc_small_overload_exceed_counter);
+ ad9361_spi_write(spi, REG_ADC_OVERLOAD_COUNTERS, reg);
+
+ ad9361_spi_writef(spi, REG_GAIN_STP_CONFIG_2, LARGE_LPF_GAIN_STEP(~0),
+ LARGE_LPF_GAIN_STEP(ctrl->adc_large_overload_inc_steps));
+
+ reg = LARGE_LMT_OVERLOAD_EXED_COUNTER(ctrl->lmt_overload_large_exceed_counter) |
+ SMALL_LMT_OVERLOAD_EXED_COUNTER(ctrl->lmt_overload_small_exceed_counter);
+ ad9361_spi_write(spi, REG_LMT_OVERLOAD_COUNTERS, reg);
+
+ ad9361_spi_writef(spi, REG_GAIN_STP_CONFIG1,
+ DEC_STP_SIZE_FOR_LARGE_LMT_OVERLOAD(~0),
+ ctrl->lmt_overload_large_inc_steps);
+
+ reg = DIG_SATURATION_EXED_COUNTER(ctrl->dig_saturation_exceed_counter) |
+ (ctrl->sync_for_gain_counter_en ?
+ ENABLE_SYNC_FOR_GAIN_COUNTER : 0);
+ ad9361_spi_write(spi, REG_DIGITAL_SAT_COUNTER, reg);
+
+ /*
+ * Fast AGC
+ */
+
+ /* Fast AGC - Low Power */
+ ad9361_spi_writef(spi, REG_FAST_CONFIG_1,
+ ENABLE_INCR_GAIN,
+ ctrl->f_agc_allow_agc_gain_increase);
+
+ ad9361_spi_write(spi, REG_FAST_INCREMENT_TIME,
+ ctrl->f_agc_lp_thresh_increment_time);
+
+ reg = ctrl->f_agc_lp_thresh_increment_steps - 1;
+ reg = clamp_t(uint32_t, reg, 0U, 7U);
+ ad9361_spi_writef(spi, REG_FAST_ENERGY_DETECT_COUNT,
+ INCREMENT_GAIN_STP_LPFLMT(~0), reg);
+
+ /* Fast AGC - Lock Level */
+ /* Dual use see also agc_inner_thresh_high */
+ ad9361_spi_writef(spi, REG_FAST_CONFIG_2_SETTLING_DELAY,
+ ENABLE_LMT_GAIN_INC_FOR_LOCK_LEVEL,
+ ctrl->f_agc_lock_level_lmt_gain_increase_en);
+
+ reg = ctrl->f_agc_lock_level_gain_increase_upper_limit;
+ reg = clamp_t(uint32_t, reg, 0U, 63U);
+ ad9361_spi_writef(spi, REG_FAST_AGCLL_UPPER_LIMIT,
+ AGCLL_MAX_INCREASE(~0), reg);
+
+ /* Fast AGC - Peak Detectors and Final Settling */
+ reg = ctrl->f_agc_lpf_final_settling_steps;
+ reg = clamp_t(uint32_t, reg, 0U, 3U);
+ ad9361_spi_writef(spi, REG_FAST_ENERGY_LOST_THRESH,
+ POST_LOCK_LEVEL_STP_SIZE_FOR_LPF_TABLE_FULL_TABLE(~0),
+ reg);
+
+ reg = ctrl->f_agc_lmt_final_settling_steps;
+ reg = clamp_t(uint32_t, reg, 0U, 3U);
+ ad9361_spi_writef(spi, REG_FAST_STRONGER_SIGNAL_THRESH,
+ POST_LOCK_LEVEL_STP_FOR_LMT_TABLE(~0), reg);
+
+ reg = ctrl->f_agc_final_overrange_count;
+ reg = clamp_t(uint32_t, reg, 0U, 7U);
+ ad9361_spi_writef(spi, REG_FAST_FINAL_OVER_RANGE_AND_OPT_GAIN,
+ FINAL_OVER_RANGE_COUNT(~0), reg);
+
+ /* Fast AGC - Final Power Test */
+ ad9361_spi_writef(spi, REG_FAST_CONFIG_1,
+ ENABLE_GAIN_INC_AFTER_GAIN_LOCK,
+ ctrl->f_agc_gain_increase_after_gain_lock_en);
+
+ /* Fast AGC - Unlocking the Gain */
+ /* 0 = MAX Gain, 1 = Optimized Gain, 2 = Set Gain */
+
+ reg = ctrl->f_agc_gain_index_type_after_exit_rx_mode;
+ ad9361_spi_writef(spi, REG_FAST_CONFIG_1,
+ GOTO_SET_GAIN_IF_EXIT_RX_STATE, reg == SET_GAIN);
+ ad9361_spi_writef(spi, REG_FAST_CONFIG_1,
+ GOTO_OPTIMIZED_GAIN_IF_EXIT_RX_STATE,
+ reg == OPTIMIZED_GAIN);
+
+ ad9361_spi_writef(spi, REG_FAST_CONFIG_2_SETTLING_DELAY,
+ USE_LAST_LOCK_LEVEL_FOR_SET_GAIN,
+ ctrl->f_agc_use_last_lock_level_for_set_gain_en);
+
+ reg = ctrl->f_agc_optimized_gain_offset;
+ reg = clamp_t(uint32_t, reg, 0U, 15U);
+ ad9361_spi_writef(spi, REG_FAST_FINAL_OVER_RANGE_AND_OPT_GAIN,
+ OPTIMIZE_GAIN_OFFSET(~0), reg);
+
+ tmp1 = !ctrl->f_agc_rst_gla_stronger_sig_thresh_exceeded_en ||
+ !ctrl->f_agc_rst_gla_engergy_lost_sig_thresh_exceeded_en ||
+ !ctrl->f_agc_rst_gla_large_adc_overload_en ||
+ !ctrl->f_agc_rst_gla_large_lmt_overload_en ||
+ ctrl->f_agc_rst_gla_en_agc_pulled_high_en;
+
+ ad9361_spi_writef(spi, REG_AGC_CONFIG_2,
+ AGC_GAIN_UNLOCK_CTRL, tmp1);
+
+ reg = !ctrl->f_agc_rst_gla_stronger_sig_thresh_exceeded_en;
+ ad9361_spi_writef(spi, REG_FAST_STRONG_SIGNAL_FREEZE,
+ DONT_UNLOCK_GAIN_IF_STRONGER_SIGNAL, reg);
+
+ reg = ctrl->f_agc_rst_gla_stronger_sig_thresh_above_ll;
+ reg = clamp_t(uint32_t, reg, 0U, 63U);
+ ad9361_spi_writef(spi, REG_FAST_STRONGER_SIGNAL_THRESH,
+ STRONGER_SIGNAL_THRESH(~0), reg);
+
+ reg = ctrl->f_agc_rst_gla_engergy_lost_sig_thresh_below_ll;
+ reg = clamp_t(uint32_t, reg, 0U, 63U);
+ ad9361_spi_writef(spi, REG_FAST_ENERGY_LOST_THRESH,
+ ENERGY_LOST_THRESH(~0), reg);
+
+ reg = ctrl->f_agc_rst_gla_engergy_lost_goto_optim_gain_en;
+ ad9361_spi_writef(spi, REG_FAST_CONFIG_1,
+ GOTO_OPT_GAIN_IF_ENERGY_LOST_OR_EN_AGC_HIGH, reg);
+
+ reg = !ctrl->f_agc_rst_gla_engergy_lost_sig_thresh_exceeded_en;
+ ad9361_spi_writef(spi, REG_FAST_CONFIG_1,
+ DONT_UNLOCK_GAIN_IF_ENERGY_LOST, reg);
+
+ reg = ctrl->f_agc_energy_lost_stronger_sig_gain_lock_exit_cnt;
+ reg = clamp_t(uint32_t, reg, 0U, 63U);
+ ad9361_spi_writef(spi, REG_FAST_GAIN_LOCK_EXIT_COUNT,
+ GAIN_LOCK_EXIT_COUNT(~0), reg);
+
+ reg = !ctrl->f_agc_rst_gla_large_adc_overload_en ||
+ !ctrl->f_agc_rst_gla_large_lmt_overload_en;
+ ad9361_spi_writef(spi, REG_FAST_CONFIG_1,
+ DONT_UNLOCK_GAIN_IF_LG_ADC_OR_LMT_OVRG, reg);
+
+ reg = !ctrl->f_agc_rst_gla_large_adc_overload_en;
+ ad9361_spi_writef(spi, REG_FAST_LOW_POWER_THRESH,
+ DONT_UNLOCK_GAIN_IF_ADC_OVRG, reg);
+
+ /* 0 = Max Gain, 1 = Set Gain, 2 = Optimized Gain, 3 = No Gain Change */
+
+ if (ctrl->f_agc_rst_gla_en_agc_pulled_high_en) {
+ switch (ctrl->f_agc_rst_gla_if_en_agc_pulled_high_mode) {
+ case MAX_GAIN:
+ ad9361_spi_writef(spi, REG_FAST_CONFIG_2_SETTLING_DELAY,
+ GOTO_MAX_GAIN_OR_OPT_GAIN_IF_EN_AGC_HIGH, 1);
+
+ ad9361_spi_writef(spi, REG_FAST_CONFIG_1,
+ GOTO_SET_GAIN_IF_EN_AGC_HIGH, 0);
+
+ ad9361_spi_writef(spi, REG_FAST_CONFIG_1,
+ GOTO_OPT_GAIN_IF_ENERGY_LOST_OR_EN_AGC_HIGH, 0);
+ break;
+ case SET_GAIN:
+ ad9361_spi_writef(spi, REG_FAST_CONFIG_2_SETTLING_DELAY,
+ GOTO_MAX_GAIN_OR_OPT_GAIN_IF_EN_AGC_HIGH, 0);
+
+ ad9361_spi_writef(spi, REG_FAST_CONFIG_1,
+ GOTO_SET_GAIN_IF_EN_AGC_HIGH, 1);
+ break;
+ case OPTIMIZED_GAIN:
+ ad9361_spi_writef(spi, REG_FAST_CONFIG_2_SETTLING_DELAY,
+ GOTO_MAX_GAIN_OR_OPT_GAIN_IF_EN_AGC_HIGH, 1);
+
+ ad9361_spi_writef(spi, REG_FAST_CONFIG_1,
+ GOTO_SET_GAIN_IF_EN_AGC_HIGH, 0);
+
+ ad9361_spi_writef(spi, REG_FAST_CONFIG_1,
+ GOTO_OPT_GAIN_IF_ENERGY_LOST_OR_EN_AGC_HIGH, 1);
+ break;
+ case NO_GAIN_CHANGE:
+ ad9361_spi_writef(spi, REG_FAST_CONFIG_1,
+ GOTO_SET_GAIN_IF_EN_AGC_HIGH, 0);
+ ad9361_spi_writef(spi, REG_FAST_CONFIG_2_SETTLING_DELAY,
+ GOTO_MAX_GAIN_OR_OPT_GAIN_IF_EN_AGC_HIGH, 0);
+ break;
+ }
+ }
+ else {
+ ad9361_spi_writef(spi, REG_FAST_CONFIG_1,
+ GOTO_SET_GAIN_IF_EN_AGC_HIGH, 0);
+ ad9361_spi_writef(spi, REG_FAST_CONFIG_2_SETTLING_DELAY,
+ GOTO_MAX_GAIN_OR_OPT_GAIN_IF_EN_AGC_HIGH, 0);
+ }
+
+ reg = ilog2(ctrl->f_agc_power_measurement_duration_in_state5 / 16);
+ reg = clamp_t(uint32_t, reg, 0U, 15U);
+ ad9361_spi_writef(spi, REG_RX1_MANUAL_LPF_GAIN,
+ POWER_MEAS_IN_STATE_5(~0), reg);
+ ad9361_spi_writef(spi, REG_RX1_MANUAL_LMT_FULL_GAIN,
+ POWER_MEAS_IN_STATE_5_MSB, reg >> 3);
+
+ return ad9361_gc_update(phy);
+}
+
+/**
+ * Set the Aux DAC.
+ * @param phy The AD9361 state structure.
+ * @param dac The DAC.
+ * @param val_mV The value.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_auxdac_set(struct ad9361_rf_phy *phy, int32_t dac,
+ int32_t val_mV)
+{
+ struct spi_device *spi = phy->spi;
+ uint32_t val, tmp;
+
+ dev_dbg(&phy->spi->dev, "%s DAC%"PRId32" = %"PRId32" mV", __func__, dac, val_mV);
+
+ /* Disable DAC if val == 0, Ignored in ENSM Auto Mode */
+ ad9361_spi_writef(spi, REG_AUXDAC_ENABLE_CTRL,
+ AUXDAC_MANUAL_BAR(dac), val_mV ? 0 : 1);
+
+ if (val_mV < 306)
+ val_mV = 306;
+
+ if (val_mV < 1888) {
+ val = ((val_mV - 306) * 1000) / 1404; /* Vref = 1V, Step = 2 */
+ tmp = AUXDAC_1_VREF(0);
+ }
+ else {
+ val = ((val_mV - 1761) * 1000) / 1836; /* Vref = 2.5V, Step = 2 */
+ tmp = AUXDAC_1_VREF(3);
+ }
+
+ val = clamp_t(uint32_t, val, 0, 1023);
+
+ switch (dac) {
+ case 1:
+ ad9361_spi_write(spi, REG_AUXDAC_1_WORD, val >> 2);
+ ad9361_spi_write(spi, REG_AUXDAC_1_CONFIG, AUXDAC_1_WORD_LSB(val) | tmp);
+ phy->auxdac1_value = val_mV;
+ break;
+ case 2:
+ ad9361_spi_write(spi, REG_AUXDAC_2_WORD, val >> 2);
+ ad9361_spi_write(spi, REG_AUXDAC_2_CONFIG, AUXDAC_2_WORD_LSB(val) | tmp);
+ phy->auxdac2_value = val_mV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * Get the Aux DAC value.
+ * @param phy The AD9361 state structure.
+ * @param dac The DAC.
+ * @return The value in case of success, negative error code otherwise.
+ */
+int32_t ad9361_auxdac_get(struct ad9361_rf_phy *phy, int32_t dac)
+{
+
+ switch (dac) {
+ case 1:
+ return phy->auxdac1_value;
+ case 2:
+ return phy->auxdac2_value;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * Setup the AuxDAC.
+ * @param phy The AD9361 state structure.
+ * @param ctrl Pointer to auxdac_control structure.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_auxdac_setup(struct ad9361_rf_phy *phy,
+struct auxdac_control *ctrl)
+{
+ struct spi_device *spi = phy->spi;
+ uint8_t tmp;
+
+ dev_dbg(&phy->spi->dev, "%s", __func__);
+
+ ad9361_auxdac_set(phy, 1, ctrl->dac1_default_value);
+ ad9361_auxdac_set(phy, 2, ctrl->dac2_default_value);
+
+ tmp = ~(AUXDAC_AUTO_TX_BAR(ctrl->dac2_in_tx_en << 1 | ctrl->dac1_in_tx_en) |
+ AUXDAC_AUTO_RX_BAR(ctrl->dac2_in_rx_en << 1 | ctrl->dac1_in_rx_en) |
+ AUXDAC_INIT_BAR(ctrl->dac2_in_alert_en << 1 | ctrl->dac1_in_alert_en));
+
+ ad9361_spi_writef(spi, REG_AUXDAC_ENABLE_CTRL,
+ AUXDAC_AUTO_TX_BAR(~0) |
+ AUXDAC_AUTO_RX_BAR(~0) |
+ AUXDAC_INIT_BAR(~0),
+ tmp); /* Auto Control */
+
+ ad9361_spi_writef(spi, REG_EXTERNAL_LNA_CTRL,
+ AUXDAC_MANUAL_SELECT, ctrl->auxdac_manual_mode_en);
+ ad9361_spi_write(spi, REG_AUXDAC1_RX_DELAY, ctrl->dac1_rx_delay_us);
+ ad9361_spi_write(spi, REG_AUXDAC1_TX_DELAY, ctrl->dac1_tx_delay_us);
+ ad9361_spi_write(spi, REG_AUXDAC2_RX_DELAY, ctrl->dac2_rx_delay_us);
+ ad9361_spi_write(spi, REG_AUXDAC2_TX_DELAY, ctrl->dac2_tx_delay_us);
+
+ return 0;
+}
+
+/**
+ * Setup the AuxADC.
+ * @param phy The AD9361 state structure.
+ * @param ctrl The AuxADC settings.
+ * @param bbpll_freq The BBPLL frequency [Hz].
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_auxadc_setup(struct ad9361_rf_phy *phy,
+struct auxadc_control *ctrl,
+ uint32_t bbpll_freq)
+{
+ struct spi_device *spi = phy->spi;
+ uint32_t val;
+
+ dev_dbg(&phy->spi->dev, "%s", __func__);
+
+ val = DIV_ROUND_CLOSEST(ctrl->temp_time_inteval_ms *
+ (bbpll_freq / 1000UL), (1 << 29));
+
+ ad9361_spi_write(spi, REG_TEMP_OFFSET, ctrl->offset);
+ ad9361_spi_write(spi, REG_START_TEMP_READING, 0x00);
+ ad9361_spi_write(spi, REG_TEMP_SENSE2,
+ MEASUREMENT_TIME_INTERVAL(val) |
+ (ctrl->periodic_temp_measuremnt ?
+ TEMP_SENSE_PERIODIC_ENABLE : 0));
+ ad9361_spi_write(spi, REG_TEMP_SENSOR_CONFIG,
+ TEMP_SENSOR_DECIMATION(
+ ilog2(ctrl->temp_sensor_decimation) - 8));
+ ad9361_spi_write(spi, REG_AUXADC_CLOCK_DIVIDER,
+ bbpll_freq / ctrl->auxadc_clock_rate);
+ ad9361_spi_write(spi, REG_AUXADC_CONFIG,
+ AUX_ADC_DECIMATION(
+ ilog2(ctrl->auxadc_decimation) - 8));
+
+ return 0;
+}
+
+/**
+ * Get the measured temperature of the device.
+ * @param phy The AD9361 state structure.
+ * @return The measured temperature of the device.
+ */
+int32_t ad9361_get_temp(struct ad9361_rf_phy *phy)
+{
+ uint32_t val;
+
+ ad9361_spi_writef(phy->spi, REG_AUXADC_CONFIG, AUXADC_POWER_DOWN, 1);
+ val = ad9361_spi_read(phy->spi, REG_TEMPERATURE);
+ ad9361_spi_writef(phy->spi, REG_AUXADC_CONFIG, AUXADC_POWER_DOWN, 0);
+
+ return DIV_ROUND_CLOSEST(val * 1000000, 1140);
+}
+
+/**
+ * Get the Aux ADC value.
+ * @param phy The AD9361 state structure.
+ * @return The value in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_auxadc(struct ad9361_rf_phy *phy)
+{
+ uint8_t buf[2];
+
+ ad9361_spi_writef(phy->spi, REG_AUXADC_CONFIG, AUXADC_POWER_DOWN, 1);
+ ad9361_spi_readm(phy->spi, REG_AUXADC_LSB, buf, 2);
+ ad9361_spi_writef(phy->spi, REG_AUXADC_CONFIG, AUXADC_POWER_DOWN, 0);
+
+ return (buf[1] << 4) | AUXADC_WORD_LSB(buf[0]);
+}
+
+/**
+ * Setup the Control Output pins.
+ * @param phy The AD9361 state structure.
+ * @param ctrl The Control Output pins settings.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_ctrl_outs_setup(struct ad9361_rf_phy *phy,
+struct ctrl_outs_control *ctrl)
+{
+ struct spi_device *spi = phy->spi;
+
+ dev_dbg(&phy->spi->dev, "%s", __func__);
+
+ ad9361_spi_write(spi, REG_CTRL_OUTPUT_POINTER, ctrl->index); // Ctrl Out index
+ return ad9361_spi_write(spi, REG_CTRL_OUTPUT_ENABLE, ctrl->en_mask); // Ctrl Out [7:0] output enable
+}
+
+/**
+ * Setup the GPO pins.
+ * @param phy The AD9361 state structure.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_gpo_setup(struct ad9361_rf_phy *phy, struct gpo_control *ctrl)
+{
+ struct spi_device *spi = phy->spi;
+
+ dev_dbg(&phy->spi->dev, "%s", __func__);
+
+ ad9361_spi_write(spi, REG_AUTO_GPO,
+ GPO_ENABLE_AUTO_RX(ctrl->gpo0_slave_rx_en |
+ (ctrl->gpo1_slave_rx_en << 1) |
+ (ctrl->gpo2_slave_rx_en << 2) |
+ (ctrl->gpo3_slave_rx_en << 3)) |
+ GPO_ENABLE_AUTO_TX(ctrl->gpo0_slave_tx_en |
+ (ctrl->gpo1_slave_tx_en << 1) |
+ (ctrl->gpo2_slave_tx_en << 2) |
+ (ctrl->gpo3_slave_tx_en << 3)));
+
+ ad9361_spi_write(spi, REG_GPO_FORCE_AND_INIT,
+ GPO_INIT_STATE(ctrl->gpo0_inactive_state_high_en |
+ (ctrl->gpo1_inactive_state_high_en << 1) |
+ (ctrl->gpo2_inactive_state_high_en << 2) |
+ (ctrl->gpo3_inactive_state_high_en << 3)));
+
+ ad9361_spi_write(spi, REG_GPO0_RX_DELAY, ctrl->gpo0_rx_delay_us);
+ ad9361_spi_write(spi, REG_GPO0_TX_DELAY, ctrl->gpo0_tx_delay_us);
+ ad9361_spi_write(spi, REG_GPO1_RX_DELAY, ctrl->gpo1_rx_delay_us);
+ ad9361_spi_write(spi, REG_GPO1_TX_DELAY, ctrl->gpo1_tx_delay_us);
+ ad9361_spi_write(spi, REG_GPO2_RX_DELAY, ctrl->gpo2_rx_delay_us);
+ ad9361_spi_write(spi, REG_GPO2_TX_DELAY, ctrl->gpo2_tx_delay_us);
+ ad9361_spi_write(spi, REG_GPO3_RX_DELAY, ctrl->gpo3_rx_delay_us);
+ ad9361_spi_write(spi, REG_GPO3_TX_DELAY, ctrl->gpo3_tx_delay_us);
+
+ return 0;
+}
+
+/**
+ * Setup the RSSI.
+ * @param phy The AD9361 state structure.
+ * @param ctrl The RSSI settings.
+ * @param is_update True if update
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_rssi_setup(struct ad9361_rf_phy *phy,
+struct rssi_control *ctrl,
+ bool is_update)
+{
+ struct spi_device *spi = phy->spi;
+ uint32_t total_weight, weight[4], total_dur = 0, temp;
+ uint8_t dur_buf[4] = { 0 };
+ int32_t val, ret, i, j = 0;
+ uint32_t rssi_delay;
+ uint32_t rssi_wait;
+ int32_t rssi_duration;
+ uint32_t rate;
+
+ dev_dbg(&phy->spi->dev, "%s", __func__);
+
+ if (ctrl->rssi_unit_is_rx_samples) {
+ if (is_update)
+ return 0; /* no update required */
+
+ rssi_delay = ctrl->rssi_delay;
+ rssi_wait = ctrl->rssi_wait;
+ rssi_duration = ctrl->rssi_duration;
+ }
+ else {
+ /* update sample based on RX rate */
+ rate = DIV_ROUND_CLOSEST(
+ clk_get_rate(phy, phy->ref_clk_scale[RX_SAMPL_CLK]), 1000);
+ /* units are in us */
+ rssi_delay = DIV_ROUND_CLOSEST(ctrl->rssi_delay * rate, 1000);
+ rssi_wait = DIV_ROUND_CLOSEST(ctrl->rssi_wait * rate, 1000);
+ rssi_duration = DIV_ROUND_CLOSEST(
+ ctrl->rssi_duration * rate, 1000);
+ }
+
+ if (ctrl->restart_mode == EN_AGC_PIN_IS_PULLED_HIGH)
+ rssi_delay = 0;
+
+ rssi_delay = clamp(rssi_delay / 8, 0U, 255U);
+ rssi_wait = clamp(rssi_wait / 4, 0U, 255U);
+
+ do {
+ for (i = 14; rssi_duration > 0 && i >= 0; i--) {
+ val = 1 << i;
+ if ((int64_t)rssi_duration >= val) {
+ dur_buf[j++] = i;
+ total_dur += val;
+ rssi_duration -= val;
+ break;
+ }
+ }
+
+ } while (j < 4 && rssi_duration > 0);
+
+ for (i = 0, total_weight = 0; i < 4; i++) {
+ if (i < j)
+ total_weight += weight[i] =
+ DIV_ROUND_CLOSEST(RSSI_MAX_WEIGHT *
+ (1 << dur_buf[i]), total_dur);
+ else
+ total_weight += weight[i] = 0;
+ }
+
+ /* total of all weights must be 0xFF */
+ val = total_weight - 0xFF;
+ weight[j - 1] -= val;
+
+ ad9361_spi_write(spi, REG_MEASURE_DURATION_01,
+ (dur_buf[1] << 4) | dur_buf[0]); // RSSI Measurement Duration 0, 1
+ ad9361_spi_write(spi, REG_MEASURE_DURATION_23,
+ (dur_buf[3] << 4) | dur_buf[2]); // RSSI Measurement Duration 2, 3
+ ad9361_spi_write(spi, REG_RSSI_WEIGHT_0, weight[0]); // RSSI Weighted Multiplier 0
+ ad9361_spi_write(spi, REG_RSSI_WEIGHT_1, weight[1]); // RSSI Weighted Multiplier 1
+ ad9361_spi_write(spi, REG_RSSI_WEIGHT_2, weight[2]); // RSSI Weighted Multiplier 2
+ ad9361_spi_write(spi, REG_RSSI_WEIGHT_3, weight[3]); // RSSI Weighted Multiplier 3
+ ad9361_spi_write(spi, REG_RSSI_DELAY, rssi_delay); // RSSI Delay
+ ad9361_spi_write(spi, REG_RSSI_WAIT_TIME, rssi_wait); // RSSI Wait
+
+ temp = RSSI_MODE_SELECT(ctrl->restart_mode);
+ if (ctrl->restart_mode == SPI_WRITE_TO_REGISTER)
+ temp |= START_RSSI_MEAS;
+
+ if (rssi_duration == 0 && j == 1) /* Power of two */
+ temp |= DEFAULT_RSSI_MEAS_MODE;
+
+ ret = ad9361_spi_write(spi, REG_RSSI_CONFIG, temp); // RSSI Mode Select
+
+ if (ret < 0)
+ dev_err(&phy->spi->dev, "Unable to write rssi config");
+
+ return 0;
+}
+
+/**
+ * This function needs to be called whenever BBPLL changes.
+ * @param phy The AD9361 state structure.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_bb_clk_change_handler(struct ad9361_rf_phy *phy)
+{
+ int32_t ret;
+
+ ret = ad9361_gc_update(phy);
+ ret |= ad9361_rssi_setup(phy, &phy->pdata->rssi_ctrl, true);
+ ret |= ad9361_auxadc_setup(phy, &phy->pdata->auxadc_ctrl,
+ clk_get_rate(phy, phy->ref_clk_scale[BBPLL_CLK]));
+
+ return ret;
+}
+
+/**
+ * Set the desired Enable State Machine (ENSM) state.
+ * @param phy The AD9361 state structure.
+ * @param ensm_state The ENSM state [ENSM_STATE_SLEEP_WAIT, ENSM_STATE_ALERT,
+ * ENSM_STATE_TX, ENSM_STATE_TX_FLUSH, ENSM_STATE_RX,
+ * ENSM_STATE_RX_FLUSH, ENSM_STATE_FDD, ENSM_STATE_FDD_FLUSH].
+ * @param pinctrl Set true, will enable the ENSM pin control.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_ensm_set_state(struct ad9361_rf_phy *phy, uint8_t ensm_state,
+ bool pinctrl)
+{
+ struct spi_device *spi = phy->spi;
+ int32_t rc = 0;
+ uint32_t val;
+ uint32_t tmp;
+
+ dev_dbg(dev, "Device is in %x state, moving to %x", phy->curr_ensm_state,
+ ensm_state);
+
+
+ if (phy->curr_ensm_state == ENSM_STATE_SLEEP) {
+ ad9361_spi_write(spi, REG_CLOCK_ENABLE,
+ DIGITAL_POWER_UP | CLOCK_ENABLE_DFLT | BBPLL_ENABLE |
+ (phy->pdata->use_extclk ? XO_BYPASS : 0)); /* Enable Clocks */
+ udelay(20);
+ ad9361_spi_write(spi, REG_ENSM_CONFIG_1, TO_ALERT | FORCE_ALERT_STATE);
+ ad9361_trx_vco_cal_control(phy, false, true); /* Enable VCO Cal */
+ ad9361_trx_vco_cal_control(phy, true, true);
+ }
+
+ val = (phy->pdata->ensm_pin_pulse_mode ? 0 : LEVEL_MODE) |
+ (pinctrl ? ENABLE_ENSM_PIN_CTRL : 0) |
+ (phy->txmon_tdd_en ? ENABLE_RX_DATA_PORT_FOR_CAL : 0) |
+ TO_ALERT;
+
+ switch (ensm_state) {
+ case ENSM_STATE_TX:
+ val |= FORCE_TX_ON;
+ if (phy->pdata->fdd)
+ rc = -EINVAL;
+ else if (phy->curr_ensm_state != ENSM_STATE_ALERT)
+ rc = -EINVAL;
+ break;
+ case ENSM_STATE_RX:
+ val |= FORCE_RX_ON;
+ if (phy->pdata->fdd)
+ rc = -EINVAL;
+ else if (phy->curr_ensm_state != ENSM_STATE_ALERT)
+ rc = -EINVAL;
+ break;
+ case ENSM_STATE_FDD:
+ val |= FORCE_TX_ON;
+ if (!phy->pdata->fdd)
+ rc = -EINVAL;
+ break;
+ case ENSM_STATE_ALERT:
+ val &= ~(FORCE_TX_ON | FORCE_RX_ON);
+ val |= TO_ALERT | FORCE_ALERT_STATE;
+ break;
+ case ENSM_STATE_SLEEP_WAIT:
+ break;
+ case ENSM_STATE_SLEEP:
+ ad9361_trx_vco_cal_control(phy, false, false); /* Disable VCO Cal */
+ ad9361_trx_vco_cal_control(phy, true, false);
+ ad9361_spi_write(spi, REG_ENSM_CONFIG_1, 0); /* Clear To Alert */
+ ad9361_spi_write(spi, REG_ENSM_CONFIG_1,
+ phy->pdata->fdd ? FORCE_TX_ON : FORCE_RX_ON);
+ /* Delay Flush Time 384 ADC clock cycles */
+ udelay(384000000UL / clk_get_rate(phy, phy->ref_clk_scale[ADC_CLK]));
+ ad9361_spi_write(spi, REG_ENSM_CONFIG_1, 0); /* Move to Wait*/
+ udelay(1); /* Wait for ENSM settle */
+ ad9361_spi_write(spi, REG_CLOCK_ENABLE,
+ (phy->pdata->use_extclk ? XO_BYPASS : 0)); /* Turn off all clocks */
+ phy->curr_ensm_state = ensm_state;
+ return 0;
+
+ default:
+ dev_err(dev, "No handling for forcing %d ensm state",
+ ensm_state);
+ goto out;
+ }
+
+ if (rc) {
+ if ((phy->curr_ensm_state != ENSM_STATE_ALERT) && (val & (FORCE_RX_ON | FORCE_TX_ON))) {
+ uint32_t val2 = val;
+
+ val2 &= ~(FORCE_TX_ON | FORCE_RX_ON);
+ val2 |= TO_ALERT | FORCE_ALERT_STATE;
+ ad9361_spi_write(spi, REG_ENSM_CONFIG_1, val2);
+
+ ad9361_check_cal_done(phy, REG_STATE, ENSM_STATE(~0), ENSM_STATE_ALERT);
+ } else {
+ dev_err(dev, "Invalid ENSM state transition in %s mode",
+ phy->pdata->fdd ? "FDD" : "TDD");
+ goto out;
+ }
+ }
+
+ if (!phy->pdata->fdd && !pinctrl && !phy->pdata->tdd_use_dual_synth &&
+ (ensm_state == ENSM_STATE_TX || ensm_state == ENSM_STATE_RX)) {
+ ad9361_spi_writef(phy->spi, REG_ENSM_CONFIG_2,
+ TXNRX_SPI_CTRL, ensm_state == ENSM_STATE_TX);
+
+ ad9361_check_cal_done(phy, (ensm_state == ENSM_STATE_TX) ?
+ REG_TX_CP_OVERRANGE_VCO_LOCK :
+ REG_RX_CP_OVERRANGE_VCO_LOCK,
+ VCO_LOCK, 1);
+ }
+
+ rc = ad9361_spi_write(spi, REG_ENSM_CONFIG_1, val);
+ if (rc)
+ dev_err(dev, "Failed to restore state");
+
+ if ((val & FORCE_RX_ON) &&
+ (phy->agc_mode[0] == RF_GAIN_MGC ||
+ phy->agc_mode[1] == RF_GAIN_MGC)) {
+ tmp = ad9361_spi_read(spi, REG_SMALL_LMT_OVERLOAD_THRESH);
+ ad9361_spi_write(spi, REG_SMALL_LMT_OVERLOAD_THRESH,
+ (tmp & SMALL_LMT_OVERLOAD_THRESH(~0)) |
+ (phy->agc_mode[0] == RF_GAIN_MGC ? FORCE_PD_RESET_RX1 : 0) |
+ (phy->agc_mode[1] == RF_GAIN_MGC ? FORCE_PD_RESET_RX2 : 0));
+ ad9361_spi_write(spi, REG_SMALL_LMT_OVERLOAD_THRESH,
+ tmp & SMALL_LMT_OVERLOAD_THRESH(~0));
+ }
+
+ phy->curr_ensm_state = ensm_state;
+
+out:
+ return rc;
+
+}
+
+/**
+ * Check if at least one of the clock rates is equal to the DATA_CLK (lvds) rate.
+ * @param phy The AD9361 state structure.
+ * @param rx_path_clks RX path rates buffer.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_validate_trx_clock_chain(struct ad9361_rf_phy *phy,
+ uint32_t *rx_path_clks)
+{
+ int32_t i;
+ uint32_t data_clk;
+
+ data_clk = (phy->pdata->rx2tx2 ? 4 : 2) /
+ ((phy->pdata->port_ctrl.pp_conf[2] & LVDS_MODE) ? 1 : 2) *
+ rx_path_clks[RX_SAMPL_FREQ];
+
+ /* CMOS Mode */
+ if (!(phy->pdata->port_ctrl.pp_conf[2] & LVDS_MODE) &&
+ (data_clk > 61440000UL)) {
+ dev_err(&phy->spi->dev,
+ "%s: Failed CMOS MODE DATA_CLK > 61.44MSPS", __func__);
+ return -EINVAL;
+ }
+
+ for (i = 1; i <= 3; i++) {
+ if (abs(rx_path_clks[ADC_FREQ] / i - data_clk) < 4)
+ return 0;
+ }
+
+ for (i = 1; i <= 4; i++) {
+ if (abs((rx_path_clks[R2_FREQ] >> i) - data_clk) < 4)
+ return 0;
+ }
+
+ dev_err(&phy->spi->dev, "%s: Failed - at least one of the clock rates"
+ " must be equal to the DATA_CLK (lvds) rate", __func__);
+
+ return -EINVAL;
+}
+
+/**
+ * Set the RX and TX path rates.
+ * @param phy The AD9361 state structure.
+ * @param rx_path_clks RX path rates buffer.
+ * @param tx_path_clks TX path rates buffer.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_set_trx_clock_chain(struct ad9361_rf_phy *phy,
+ uint32_t *rx_path_clks,
+ uint32_t *tx_path_clks)
+{
+ int32_t ret, i, j, n;
+
+ dev_dbg(&phy->spi->dev, "%s", __func__);
+
+ if (!rx_path_clks || !tx_path_clks)
+ return -EINVAL;
+
+ dev_dbg(&phy->spi->dev, "%s: %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32,
+ __func__, rx_path_clks[BBPLL_FREQ], rx_path_clks[ADC_FREQ],
+ rx_path_clks[R2_FREQ], rx_path_clks[R1_FREQ],
+ rx_path_clks[CLKRF_FREQ], rx_path_clks[RX_SAMPL_FREQ]);
+
+ dev_dbg(&phy->spi->dev, "%s: %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32,
+ __func__, tx_path_clks[BBPLL_FREQ], tx_path_clks[ADC_FREQ],
+ tx_path_clks[R2_FREQ], tx_path_clks[R1_FREQ],
+ tx_path_clks[CLKRF_FREQ], tx_path_clks[RX_SAMPL_FREQ]);
+
+ ret = ad9361_validate_trx_clock_chain(phy, rx_path_clks);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_set_rate(phy, phy->ref_clk_scale[BBPLL_CLK], rx_path_clks[BBPLL_FREQ]);
+ if (ret < 0)
+ return ret;
+
+ for (i = ADC_CLK, j = DAC_CLK, n = ADC_FREQ;
+ i <= RX_SAMPL_CLK; i++, j++, n++) {
+ ret = clk_set_rate(phy, phy->ref_clk_scale[i], rx_path_clks[n]);
+ if (ret < 0) {
+ dev_err(dev, "Failed to set BB ref clock rate (%"PRId32")",
+ ret);
+ return ret;
+ }
+ ret = clk_set_rate(phy, phy->ref_clk_scale[j], tx_path_clks[n]);
+ if (ret < 0) {
+ dev_err(dev, "Failed to set BB ref clock rate (%"PRId32")",
+ ret);
+ return ret;
+ }
+ }
+
+ /*
+ * Workaround for clock framework since clocks don't change we
+ * manually need to enable the filter
+ */
+
+ if (phy->rx_fir_dec == 1 || phy->bypass_rx_fir) {
+ ad9361_spi_writef(phy->spi, REG_RX_ENABLE_FILTER_CTRL,
+ RX_FIR_ENABLE_DECIMATION(~0), !phy->bypass_rx_fir);
+ }
+
+ if (phy->tx_fir_int == 1 || phy->bypass_tx_fir) {
+ ad9361_spi_writef(phy->spi, REG_TX_ENABLE_FILTER_CTRL,
+ TX_FIR_ENABLE_INTERPOLATION(~0), !phy->bypass_tx_fir);
+ }
+
+ /* The FIR filter once enabled causes the interface timing to change.
+ * It's typically not a problem if the timing margin is big enough.
+ * However at 61.44 MSPS it causes problems on some systems.
+ * So we always run the digital tune in case the filter is enabled.
+ * If it is disabled we restore the values from the initial calibration.
+ */
+
+ if (!phy->pdata->dig_interface_tune_fir_disable &&
+ !(phy->bypass_tx_fir && phy->bypass_rx_fir))
+ ret = ad9361_dig_tune(phy, 0, SKIP_STORE_RESULT);
+
+ return ad9361_bb_clk_change_handler(phy);
+}
+
+/**
+ * Get the RX and TX path rates.
+ * @param phy The AD9361 state structure.
+ * @param rx_path_clks RX path rates buffer.
+ * @param tx_path_clks TX path rates buffer.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_trx_clock_chain(struct ad9361_rf_phy *phy, uint32_t *rx_path_clks,
+ uint32_t *tx_path_clks)
+{
+ int32_t i, j, n;
+ uint32_t bbpll_freq;
+
+ if (!rx_path_clks && !tx_path_clks)
+ return -EINVAL;
+
+ bbpll_freq = clk_get_rate(phy, phy->ref_clk_scale[BBPLL_CLK]);
+
+ if (rx_path_clks)
+ rx_path_clks[BBPLL_FREQ] = bbpll_freq;
+
+ if (tx_path_clks)
+ tx_path_clks[BBPLL_FREQ] = bbpll_freq;
+
+ for (i = ADC_CLK, j = DAC_CLK, n = ADC_FREQ;
+ i <= RX_SAMPL_CLK; i++, j++, n++) {
+ if (rx_path_clks)
+ rx_path_clks[n] = clk_get_rate(phy, phy->ref_clk_scale[i]);
+ if (tx_path_clks)
+ tx_path_clks[n] = clk_get_rate(phy, phy->ref_clk_scale[j]);
+ }
+
+ return 0;
+}
+
+/**
+ * Calculate the RX and TX path rates to obtain the desired sample rate.
+ * @param phy The AD9361 state structure.
+ * @param tx_sample_rate The desired sample rate.
+ * @param rate_gov The rate governor option.
+ * @param rx_path_clks RX path rates buffer.
+ * @param tx_path_clks TX path rates buffer.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_calculate_rf_clock_chain(struct ad9361_rf_phy *phy,
+ uint32_t tx_sample_rate,
+ uint32_t rate_gov,
+ uint32_t *rx_path_clks,
+ uint32_t *tx_path_clks)
+{
+ uint32_t clktf, clkrf, adc_rate = 0, dac_rate = 0;
+ uint64_t bbpll_rate;
+ int32_t i, index_rx = -1, index_tx = -1, tmp;
+ uint32_t div, tx_intdec, rx_intdec, recursion = 1;
+ const int8_t clk_dividers[][4] = {
+ { 12, 3, 2, 2 },
+ { 8, 2, 2, 2 },
+ { 6, 3, 1, 2 },
+ { 4, 2, 2, 1 },
+ { 3, 3, 1, 1 },
+ { 2, 2, 1, 1 },
+ { 1, 1, 1, 1 },
+ };
+
+ if (phy->bypass_rx_fir)
+ rx_intdec = 1;
+ else
+ rx_intdec = phy->rx_fir_dec;
+
+ if (phy->bypass_tx_fir)
+ tx_intdec = 1;
+ else
+ tx_intdec = phy->tx_fir_int;
+
+ if ((rate_gov == 1) && ((rx_intdec * tx_sample_rate * 8) < MIN_ADC_CLK)) {
+ recursion = 0;
+ rate_gov = 0;
+ }
+
+ dev_dbg(&phy->spi->dev, "%s: requested rate %"PRIu32" TXFIR int %"PRIu32" RXFIR dec %"PRIu32" mode %s",
+ __func__, tx_sample_rate, tx_intdec, rx_intdec,
+ rate_gov ? "Nominal" : "Highest OSR");
+
+ if (tx_sample_rate > 61440000UL)
+ return -EINVAL;
+
+ clktf = tx_sample_rate * tx_intdec;
+ clkrf = tx_sample_rate * rx_intdec * (phy->rx_eq_2tx ? 2 : 1);
+
+ for (i = rate_gov; i < 7; i++) {
+ adc_rate = clkrf * clk_dividers[i][0];
+ dac_rate = clktf * clk_dividers[i][0];
+
+ if ((adc_rate <= MAX_ADC_CLK) && (adc_rate >= MIN_ADC_CLK)) {
+
+
+ if (dac_rate > adc_rate)
+ tmp = (dac_rate / adc_rate) * -1;
+ else
+ tmp = adc_rate / dac_rate;
+
+ if (adc_rate <= MAX_DAC_CLK) {
+ index_rx = i;
+ index_tx = i - ((tmp == 1) ? 0 : tmp);
+ dac_rate = adc_rate; /* ADC_CLK */
+ break;
+ }
+ else {
+ dac_rate = adc_rate / 2; /* ADC_CLK/2 */
+ index_rx = i;
+
+ if (i == 4 && tmp >= 0)
+ index_tx = 7; /* STOP: 3/2 != 1 */
+ else
+ index_tx = i + ((i == 5 && tmp >= 0) ? 1 : 2) -
+ ((tmp == 1) ? 0 : tmp);
+
+ break;
+ }
+ }
+ }
+
+ if ((index_tx < 0 || index_tx > 6 || index_rx < 0 || index_rx > 6) && rate_gov < 7 && recursion) {
+ return ad9361_calculate_rf_clock_chain(phy, tx_sample_rate,
+ ++rate_gov, rx_path_clks, tx_path_clks);
+ }
+ else if ((index_tx < 0 || index_tx > 6 || index_rx < 0 || index_rx > 6)) {
+ dev_err(&phy->spi->dev, "%s: Failed to find suitable dividers: %s",
+ __func__, (adc_rate < MIN_ADC_CLK) ? "ADC clock below limit" : "BBPLL rate above limit");
+
+ return -EINVAL;
+ }
+
+ /* Calculate target BBPLL rate */
+ div = MAX_BBPLL_DIV;
+
+ do {
+ bbpll_rate = (uint64_t)adc_rate * div;
+ div >>= 1;
+
+ } while ((bbpll_rate > MAX_BBPLL_FREQ) && (div >= MIN_BBPLL_DIV));
+
+ rx_path_clks[BBPLL_FREQ] = bbpll_rate;
+ rx_path_clks[ADC_FREQ] = adc_rate;
+ rx_path_clks[R2_FREQ] = rx_path_clks[ADC_FREQ] / clk_dividers[index_rx][1];
+ rx_path_clks[R1_FREQ] = rx_path_clks[R2_FREQ] / clk_dividers[index_rx][2];
+ rx_path_clks[CLKRF_FREQ] = rx_path_clks[R1_FREQ] / clk_dividers[index_rx][3];
+ rx_path_clks[RX_SAMPL_FREQ] = rx_path_clks[CLKRF_FREQ] / rx_intdec;
+
+ tx_path_clks[BBPLL_FREQ] = bbpll_rate;
+ tx_path_clks[DAC_FREQ] = dac_rate;
+ tx_path_clks[T2_FREQ] = tx_path_clks[DAC_FREQ] / clk_dividers[index_tx][1];
+ tx_path_clks[T1_FREQ] = tx_path_clks[T2_FREQ] / clk_dividers[index_tx][2];
+ tx_path_clks[CLKTF_FREQ] = tx_path_clks[T1_FREQ] / clk_dividers[index_tx][3];
+ tx_path_clks[TX_SAMPL_FREQ] = tx_path_clks[CLKTF_FREQ] / tx_intdec;
+
+ return 0;
+}
+
+/**
+ * Set the desired sample rate.
+ * @param phy The AD9361 state structure.
+ * @param freq The desired sample rate.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_set_trx_clock_chain_freq(struct ad9361_rf_phy *phy,
+ uint32_t freq)
+{
+ uint32_t rx[6], tx[6];
+ int32_t ret;
+
+ ret = ad9361_calculate_rf_clock_chain(phy, freq,
+ phy->rate_governor, rx, tx);
+ if (ret < 0)
+ return ret;
+ return ad9361_set_trx_clock_chain(phy, rx, tx);
+}
+
+/**
+ * Internal ENSM mode options helper function.
+ * @param phy The AD9361 state structure.
+ * @param fdd
+ * @param pinctrl
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_set_ensm_mode(struct ad9361_rf_phy *phy, bool fdd, bool pinctrl)
+{
+ struct ad9361_phy_platform_data *pd = phy->pdata;
+ int32_t ret;
+ uint32_t val = 0;
+
+ ad9361_spi_write(phy->spi, REG_ENSM_MODE, fdd ? FDD_MODE : 0);
+
+ val = ad9361_spi_read(phy->spi, REG_ENSM_CONFIG_2);
+ val &= POWER_DOWN_RX_SYNTH | POWER_DOWN_TX_SYNTH;
+
+ if (fdd)
+ ret = ad9361_spi_write(phy->spi, REG_ENSM_CONFIG_2,
+ val | DUAL_SYNTH_MODE |
+ (pd->fdd_independent_mode ? FDD_EXTERNAL_CTRL_ENABLE : 0));
+ else
+ ret = ad9361_spi_write(phy->spi, REG_ENSM_CONFIG_2, val |
+ (pd->tdd_use_dual_synth ? DUAL_SYNTH_MODE : 0) |
+ (pd->tdd_use_dual_synth ? 0 :
+ (pinctrl ? SYNTH_ENABLE_PIN_CTRL_MODE : 0)));
+
+ return ret;
+}
+
+/**
+ * Fastlock read value.
+ * @param spi
+ * @param tx
+ * @param profile
+ * @param word
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_fastlock_readval(struct spi_device *spi, bool tx,
+ uint32_t profile, uint32_t word)
+{
+ uint32_t offs = 0;
+
+ if (tx)
+ offs = REG_TX_FAST_LOCK_SETUP - REG_RX_FAST_LOCK_SETUP;
+
+ ad9361_spi_write(spi, REG_RX_FAST_LOCK_PROGRAM_ADDR + offs,
+ RX_FAST_LOCK_PROFILE_ADDR(profile) |
+ RX_FAST_LOCK_PROFILE_WORD(word));
+
+ return ad9361_spi_read(spi, REG_RX_FAST_LOCK_PROGRAM_READ + offs);
+}
+
+/**
+ * Fastlock write value.
+ * @param spi
+ * @param tx
+ * @param profile
+ * @param word
+ * @param val
+ * @param last
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_fastlock_writeval(struct spi_device *spi, bool tx,
+ uint32_t profile, uint32_t word, uint8_t val, bool last)
+{
+ uint32_t offs = 0;
+ int32_t ret;
+
+ if (tx)
+ offs = REG_TX_FAST_LOCK_SETUP - REG_RX_FAST_LOCK_SETUP;
+
+ ret = ad9361_spi_write(spi, REG_RX_FAST_LOCK_PROGRAM_ADDR + offs,
+ RX_FAST_LOCK_PROFILE_ADDR(profile) |
+ RX_FAST_LOCK_PROFILE_WORD(word));
+ ret |= ad9361_spi_write(spi, REG_RX_FAST_LOCK_PROGRAM_DATA + offs, val);
+ ret |= ad9361_spi_write(spi, REG_RX_FAST_LOCK_PROGRAM_CTRL + offs,
+ RX_FAST_LOCK_PROGRAM_WRITE |
+ RX_FAST_LOCK_PROGRAM_CLOCK_ENABLE);
+
+ if (last) /* Stop Clocks */
+ ret |= ad9361_spi_write(spi,
+ REG_RX_FAST_LOCK_PROGRAM_CTRL + offs, 0);
+
+ return ret;
+}
+
+/**
+ * Fastlock load values.
+ * @param phy The AD9361 state structure.
+ * @param tx
+ * @param profile
+ * @param values
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_fastlock_load(struct ad9361_rf_phy *phy, bool tx,
+ uint32_t profile, uint8_t *values)
+{
+ uint32_t offs = 0;
+ int32_t i, ret = 0;
+ uint8_t buf[4];
+
+ dev_dbg(&phy->spi->dev, "%s: %s Profile %"PRIu32":",
+ __func__, tx ? "TX" : "RX", profile);
+
+ if (tx)
+ offs = REG_TX_FAST_LOCK_SETUP - REG_RX_FAST_LOCK_SETUP;
+
+ buf[0] = values[0];
+ buf[1] = RX_FAST_LOCK_PROFILE_ADDR(profile) | RX_FAST_LOCK_PROFILE_WORD(0);
+ ad9361_spi_writem(phy->spi, REG_RX_FAST_LOCK_PROGRAM_DATA + offs, buf, 2);
+
+ for (i = 1; i < RX_FAST_LOCK_CONFIG_WORD_NUM; i++) {
+ buf[0] = RX_FAST_LOCK_PROGRAM_WRITE | RX_FAST_LOCK_PROGRAM_CLOCK_ENABLE;
+ buf[1] = 0;
+ buf[2] = values[i];
+ buf[3] = RX_FAST_LOCK_PROFILE_ADDR(profile) | RX_FAST_LOCK_PROFILE_WORD(i);
+ ad9361_spi_writem(phy->spi, REG_RX_FAST_LOCK_PROGRAM_CTRL + offs, buf, 4);
+ }
+
+ ad9361_spi_write(phy->spi, REG_RX_FAST_LOCK_PROGRAM_CTRL + offs,
+ RX_FAST_LOCK_PROGRAM_WRITE | RX_FAST_LOCK_PROGRAM_CLOCK_ENABLE);
+ ad9361_spi_write(phy->spi, REG_RX_FAST_LOCK_PROGRAM_CTRL + offs, 0);
+
+ phy->fastlock.entry[tx][profile].flags = FASTLOOK_INIT;
+ phy->fastlock.entry[tx][profile].alc_orig = values[15];
+ phy->fastlock.entry[tx][profile].alc_written = values[15];
+
+ return ret;
+}
+
+/**
+ * Fastlock store.
+ * @param phy The AD9361 state structure.
+ * @param tx
+ * @param profile
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_fastlock_store(struct ad9361_rf_phy *phy, bool tx, uint32_t profile)
+{
+ struct spi_device *spi = phy->spi;
+ uint8_t val[16];
+ uint32_t offs = 0, x, y;
+
+ dev_dbg(&phy->spi->dev, "%s: %s Profile %"PRIu32":",
+ __func__, tx ? "TX" : "RX", profile);
+
+ if (tx)
+ offs = REG_TX_FAST_LOCK_SETUP - REG_RX_FAST_LOCK_SETUP;
+
+ val[0] = ad9361_spi_read(spi, REG_RX_INTEGER_BYTE_0 + offs);
+ val[1] = ad9361_spi_read(spi, REG_RX_INTEGER_BYTE_1 + offs);
+ val[2] = ad9361_spi_read(spi, REG_RX_FRACT_BYTE_0 + offs);
+ val[3] = ad9361_spi_read(spi, REG_RX_FRACT_BYTE_1 + offs);
+ val[4] = ad9361_spi_read(spi, REG_RX_FRACT_BYTE_2 + offs);
+
+ x = ad9361_spi_readf(spi, REG_RX_VCO_BIAS_1 + offs, VCO_BIAS_REF(~0));
+ y = ad9361_spi_readf(spi, REG_RX_ALC_VARACTOR + offs, VCO_VARACTOR(~0));
+ val[5] = (x << 4) | y;
+
+ x = ad9361_spi_readf(spi, REG_RX_VCO_BIAS_1 + offs, VCO_BIAS_TCF(~0));
+ y = ad9361_spi_readf(spi, REG_RX_CP_CURRENT + offs, CHARGE_PUMP_CURRENT(~0));
+ /* Wide BW option: N = 1
+ * Set init and steady state values to the same - let user space handle it
+ */
+ val[6] = (x << 3) | y;
+ val[7] = y;
+
+ x = ad9361_spi_readf(spi, REG_RX_LOOP_FILTER_3 + offs, LOOP_FILTER_R3(~0));
+ val[8] = (x << 4) | x;
+
+ x = ad9361_spi_readf(spi, REG_RX_LOOP_FILTER_2 + offs, LOOP_FILTER_C3(~0));
+ val[9] = (x << 4) | x;
+
+ x = ad9361_spi_readf(spi, REG_RX_LOOP_FILTER_1 + offs, LOOP_FILTER_C1(~0));
+ y = ad9361_spi_readf(spi, REG_RX_LOOP_FILTER_1 + offs, LOOP_FILTER_C2(~0));
+ val[10] = (x << 4) | y;
+
+ x = ad9361_spi_readf(spi, REG_RX_LOOP_FILTER_2 + offs, LOOP_FILTER_R1(~0));
+ val[11] = (x << 4) | x;
+
+ x = ad9361_spi_readf(spi, REG_RX_VCO_VARACTOR_CTRL_0 + offs,
+ VCO_VARACTOR_REFERENCE_TCF(~0));
+ y = ad9361_spi_readf(spi, REG_RFPLL_DIVIDERS,
+ tx ? TX_VCO_DIVIDER(~0) : RX_VCO_DIVIDER(~0));
+ val[12] = (x << 4) | y;
+
+ x = ad9361_spi_readf(spi, REG_RX_FORCE_VCO_TUNE_1 + offs, VCO_CAL_OFFSET(~0));
+ y = ad9361_spi_readf(spi, REG_RX_VCO_VARACTOR_CTRL_1 + offs, VCO_VARACTOR_REFERENCE(~0));
+ val[13] = (x << 4) | y;
+
+ val[14] = ad9361_spi_read(spi, REG_RX_FORCE_VCO_TUNE_0 + offs);
+
+ x = ad9361_spi_readf(spi, REG_RX_FORCE_ALC + offs, FORCE_ALC_WORD(~0));
+ y = ad9361_spi_readf(spi, REG_RX_FORCE_VCO_TUNE_1 + offs, FORCE_VCO_TUNE);
+ val[15] = (x << 1) | y;
+
+ return ad9361_fastlock_load(phy, tx, profile, val);
+}
+
+/**
+ * Fastlock prepare.
+ * @param phy The AD9361 state structure.
+ * @param tx
+ * @param profile
+ * @param prepare
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_fastlock_prepare(struct ad9361_rf_phy *phy, bool tx,
+ uint32_t profile, bool prepare)
+{
+ uint32_t offs, ready_mask;
+ bool is_prepared;
+
+ dev_dbg(&phy->spi->dev, "%s: %s Profile %"PRIu32": %s",
+ __func__, tx ? "TX" : "RX", profile,
+ prepare ? "Prepare" : "Un-Prepare");
+
+ if (tx) {
+ offs = REG_TX_FAST_LOCK_SETUP - REG_RX_FAST_LOCK_SETUP;
+ ready_mask = TX_SYNTH_READY_MASK;
+ }
+ else {
+ offs = 0;
+ ready_mask = RX_SYNTH_READY_MASK;
+ }
+
+ is_prepared = !!phy->fastlock.current_profile[tx];
+
+ if (prepare && !is_prepared) {
+ ad9361_spi_write(phy->spi,
+ REG_RX_FAST_LOCK_SETUP_INIT_DELAY + offs,
+ (tx ? phy->pdata->tx_fastlock_delay_ns :
+ phy->pdata->rx_fastlock_delay_ns) / 250);
+ ad9361_spi_write(phy->spi, REG_RX_FAST_LOCK_SETUP + offs,
+ RX_FAST_LOCK_PROFILE(profile) |
+ RX_FAST_LOCK_MODE_ENABLE);
+ ad9361_spi_write(phy->spi, REG_RX_FAST_LOCK_PROGRAM_CTRL + offs,
+ 0);
+
+ ad9361_spi_writef(phy->spi, REG_ENSM_CONFIG_2, ready_mask, 1);
+ ad9361_trx_vco_cal_control(phy, tx, false);
+ }
+ else if (!prepare && is_prepared) {
+ ad9361_spi_write(phy->spi, REG_RX_FAST_LOCK_SETUP + offs, 0);
+
+ /* Workaround: Exiting Fastlock Mode */
+ ad9361_spi_writef(phy->spi, REG_RX_FORCE_ALC + offs, FORCE_ALC_ENABLE, 1);
+ ad9361_spi_writef(phy->spi, REG_RX_FORCE_VCO_TUNE_1 + offs, FORCE_VCO_TUNE, 1);
+ ad9361_spi_writef(phy->spi, REG_RX_FORCE_ALC + offs, FORCE_ALC_ENABLE, 0);
+ ad9361_spi_writef(phy->spi, REG_RX_FORCE_VCO_TUNE_1 + offs, FORCE_VCO_TUNE, 0);
+
+ ad9361_trx_vco_cal_control(phy, tx, true);
+ ad9361_spi_writef(phy->spi, REG_ENSM_CONFIG_2, ready_mask, 0);
+
+ phy->fastlock.current_profile[tx] = 0;
+ }
+
+ return 0;
+}
+
+/**
+ * Fastlock recall.
+ * @param phy The AD9361 state structure.
+ * @param tx
+ * @param profile
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_fastlock_recall(struct ad9361_rf_phy *phy, bool tx, uint32_t profile)
+{
+ uint32_t offs = 0;
+ uint8_t curr, _new, orig, current_profile;
+
+ dev_dbg(&phy->spi->dev, "%s: %s Profile %"PRIu32":",
+ __func__, tx ? "TX" : "RX", profile);
+
+ if (tx)
+ offs = REG_TX_FAST_LOCK_SETUP - REG_RX_FAST_LOCK_SETUP;
+
+ if (phy->fastlock.entry[tx][profile].flags != FASTLOOK_INIT)
+ return -EINVAL;
+
+ /* Workaround: Lock problem with same ALC word */
+
+ current_profile = phy->fastlock.current_profile[tx];
+ _new = phy->fastlock.entry[tx][profile].alc_written;
+
+ if (current_profile == 0)
+ curr = ad9361_spi_readf(phy->spi, REG_RX_FORCE_ALC + offs,
+ FORCE_ALC_WORD(~0)) << 1;
+ else
+ curr = phy->fastlock.entry[tx][current_profile - 1].alc_written;
+
+ if ((curr >> 1) == (_new >> 1)) {
+ orig = phy->fastlock.entry[tx][profile].alc_orig;
+
+ if ((orig >> 1) == (_new >> 1))
+ phy->fastlock.entry[tx][profile].alc_written += 2;
+ else
+ phy->fastlock.entry[tx][profile].alc_written = orig;
+
+ ad9361_fastlock_writeval(phy->spi, tx, profile, 0xF,
+ phy->fastlock.entry[tx][profile].alc_written, true);
+ }
+
+ ad9361_fastlock_prepare(phy, tx, profile, true);
+ phy->fastlock.current_profile[tx] = profile + 1;
+
+ return ad9361_spi_write(phy->spi, REG_RX_FAST_LOCK_SETUP + offs,
+ RX_FAST_LOCK_PROFILE(profile) |
+ (phy->pdata->trx_fastlock_pinctrl_en[tx] ?
+ RX_FAST_LOCK_PROFILE_PIN_SELECT : 0) |
+ RX_FAST_LOCK_MODE_ENABLE);
+}
+
+/**
+ * Fastlock save.
+ * @param phy The AD9361 state structure.
+ * @param tx
+ * @param profile
+ * @param values
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_fastlock_save(struct ad9361_rf_phy *phy, bool tx,
+ uint32_t profile, uint8_t *values)
+{
+ int32_t i;
+
+ dev_dbg(&phy->spi->dev, "%s: %s Profile %"PRIu32":",
+ __func__, tx ? "TX" : "RX", profile);
+
+ for (i = 0; i < RX_FAST_LOCK_CONFIG_WORD_NUM; i++)
+ values[i] = ad9361_fastlock_readval(phy->spi, tx, profile, i);
+
+ return 0;
+}
+
+/**
+ * Multi Chip Sync (MCS) config.
+ * @param phy The AD9361 state structure.
+ * @param step MCS step.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_mcs(struct ad9361_rf_phy *phy, int32_t step)
+{
+ int32_t mcs_mask = MCS_RF_ENABLE | MCS_BBPLL_ENABLE |
+ MCS_DIGITAL_CLK_ENABLE | MCS_BB_ENABLE;
+
+ dev_dbg(&phy->spi->dev, "%s: MCS step %"PRId32, __func__, step);
+
+ switch (step) {
+ case 0:
+ /* REVIST:
+ * POWER_DOWN_TRX_SYNTH and MCS_RF_ENABLE somehow conflict
+ */
+ ad9361_spi_writef(phy->spi, REG_ENSM_CONFIG_2,
+ POWER_DOWN_TX_SYNTH | POWER_DOWN_RX_SYNTH, 0);
+ case 1:
+ /* REVIST:
+ * POWER_DOWN_TRX_SYNTH and MCS_RF_ENABLE somehow conflict
+ */
+ ad9361_spi_writef(phy->spi, REG_ENSM_CONFIG_2,
+ POWER_DOWN_TX_SYNTH | POWER_DOWN_RX_SYNTH, 0);
+
+ ad9361_spi_writef(phy->spi, REG_MULTICHIP_SYNC_AND_TX_MON_CTRL,
+ mcs_mask, MCS_BB_ENABLE | MCS_BBPLL_ENABLE | MCS_RF_ENABLE);
+ ad9361_spi_writef(phy->spi, REG_CP_BLEED_CURRENT,
+ MCS_REFCLK_SCALE_EN, 1);
+ break;
+ case 2:
+#ifdef NUAND_MODIFICATIONS
+ // use alternate gpio accessors
+ if(!gpio_is_valid(phy->gpio, phy->pdata->gpio_sync))
+ break;
+#else
+ if(!gpio_is_valid(phy->pdata->gpio_sync))
+ break;
+#endif // NUAND_MODIFICATIONS
+ /*
+ * NOTE: This is not a regular GPIO -
+ * HDL ensures Multi-chip Synchronization SYNC_IN Pulse Timing
+ * relative to rising and falling edge of REF_CLK
+ */
+#ifdef NUAND_MODIFICATIONS
+ // use alternate gpio accessors
+ if(!gpio_is_valid(phy->gpio, phy->pdata->gpio_sync))
+ break;
+ gpio_set_value(phy->gpio, phy->pdata->gpio_sync, 1);
+ gpio_set_value(phy->gpio, phy->pdata->gpio_sync, 0);
+#else
+ gpio_set_value(phy->pdata->gpio_sync, 1);
+ gpio_set_value(phy->pdata->gpio_sync, 0);
+ break;
+#endif // NUAND_MODIFICATIONS
+ case 3:
+ ad9361_spi_writef(phy->spi, REG_MULTICHIP_SYNC_AND_TX_MON_CTRL,
+ mcs_mask, MCS_BB_ENABLE | MCS_DIGITAL_CLK_ENABLE | MCS_RF_ENABLE);
+ break;
+ case 4:
+#ifdef NUAND_MODIFICATIONS
+ // use alternate gpio accessors
+ if(!gpio_is_valid(phy->gpio, phy->pdata->gpio_sync))
+ break;
+ gpio_set_value(phy->gpio, phy->pdata->gpio_sync, 1);
+ gpio_set_value(phy->gpio, phy->pdata->gpio_sync, 0);
+ break;
+#else
+ if(!gpio_is_valid(phy->pdata->gpio_sync))
+ break;
+ gpio_set_value(phy->pdata->gpio_sync, 1);
+ gpio_set_value(phy->pdata->gpio_sync, 0);
+ break;
+#endif // NUAND_MODIFICATIONS
+ case 5:
+ ad9361_spi_writef(phy->spi, REG_MULTICHIP_SYNC_AND_TX_MON_CTRL,
+ mcs_mask, MCS_RF_ENABLE);
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * Clear state.
+ * @param phy The AD9361 state structure.
+ * @return None.
+ */
+void ad9361_clear_state(struct ad9361_rf_phy *phy)
+{
+ phy->current_table = RXGAIN_TBLS_END;
+ phy->bypass_tx_fir = true;
+ phy->bypass_rx_fir = true;
+ phy->rate_governor = 1;
+ phy->rfdc_track_en = true;
+ phy->bbdc_track_en = true;
+ phy->quad_track_en = true;
+ phy->prev_ensm_state = 0;
+ phy->curr_ensm_state = 0;
+ phy->auto_cal_en = false;
+ phy->last_tx_quad_cal_freq = 0;
+ phy->flags = 0;
+ phy->current_rx_bw_Hz = 0;
+ phy->current_tx_bw_Hz = 0;
+ phy->rxbbf_div = 0;
+ phy->tx_fir_int = 0;
+ phy->tx_fir_ntaps = 0;
+ phy->rx_fir_dec = 0;
+ phy->rx_fir_ntaps = 0;
+ phy->ensm_pin_ctl_en = false;
+ phy->txmon_tdd_en = 0;
+ phy->current_tx_lo_freq = 0;
+ phy->current_rx_lo_freq = 0;
+ phy->current_tx_use_tdd_table = false;
+ phy->current_rx_use_tdd_table = false;
+
+ memset(&phy->fastlock, 0, sizeof(phy->fastlock));
+}
+
+/**
+ * Determine the reference frequency value.
+ * @param refin_Hz Maximum allowed frequency.
+ * @param max Reference in frequency value.
+ * @return Reference frequency value.
+ */
+static uint32_t ad9361_ref_div_sel(uint32_t refin_Hz, uint32_t max)
+{
+ if (refin_Hz <= (max / 2))
+ return 2 * refin_Hz;
+ else if (refin_Hz <= max)
+ return refin_Hz;
+ else if (refin_Hz <= (max * 2))
+ return refin_Hz / 2;
+ else if (refin_Hz <= (max * 4))
+ return refin_Hz / 4;
+ else
+ return 0;
+}
+
+/**
+ * Setup the AD9361 device.
+ * @param phy The AD9361 state structure.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_setup(struct ad9361_rf_phy *phy)
+{
+ uint32_t refin_Hz, ref_freq, bbpll_freq;
+ struct spi_device *spi = phy->spi;
+ struct ad9361_phy_platform_data *pd = phy->pdata;
+ int32_t ret;
+ uint32_t real_rx_bandwidth, real_tx_bandwidth;
+ bool tmp_use_ext_rx_lo = pd->use_ext_rx_lo;
+ bool tmp_use_ext_tx_lo = pd->use_ext_tx_lo;
+
+ dev_dbg(dev, "%s", __func__);
+
+ pd->rf_rx_bandwidth_Hz = ad9361_validate_rf_bw(phy, pd->rf_rx_bandwidth_Hz);
+ pd->rf_tx_bandwidth_Hz = ad9361_validate_rf_bw(phy, pd->rf_tx_bandwidth_Hz);
+
+ real_rx_bandwidth = pd->rf_rx_bandwidth_Hz / 2;
+ real_tx_bandwidth = pd->rf_tx_bandwidth_Hz / 2;
+
+ if (pd->fdd) {
+ pd->tdd_skip_vco_cal = false;
+ if (pd->ensm_pin_ctrl && pd->fdd_independent_mode) {
+ dev_warn(dev,
+ "%s: Either set ENSM PINCTRL or FDD Independent Mode",
+ __func__);
+ pd->ensm_pin_ctrl = false;
+ }
+ }
+
+ if (pd->port_ctrl.pp_conf[2] & FDD_RX_RATE_2TX_RATE)
+ phy->rx_eq_2tx = true;
+
+ ad9361_spi_write(spi, REG_CTRL, CTRL_ENABLE);
+ ad9361_spi_write(spi, REG_BANDGAP_CONFIG0, MASTER_BIAS_TRIM(0x0E)); /* Enable Master Bias */
+ ad9361_spi_write(spi, REG_BANDGAP_CONFIG1, BANDGAP_TEMP_TRIM(0x0E)); /* Set Bandgap Trim */
+
+ ad9361_set_dcxo_tune(phy, pd->dcxo_coarse, pd->dcxo_fine);
+
+ refin_Hz = phy->clk_refin->rate;
+
+ ref_freq = ad9361_ref_div_sel(refin_Hz, MAX_BBPLL_FREF);
+ if (!ref_freq)
+ return -EINVAL;
+
+ ad9361_spi_writef(spi, REG_REF_DIVIDE_CONFIG_1, RX_REF_RESET_BAR, 1);
+ ad9361_spi_writef(spi, REG_REF_DIVIDE_CONFIG_2, TX_REF_RESET_BAR, 1);
+ ad9361_spi_writef(spi, REG_REF_DIVIDE_CONFIG_2,
+ TX_REF_DOUBLER_FB_DELAY(~0), 3); /* FB DELAY */
+ ad9361_spi_writef(spi, REG_REF_DIVIDE_CONFIG_2,
+ RX_REF_DOUBLER_FB_DELAY(~0), 3); /* FB DELAY */
+
+ ad9361_spi_write(spi, REG_CLOCK_ENABLE,
+ DIGITAL_POWER_UP | CLOCK_ENABLE_DFLT | BBPLL_ENABLE |
+ (pd->use_extclk ? XO_BYPASS : 0)); /* Enable Clocks */
+
+ ret = clk_set_rate(phy, phy->ref_clk_scale[BB_REFCLK], ref_freq);
+ if (ret < 0) {
+ dev_err(dev, "Failed to set BB ref clock rate (%"PRId32")",
+ ret);
+ return ret;
+ }
+
+ ret = ad9361_set_trx_clock_chain(phy, pd->rx_path_clks,
+ pd->tx_path_clks);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_prepare_enable(phy->clks[BB_REFCLK]);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable BB ref clock rate (%"PRId32")",
+ ret);
+ return ret;
+ }
+
+ if (!pd->rx2tx2) {
+ pd->rx1tx1_mode_use_tx_num =
+ clamp_t(uint32_t, pd->rx1tx1_mode_use_tx_num, TX_1, TX_2);
+ pd->rx1tx1_mode_use_rx_num =
+ clamp_t(uint32_t, pd->rx1tx1_mode_use_rx_num, RX_1, RX_2);
+
+ ad9361_en_dis_tx(phy, TX_1 | TX_2, pd->rx1tx1_mode_use_tx_num);
+ ad9361_en_dis_rx(phy, TX_1 | TX_2, pd->rx1tx1_mode_use_rx_num);
+ } else {
+ ad9361_en_dis_tx(phy, TX_1 | TX_2, TX_1 | TX_2);
+ ad9361_en_dis_rx(phy, RX_1 | RX_2, RX_1 | RX_2);
+ }
+
+ ret = ad9361_rf_port_setup(phy, true, pd->rf_rx_input_sel,
+ pd->rf_tx_output_sel);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9361_pp_port_setup(phy, false);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9361_auxdac_setup(phy, &pd->auxdac_ctrl);
+ if (ret < 0)
+ return ret;
+
+ bbpll_freq = clk_get_rate(phy, phy->ref_clk_scale[BBPLL_CLK]);
+ ret = ad9361_auxadc_setup(phy, &pd->auxadc_ctrl, bbpll_freq);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9361_ctrl_outs_setup(phy, &pd->ctrl_outs_ctrl);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9361_gpo_setup(phy, &pd->gpo_ctrl);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9361_set_ref_clk_cycles(phy, refin_Hz);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9361_setup_ext_lna(phy, &pd->elna_ctrl);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * This allows forcing a lower F_REF window
+ * (worse phase noise, better fractional spurs)
+ */
+ pd->trx_synth_max_fref = clamp_t(uint32_t, pd->trx_synth_max_fref,
+ MIN_SYNTH_FREF, MAX_SYNTH_FREF);
+
+ ref_freq = ad9361_ref_div_sel(refin_Hz, pd->trx_synth_max_fref);
+ if (!ref_freq)
+ return -EINVAL;
+
+ ret = clk_set_rate(phy, phy->ref_clk_scale[RX_REFCLK], ref_freq);
+ if (ret < 0) {
+ dev_err(dev, "Failed to set RX Synth ref clock rate (%"PRId32")", ret);
+ return ret;
+ }
+
+ ret = clk_set_rate(phy, phy->ref_clk_scale[TX_REFCLK], ref_freq);
+ if (ret < 0) {
+ dev_err(dev, "Failed to set TX Synth ref clock rate (%"PRId32")", ret);
+ return ret;
+ }
+
+ ret = ad9361_txrx_synth_cp_calib(phy, ref_freq, false); /* RXCP */
+ if (ret < 0)
+ return ret;
+
+ ret = ad9361_txrx_synth_cp_calib(phy, ref_freq, true); /* TXCP */
+ if (ret < 0)
+ return ret;
+
+ phy->pdata->use_ext_rx_lo = 0;
+ phy->pdata->use_ext_tx_lo = 0;
+
+ ret = clk_set_rate(phy, phy->ref_clk_scale[RX_RFPLL], ad9361_to_clk(pd->rx_synth_freq));
+ if (ret < 0) {
+ dev_err(dev, "Failed to set RX Synth rate (%"PRId32")",
+ ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(phy->clks[RX_REFCLK]);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable RX Synth ref clock (%"PRId32")", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(phy->clks[RX_RFPLL]);
+ if (ret < 0)
+ return ret;
+
+ /* Skip quad cal here we do it later again */
+ phy->last_tx_quad_cal_freq = pd->tx_synth_freq;
+ ret = clk_set_rate(phy, phy->ref_clk_scale[TX_RFPLL], ad9361_to_clk(pd->tx_synth_freq));
+ if (ret < 0) {
+ dev_err(dev, "Failed to set TX Synth rate (%"PRId32")",
+ ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(phy->clks[TX_REFCLK]);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable TX Synth ref clock (%"PRId32")", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(phy->clks[TX_RFPLL]);
+ if (ret < 0)
+ return ret;
+
+ phy->pdata->use_ext_rx_lo = tmp_use_ext_rx_lo;
+ phy->pdata->use_ext_tx_lo = tmp_use_ext_tx_lo;
+
+ ad9361_clk_mux_set_parent(phy->ref_clk_scale[RX_RFPLL],
+ pd->use_ext_rx_lo);
+
+ ad9361_clk_mux_set_parent(phy->ref_clk_scale[TX_RFPLL],
+ pd->use_ext_tx_lo);
+
+ ret = ad9361_load_mixer_gm_subtable(phy);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9361_gc_setup(phy, &pd->gain_ctrl);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9361_rx_bb_analog_filter_calib(phy,
+ real_rx_bandwidth,
+ bbpll_freq);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9361_tx_bb_analog_filter_calib(phy,
+ real_tx_bandwidth,
+ bbpll_freq);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9361_rx_tia_calib(phy, real_rx_bandwidth);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9361_tx_bb_second_filter_calib(phy, real_tx_bandwidth);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9361_rx_adc_setup(phy,
+ bbpll_freq,
+ clk_get_rate(phy, phy->ref_clk_scale[ADC_CLK]));
+ if (ret < 0)
+ return ret;
+
+ ret = ad9361_bb_dc_offset_calib(phy);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9361_rf_dc_offset_calib(phy,
+ ad9361_from_clk(clk_get_rate(phy, phy->ref_clk_scale[RX_RFPLL])));
+ if (ret < 0)
+ return ret;
+
+ phy->current_rx_bw_Hz = pd->rf_rx_bandwidth_Hz;
+ phy->current_tx_bw_Hz = pd->rf_tx_bandwidth_Hz;
+ phy->last_tx_quad_cal_phase = ~0;
+ ret = ad9361_tx_quad_calib(phy, real_rx_bandwidth, real_tx_bandwidth, -1);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9361_tracking_control(phy, phy->bbdc_track_en,
+ phy->rfdc_track_en, phy->quad_track_en);
+ if (ret < 0)
+ return ret;
+
+ if (!pd->fdd)
+ ad9361_run_calibration(phy, TXMON_CAL);
+
+ ad9361_pp_port_setup(phy, true);
+
+ ret = ad9361_set_ensm_mode(phy, pd->fdd, pd->ensm_pin_ctrl);
+ if (ret < 0)
+ return ret;
+
+ ad9361_spi_writef(phy->spi, REG_TX_ATTEN_OFFSET,
+ MASK_CLR_ATTEN_UPDATE, 0);
+
+ ret = ad9361_set_tx_atten(phy, pd->tx_atten,
+ pd->rx2tx2 ? true : pd->rx1tx1_mode_use_tx_num == 1,
+ pd->rx2tx2 ? true : pd->rx1tx1_mode_use_tx_num == 2, true);
+ if (ret < 0)
+ return ret;
+
+ if (!pd->rx2tx2) {
+ ret = ad9361_set_tx_atten(phy, 89750,
+ pd->rx1tx1_mode_use_tx_num == 2,
+ pd->rx1tx1_mode_use_tx_num == 1, true);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = ad9361_rssi_setup(phy, &pd->rssi_ctrl, false);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9361_clkout_control(phy, pd->ad9361_clkout_mode);
+ if (ret < 0)
+ return ret;
+
+
+ ret = ad9361_txmon_setup(phy, &pd->txmon_ctrl);
+ if (ret < 0)
+ return ret;
+
+ phy->curr_ensm_state = ad9361_spi_readf(spi, REG_STATE, ENSM_STATE(~0));
+ ad9361_ensm_set_state(phy, pd->fdd ? ENSM_STATE_FDD : ENSM_STATE_RX,
+ pd->ensm_pin_ctrl);
+
+ phy->auto_cal_en = true;
+ phy->cal_threshold_freq = 100000000ULL; /* 100 MHz */
+
+ return 0;
+
+}
+
+/**
+ * Perform the selected calibration
+ * @param phy The AD9361 state structure.
+ * @param cal The selected calibration.
+ * @param arg The argument of the calibration.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_do_calib_run(struct ad9361_rf_phy *phy, uint32_t cal, int32_t arg)
+{
+ int32_t ret;
+
+ dev_dbg(&phy->spi->dev, "%s: CAL %"PRIu32" ARG %"PRId32, __func__, cal, arg);
+
+ ret = ad9361_tracking_control(phy, false, false, false);
+ if (ret < 0)
+ return ret;
+
+ ad9361_ensm_force_state(phy, ENSM_STATE_ALERT);
+
+ switch (cal) {
+ case TX_QUAD_CAL:
+ ret = ad9361_tx_quad_calib(phy, phy->current_rx_bw_Hz / 2,
+ phy->current_tx_bw_Hz / 2, arg);
+ break;
+ case RFDC_CAL:
+ ret = ad9361_rf_dc_offset_calib(phy,
+ ad9361_from_clk(clk_get_rate(phy, phy->ref_clk_scale[RX_RFPLL])));
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ ret = ad9361_tracking_control(phy, phy->bbdc_track_en,
+ phy->rfdc_track_en, phy->quad_track_en);
+ ad9361_ensm_restore_prev_state(phy);
+
+ return ret;
+}
+
+/**
+ * Set the RF bandwidth.
+ * @param phy The AD9361 state structure.
+ * @param rf_rx_bw The desired RX bandwidth [Hz].
+ * @param rf_tx_bw The desired TX bandwidth [Hz].
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_update_rf_bandwidth(struct ad9361_rf_phy *phy,
+ uint32_t rf_rx_bw, uint32_t rf_tx_bw)
+{
+ int32_t ret;
+
+ ret = ad9361_tracking_control(phy, false, false, false);
+ if (ret < 0)
+ return ret;
+
+ ad9361_ensm_force_state(phy, ENSM_STATE_ALERT);
+
+ ret = __ad9361_update_rf_bandwidth(phy, rf_rx_bw, rf_tx_bw);
+ if (ret < 0)
+ return ret;
+
+ phy->current_rx_bw_Hz = rf_rx_bw;
+ phy->current_tx_bw_Hz = rf_tx_bw;
+
+ ret = ad9361_tx_quad_calib(phy, rf_rx_bw / 2, rf_tx_bw / 2, -1);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9361_tracking_control(phy, phy->bbdc_track_en,
+ phy->rfdc_track_en, phy->quad_track_en);
+ if (ret < 0)
+ return ret;
+
+ ad9361_ensm_restore_prev_state(phy);
+
+ return 0;
+}
+
+/**
+ * Verify the FIR filter coefficients.
+ * @param phy The AD9361 state structure.
+ * @param dest Destination identifier (RX1,2 / TX1,2).
+ * @param ntaps Number of filter Taps.
+ * @param coef Pointer to filter coefficients.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_verify_fir_filter_coef(struct ad9361_rf_phy *phy,
+ enum fir_dest dest,
+ uint32_t ntaps, short *coef)
+{
+ struct spi_device *spi = phy->spi;
+ uint32_t val, offs = 0, gain = 0, conf, sel, cnt;
+ int32_t ret = 0;
+
+#ifndef DEBUG
+ return 0;
+#endif
+ dev_dbg(&phy->spi->dev, "%s: TAPS %"PRIu32", dest %d",
+ __func__, ntaps, dest);
+
+ if (dest & FIR_IS_RX) {
+ gain = ad9361_spi_read(spi, REG_RX_FILTER_GAIN);
+ offs = REG_RX_FILTER_COEF_ADDR - REG_TX_FILTER_COEF_ADDR;
+ ad9361_spi_write(spi, REG_RX_FILTER_GAIN, 0);
+ }
+
+ conf = ad9361_spi_read(spi, REG_TX_FILTER_CONF + offs);
+
+ if ((dest & 3) == 3) {
+ sel = 1;
+ cnt = 2;
+ } else {
+ sel = (dest & 3);
+ cnt = 1;
+ }
+
+ for (; cnt > 0; cnt--, sel++) {
+
+ ad9361_spi_write(spi, REG_TX_FILTER_CONF + offs,
+ FIR_NUM_TAPS(ntaps / 16 - 1) |
+ FIR_SELECT(sel) | FIR_START_CLK);
+ for (val = 0; val < ntaps; val++) {
+ short tmp;
+ ad9361_spi_write(spi, REG_TX_FILTER_COEF_ADDR + offs, val);
+
+ tmp = (ad9361_spi_read(spi, REG_TX_FILTER_COEF_READ_DATA_1 + offs) & 0xFF) |
+ (ad9361_spi_read(spi, REG_TX_FILTER_COEF_READ_DATA_2 + offs) << 8);
+
+ if (tmp != coef[val]) {
+ dev_err(&phy->spi->dev,"%s%"PRIu32" read verify failed TAP%"PRIu32" %d =! %d",
+ (dest & FIR_IS_RX) ? "RX" : "TX", sel,
+ val, tmp, coef[val]);
+ ret = -EIO;
+ }
+ }
+ }
+
+ if (dest & FIR_IS_RX) {
+ ad9361_spi_write(spi, REG_RX_FILTER_GAIN, gain);
+ }
+
+ ad9361_spi_write(spi, REG_TX_FILTER_CONF + offs, conf);
+
+ return ret;
+}
+
+/**
+ * Load the FIR filter coefficients.
+ * @param phy The AD9361 state structure.
+ * @param dest Destination identifier (RX1,2 / TX1,2).
+ * @param gain_dB Gain option.
+ * @param ntaps Number of filter Taps.
+ * @param coef Pointer to filter coefficients.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_load_fir_filter_coef(struct ad9361_rf_phy *phy,
+ enum fir_dest dest, int32_t gain_dB,
+ uint32_t ntaps, int16_t *coef)
+{
+ struct spi_device *spi = phy->spi;
+ uint32_t val, offs = 0, fir_conf = 0, fir_enable = 0;
+
+ dev_dbg(&phy->spi->dev, "%s: TAPS %"PRIu32", gain %"PRId32", dest %d",
+ __func__, ntaps, gain_dB, dest);
+
+ if (coef == NULL || !ntaps || ntaps > 128 || ntaps % 16) {
+ dev_err(&phy->spi->dev,
+ "%s: Invalid parameters: TAPS %"PRIu32", gain %"PRId32", dest 0x%X",
+ __func__, ntaps, gain_dB, dest);
+
+ return -EINVAL;
+ }
+
+ ad9361_ensm_force_state(phy, ENSM_STATE_ALERT);
+
+ if (dest & FIR_IS_RX) {
+ val = 3 - (gain_dB + 12) / 6;
+ ad9361_spi_write(spi, REG_RX_FILTER_GAIN, val & 0x3);
+ offs = REG_RX_FILTER_COEF_ADDR - REG_TX_FILTER_COEF_ADDR;
+ phy->rx_fir_ntaps = ntaps;
+ fir_enable = ad9361_spi_readf(phy->spi,
+ REG_RX_ENABLE_FILTER_CTRL, RX_FIR_ENABLE_DECIMATION(~0));
+ ad9361_spi_writef(phy->spi, REG_RX_ENABLE_FILTER_CTRL,
+ RX_FIR_ENABLE_DECIMATION(~0),
+ (phy->rx_fir_dec == 4) ? 3 : phy->rx_fir_dec);
+ }
+ else {
+ if (gain_dB == -6)
+ fir_conf = TX_FIR_GAIN_6DB;
+ phy->tx_fir_ntaps = ntaps;
+ fir_enable = ad9361_spi_readf(phy->spi,
+ REG_TX_ENABLE_FILTER_CTRL, TX_FIR_ENABLE_INTERPOLATION(~0));
+ ad9361_spi_writef(phy->spi, REG_TX_ENABLE_FILTER_CTRL,
+ TX_FIR_ENABLE_INTERPOLATION(~0),
+ (phy->tx_fir_int == 4) ? 3 : phy->tx_fir_int);
+ }
+
+ val = ntaps / 16 - 1;
+
+ fir_conf |= FIR_NUM_TAPS(val) | FIR_SELECT(dest) | FIR_START_CLK;
+
+ ad9361_spi_write(spi, REG_TX_FILTER_CONF + offs, fir_conf);
+
+ for (val = 0; val < ntaps; val++) {
+ ad9361_spi_write(spi, REG_TX_FILTER_COEF_ADDR + offs, val);
+ ad9361_spi_write(spi, REG_TX_FILTER_COEF_WRITE_DATA_1 + offs,
+ coef[val] & 0xFF);
+ ad9361_spi_write(spi, REG_TX_FILTER_COEF_WRITE_DATA_2 + offs,
+ coef[val] >> 8);
+ ad9361_spi_write(spi, REG_TX_FILTER_CONF + offs,
+ fir_conf | FIR_WRITE);
+ ad9361_spi_write(spi, REG_TX_FILTER_COEF_READ_DATA_2 + offs, 0);
+ ad9361_spi_write(spi, REG_TX_FILTER_COEF_READ_DATA_2 + offs, 0);
+ }
+
+ ad9361_spi_write(spi, REG_TX_FILTER_CONF + offs, fir_conf);
+ fir_conf &= ~FIR_START_CLK;
+ ad9361_spi_write(spi, REG_TX_FILTER_CONF + offs, fir_conf);
+
+ if (dest & FIR_IS_RX)
+ ad9361_spi_writef(phy->spi, REG_RX_ENABLE_FILTER_CTRL,
+ RX_FIR_ENABLE_DECIMATION(~0), fir_enable);
+ else
+ ad9361_spi_writef(phy->spi, REG_TX_ENABLE_FILTER_CTRL,
+ TX_FIR_ENABLE_INTERPOLATION(~0), fir_enable);
+
+ ad9361_ensm_restore_prev_state(phy);
+
+ return ad9361_verify_fir_filter_coef(phy, dest, ntaps, coef);
+}
+
+#ifndef NUAND_MODIFICATIONS
+/**
+ * Parse the FIR filter file/buffer.
+ * @param phy The AD9361 state structure.
+ * @param data Pointer to buffer.
+ * @param size Buffer size.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_parse_fir(struct ad9361_rf_phy *phy,
+ char *data, uint32_t size)
+{
+ char *line;
+ int32_t i = 0, ret, txc, rxc;
+ int32_t tx = -1, tx_gain, tx_int;
+ int32_t rx = -1, rx_gain, rx_dec;
+ int32_t rtx = -1, rrx = -1;
+ int16_t coef_tx[128];
+ int16_t coef_rx[128];
+ char *ptr = data;
+
+ phy->filt_rx_bw_Hz = 0;
+ phy->filt_tx_bw_Hz = 0;
+ phy->filt_valid = false;
+
+ while ((line = strsep(&ptr, "\n"))) {
+ if (line >= data + size) {
+ break;
+ }
+
+ if (line[0] == '#')
+ continue;
+
+ if (tx < 0) {
+#ifdef WIN32
+ ret = sscanf_s(line, "TX %d GAIN %d INT %d",
+ &tx, &tx_gain, &tx_int);
+#else
+ ret = sscanf(line, "TX %"PRId32" GAIN %"PRId32" INT %"PRId32,
+ &tx, &tx_gain, &tx_int);
+#endif
+ if (ret == 3)
+ continue;
+ else
+ tx = -1;
+ }
+ if (rx < 0) {
+#ifdef WIN32
+ ret = sscanf_s(line, "RX %d GAIN %d DEC %d",
+ &rx, &rx_gain, &rx_dec);
+#else
+ ret = sscanf(line, "RX %"PRId32" GAIN %"PRId32" DEC %"PRId32,
+ &rx, &rx_gain, &rx_dec);
+#endif
+ if (ret == 3)
+ continue;
+ else
+ tx = -1;
+ }
+
+ if (rtx < 0) {
+#ifdef WIN32
+ ret = sscanf(line, "RTX %lu %lu %lu %lu %lu %lu",
+#else
+ ret = sscanf(line, "RTX %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32,
+#endif
+ &phy->filt_tx_path_clks[0],
+ &phy->filt_tx_path_clks[1],
+ &phy->filt_tx_path_clks[2],
+ &phy->filt_tx_path_clks[3],
+ &phy->filt_tx_path_clks[4],
+ &phy->filt_tx_path_clks[5]);
+ if (ret == 6) {
+ rtx = 0;
+ continue;
+ } else {
+ rtx = -1;
+ }
+ }
+
+ if (rrx < 0) {
+#ifdef WIN32
+ ret = sscanf(line, "RRX %lu %lu %lu %lu %lu %lu",
+#else
+ ret = sscanf(line, "RRX %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32,
+#endif
+ &phy->filt_rx_path_clks[0],
+ &phy->filt_rx_path_clks[1],
+ &phy->filt_rx_path_clks[2],
+ &phy->filt_rx_path_clks[3],
+ &phy->filt_rx_path_clks[4],
+ &phy->filt_rx_path_clks[5]);
+ if (ret == 6) {
+ rrx = 0;
+ continue;
+ } else {
+ rrx = -1;
+ }
+ }
+
+ if (!phy->filt_rx_bw_Hz) {
+#ifdef WIN32
+ ret = sscanf(line, "BWRX %d", &phy->filt_rx_bw_Hz);
+#else
+ ret = sscanf(line, "BWRX %"PRId32, &phy->filt_rx_bw_Hz);
+#endif
+ if (ret == 1)
+ continue;
+ else
+ phy->filt_rx_bw_Hz = 0;
+ }
+
+ if (!phy->filt_tx_bw_Hz) {
+#ifdef WIN32
+ ret = sscanf(line, "BWTX %d", &phy->filt_tx_bw_Hz);
+#else
+ ret = sscanf(line, "BWTX %"PRId32, &phy->filt_tx_bw_Hz);
+#endif
+ if (ret == 1)
+ continue;
+ else
+ phy->filt_tx_bw_Hz = 0;
+ }
+
+#ifdef WIN32
+ ret = sscanf_s(line, "%d,%d", &txc, &rxc);
+#else
+ ret = sscanf(line, "%"PRId32",%"PRId32, &txc, &rxc);
+#endif
+ if (ret == 1) {
+ coef_tx[i] = coef_rx[i] = (int16_t)txc;
+ i++;
+ continue;
+ }
+ else if (ret == 2) {
+ coef_tx[i] = (int16_t)txc;
+ coef_rx[i] = (int16_t)rxc;
+ i++;
+ continue;
+ }
+ }
+
+ switch (tx) {
+ case FIR_TX1:
+ case FIR_TX2:
+ case FIR_TX1_TX2:
+ phy->tx_fir_int = tx_int;
+ ret = ad9361_load_fir_filter_coef(phy, (enum fir_dest)tx, tx_gain, i, coef_tx);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ switch (rx | FIR_IS_RX) {
+ case FIR_RX1:
+ case FIR_RX2:
+ case FIR_RX1_RX2:
+ phy->rx_fir_dec = rx_dec;
+ ret = ad9361_load_fir_filter_coef(phy, (enum fir_dest)(rx | FIR_IS_RX),
+ rx_gain, i, coef_rx);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ if (!(rrx | rtx))
+ phy->filt_valid = true;
+
+ return size;
+}
+#endif // !NUAND_MODIFICATIONS
+
+/**
+ * Validate FIR filter configuration - on pass enable.
+ * @param phy The AD9361 state structure.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_validate_enable_fir(struct ad9361_rf_phy *phy)
+{
+ int32_t ret;
+ uint32_t rx[6], tx[6];
+ uint32_t max, min, valid;
+
+ dev_dbg(dev, "%s: TX FIR EN=%d/TAPS%d/INT%d, RX FIR EN=%d/TAPS%d/DEC%d",
+ __func__, !phy->bypass_tx_fir, phy->tx_fir_ntaps, phy->tx_fir_int,
+ !phy->bypass_rx_fir, phy->rx_fir_ntaps, phy->rx_fir_dec);
+
+ if (!phy->bypass_tx_fir) {
+ if (!(phy->tx_fir_int == 1 || phy->tx_fir_int == 2 ||
+ phy->tx_fir_int == 4)) {
+ dev_err(dev,
+ "%s: Invalid: Interpolation %d in filter config",
+ __func__, phy->tx_fir_int);
+ return -EINVAL;
+ }
+
+
+ if (phy->tx_fir_int == 1 && phy->tx_fir_ntaps > 64) {
+ dev_err(dev,
+ "%s: Invalid: TAPS > 64 and Interpolation = 1",
+ __func__);
+ return -EINVAL;
+ }
+ }
+
+ if (!phy->bypass_rx_fir) {
+ if (!(phy->rx_fir_dec == 1 || phy->rx_fir_dec == 2 ||
+ phy->rx_fir_dec == 4)) {
+ dev_err(dev,
+ "%s: Invalid: Decimation %d in filter config",
+ __func__, phy->rx_fir_dec);
+
+ return -EINVAL;
+ }
+ }
+
+ if (!phy->filt_valid || phy->bypass_rx_fir || phy->bypass_tx_fir) {
+ ret = ad9361_calculate_rf_clock_chain(phy,
+ clk_get_rate(phy, phy->ref_clk_scale[TX_SAMPL_CLK]),
+ phy->rate_governor, rx, tx);
+ if (ret < 0) {
+ min = phy->rate_governor ? 1500000U : 1000000U;
+ dev_err(dev,
+ "%s: Calculating filter rates failed %"PRId32
+ " using min frequency",__func__, ret);
+ ret = ad9361_calculate_rf_clock_chain(phy, min,
+ phy->rate_governor, rx, tx);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+ valid = false;
+ } else {
+#ifndef ALTERA_PLATFORM
+ memcpy(rx, phy->filt_rx_path_clks, sizeof(rx));
+ memcpy(tx, phy->filt_tx_path_clks, sizeof(tx));
+#else
+ int32_t i;
+ uint32_t num;
+#ifdef NUAND_MODIFICATIONS
+ // fix memory overrun :x
+ num = sizeof(rx)/sizeof(rx[0]);
+#else
+ num = sizeof(rx);
+#endif // NUAND_MODIFICATIONS
+ for (i = 0; i < num; i++)
+ rx[i] = phy->filt_rx_path_clks[i];
+#ifdef NUAND_MODIFICATIONS
+ // fix memory overrun :x
+ num = sizeof(tx)/sizeof(tx[0]);
+#else
+ num = sizeof(tx);
+#endif // NUAND_MODIFICATIONS
+ for (i = 0; i < num; i++)
+ tx[i] = phy->filt_tx_path_clks[i];
+#endif
+ valid = true;
+
+ }
+
+#ifdef _DEBUG
+ dev_dbg(&phy->spi->dev, "%s:RX %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32,
+ __func__, rx[BBPLL_FREQ], rx[ADC_FREQ],
+ rx[R2_FREQ], rx[R1_FREQ],
+ rx[CLKRF_FREQ], rx[RX_SAMPL_FREQ]);
+
+ dev_dbg(&phy->spi->dev, "%s:TX %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32,
+ __func__, tx[BBPLL_FREQ], tx[ADC_FREQ],
+ tx[R2_FREQ], tx[R1_FREQ],
+ tx[CLKRF_FREQ], tx[RX_SAMPL_FREQ]);
+#endif
+
+ if (!phy->bypass_tx_fir) {
+ max = (tx[DAC_FREQ] / tx[TX_SAMPL_FREQ]) * 16;
+ if (phy->tx_fir_ntaps > max) {
+ dev_err(dev,
+ "%s: Invalid: ratio ADC/2 / TX_SAMPL * 16 > TAPS"
+ "(max %"PRIu32", adc %"PRIu32", tx %"PRIu32")",
+ __func__, max, rx[ADC_FREQ], tx[TX_SAMPL_FREQ]);
+ return -EINVAL;
+ }
+ }
+
+ if (!phy->bypass_rx_fir) {
+ max = ((rx[ADC_FREQ] / ((rx[ADC_FREQ] == rx[R2_FREQ]) ? 1 : 2)) /
+ rx[RX_SAMPL_FREQ]) * 16;
+ if (phy->rx_fir_ntaps > max) {
+ dev_err(dev,
+ "%s: Invalid: ratio ADC/2 / RX_SAMPL * 16 > TAPS (max %"PRIu32")",
+ __func__, max);
+ return -EINVAL;
+ }
+ }
+
+ ret = ad9361_set_trx_clock_chain(phy, rx, tx);
+ if (ret < 0)
+ return ret;
+
+ /* See also: ad9361_set_trx_clock_chain() */
+ if (!phy->pdata->dig_interface_tune_fir_disable &&
+ phy->bypass_tx_fir && phy->bypass_rx_fir)
+ ad9361_dig_tune(phy, 0, RESTORE_DEFAULT);
+
+ return ad9361_update_rf_bandwidth(phy,
+ valid ? phy->filt_rx_bw_Hz : phy->current_rx_bw_Hz,
+ valid ? phy->filt_tx_bw_Hz : phy->current_tx_bw_Hz);
+}
+
+/*
+* AD9361 Clocks
+*/
+
+/**
+* Set the multiplier and the divider for the selected refclk_scale structure.
+* @param priv The selected refclk_scale structure.
+* @param mul The multiplier value.
+* @param div The divider value.
+* @return 0 in case of success, negative error code otherwise.
+*/
+static inline int32_t ad9361_set_muldiv(struct refclk_scale *priv, uint32_t mul, uint32_t div)
+{
+ priv->mult = mul;
+ priv->div = div;
+ return 0;
+}
+
+/**
+ * Get the clk scaler for the selected refclk_scale structure.
+ * @param priv The selected refclk_scale structure.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_get_clk_scaler(struct refclk_scale *clk_priv)
+{
+ struct spi_device *spi = clk_priv->spi;
+ uint32_t tmp, tmp1;
+
+ switch (clk_priv->source) {
+ case BB_REFCLK:
+ tmp = ad9361_spi_read(spi, REG_CLOCK_CTRL);
+ tmp &= 0x3;
+ break;
+ case RX_REFCLK:
+ tmp = ad9361_spi_readf(spi, REG_REF_DIVIDE_CONFIG_1,
+ RX_REF_DIVIDER_MSB);
+ tmp1 = ad9361_spi_readf(spi, REG_REF_DIVIDE_CONFIG_2,
+ RX_REF_DIVIDER_LSB);
+ tmp = (tmp << 1) | tmp1;
+ break;
+ case TX_REFCLK:
+ tmp = ad9361_spi_readf(spi, REG_REF_DIVIDE_CONFIG_2,
+ TX_REF_DIVIDER(~0));
+ break;
+ case ADC_CLK:
+ tmp = ad9361_spi_read(spi, REG_BBPLL);
+ return ad9361_set_muldiv(clk_priv, 1, 1 << (tmp & 0x7));
+ case R2_CLK:
+ tmp = ad9361_spi_readf(spi, REG_RX_ENABLE_FILTER_CTRL,
+ DEC3_ENABLE_DECIMATION(~0));
+ return ad9361_set_muldiv(clk_priv, 1, tmp + 1);
+ case R1_CLK:
+ tmp = ad9361_spi_readf(spi, REG_RX_ENABLE_FILTER_CTRL, RHB2_EN);
+ return ad9361_set_muldiv(clk_priv, 1, tmp + 1);
+ case CLKRF_CLK:
+ tmp = ad9361_spi_readf(spi, REG_RX_ENABLE_FILTER_CTRL, RHB1_EN);
+ return ad9361_set_muldiv(clk_priv, 1, tmp + 1);
+ case RX_SAMPL_CLK:
+ tmp = ad9361_spi_readf(spi, REG_RX_ENABLE_FILTER_CTRL,
+ RX_FIR_ENABLE_DECIMATION(~0));
+
+ if (!tmp)
+ tmp = 1; /* bypass filter */
+ else
+ tmp = (1 << (tmp - 1));
+
+ return ad9361_set_muldiv(clk_priv, 1, tmp);
+ case DAC_CLK:
+ tmp = ad9361_spi_readf(spi, REG_BBPLL, BIT(3));
+ return ad9361_set_muldiv(clk_priv, 1, tmp + 1);
+ case T2_CLK:
+ tmp = ad9361_spi_readf(spi, REG_TX_ENABLE_FILTER_CTRL,
+ THB3_ENABLE_INTERP(~0));
+ return ad9361_set_muldiv(clk_priv, 1, tmp + 1);
+ case T1_CLK:
+ tmp = ad9361_spi_readf(spi, REG_TX_ENABLE_FILTER_CTRL, THB2_EN);
+ return ad9361_set_muldiv(clk_priv, 1, tmp + 1);
+ case CLKTF_CLK:
+ tmp = ad9361_spi_readf(spi, REG_TX_ENABLE_FILTER_CTRL, THB1_EN);
+ return ad9361_set_muldiv(clk_priv, 1, tmp + 1);
+ case TX_SAMPL_CLK:
+ tmp = ad9361_spi_readf(spi, REG_TX_ENABLE_FILTER_CTRL,
+ TX_FIR_ENABLE_INTERPOLATION(~0));
+
+ if (!tmp)
+ tmp = 1; /* bypass filter */
+ else
+ tmp = (1 << (tmp - 1));
+
+ return ad9361_set_muldiv(clk_priv, 1, tmp);
+ default:
+ return -EINVAL;
+ }
+
+ /* REFCLK Scaler */
+ switch (tmp) {
+ case 0:
+ ad9361_set_muldiv(clk_priv, 1, 1);
+ break;
+ case 1:
+ ad9361_set_muldiv(clk_priv, 1, 2);
+ break;
+ case 2:
+ ad9361_set_muldiv(clk_priv, 1, 4);
+ break;
+ case 3:
+ ad9361_set_muldiv(clk_priv, 2, 1);
+ break;
+ default:
+ return -EINVAL;
+
+ }
+
+ return 0;
+}
+
+/**
+ * Calculate the REFCLK Scaler for the selected refclk_scale structure.
+ * Note: REFCLK Scaler values - 00: x1; 01: x½; 10: x¼; 11: x2.
+ * @param clk_priv The selected refclk_scale structure.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_to_refclk_scaler(struct refclk_scale *clk_priv)
+{
+ /* REFCLK Scaler */
+ switch (((clk_priv->mult & 0xF) << 4) | (clk_priv->div & 0xF)) {
+ case 0x11:
+ return 0;
+ case 0x12:
+ return 1;
+ case 0x14:
+ return 2;
+ case 0x21:
+ return 3;
+ default:
+ return -EINVAL;
+ }
+};
+
+/**
+ * Set clk scaler for the selected refclk_scale structure.
+ * @param clk_priv The selected refclk_scale structure.
+ * @param set Set true, the reference clock frequency will be scaled before
+ * it enters the BBPLL.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_set_clk_scaler(struct refclk_scale *clk_priv, bool set)
+{
+ struct spi_device *spi = clk_priv->spi;
+ uint32_t tmp;
+ int32_t ret;
+
+ switch (clk_priv->source) {
+ case BB_REFCLK:
+ ret = ad9361_to_refclk_scaler(clk_priv);
+ if (ret < 0)
+ return ret;
+ if (set)
+ return ad9361_spi_writef(spi, REG_CLOCK_CTRL,
+ REF_FREQ_SCALER(~0), ret);
+ break;
+
+ case RX_REFCLK:
+ ret = ad9361_to_refclk_scaler(clk_priv);
+ if (ret < 0)
+ return ret;
+ if (set) {
+ tmp = ret;
+ ret = ad9361_spi_writef(spi, REG_REF_DIVIDE_CONFIG_1,
+ RX_REF_DIVIDER_MSB, tmp >> 1);
+ ret |= ad9361_spi_writef(spi, REG_REF_DIVIDE_CONFIG_2,
+ RX_REF_DIVIDER_LSB, tmp & 1);
+ return ret;
+ }
+ break;
+ case TX_REFCLK:
+ ret = ad9361_to_refclk_scaler(clk_priv);
+ if (ret < 0)
+ return ret;
+ if (set)
+ return ad9361_spi_writef(spi, REG_REF_DIVIDE_CONFIG_2,
+ TX_REF_DIVIDER(~0), ret);
+ break;
+ case ADC_CLK:
+ tmp = ilog2((uint8_t)clk_priv->div);
+ if (clk_priv->mult != 1 || tmp > 6 || tmp < 1)
+ return -EINVAL;
+
+ if (set)
+ return ad9361_spi_writef(spi, REG_BBPLL, 0x7, tmp);
+ break;
+ case R2_CLK:
+ if (clk_priv->mult != 1 || clk_priv->div > 3 || clk_priv->div < 1)
+ return -EINVAL;
+ if (set)
+ return ad9361_spi_writef(spi, REG_RX_ENABLE_FILTER_CTRL,
+ DEC3_ENABLE_DECIMATION(~0),
+ clk_priv->div - 1);
+ break;
+ case R1_CLK:
+ if (clk_priv->mult != 1 || clk_priv->div > 2 || clk_priv->div < 1)
+ return -EINVAL;
+ if (set)
+ return ad9361_spi_writef(spi, REG_RX_ENABLE_FILTER_CTRL,
+ RHB2_EN, clk_priv->div - 1);
+ break;
+ case CLKRF_CLK:
+ if (clk_priv->mult != 1 || clk_priv->div > 2 || clk_priv->div < 1)
+ return -EINVAL;
+ if (set)
+ return ad9361_spi_writef(spi, REG_RX_ENABLE_FILTER_CTRL,
+ RHB1_EN, clk_priv->div - 1);
+ break;
+ case RX_SAMPL_CLK:
+ if (clk_priv->mult != 1 || clk_priv->div > 4 ||
+ clk_priv->div < 1 || clk_priv->div == 3)
+ return -EINVAL;
+
+ if (clk_priv->phy->bypass_rx_fir)
+ tmp = 0;
+ else
+ tmp = ilog2(clk_priv->div) + 1;
+
+ if (set)
+ return ad9361_spi_writef(spi, REG_RX_ENABLE_FILTER_CTRL,
+ RX_FIR_ENABLE_DECIMATION(~0), tmp);
+ break;
+ case DAC_CLK:
+ if (clk_priv->mult != 1 || clk_priv->div > 2 || clk_priv->div < 1)
+ return -EINVAL;
+ if (set)
+ return ad9361_spi_writef(spi, REG_BBPLL,
+ BIT(3), clk_priv->div - 1);
+ break;
+ case T2_CLK:
+ if (clk_priv->mult != 1 || clk_priv->div > 3 || clk_priv->div < 1)
+ return -EINVAL;
+ if (set)
+ return ad9361_spi_writef(spi, REG_TX_ENABLE_FILTER_CTRL,
+ THB3_ENABLE_INTERP(~0),
+ clk_priv->div - 1);
+ break;
+ case T1_CLK:
+ if (clk_priv->mult != 1 || clk_priv->div > 2 || clk_priv->div < 1)
+ return -EINVAL;
+ if (set)
+ return ad9361_spi_writef(spi, REG_TX_ENABLE_FILTER_CTRL,
+ THB2_EN, clk_priv->div - 1);
+ break;
+ case CLKTF_CLK:
+ if (clk_priv->mult != 1 || clk_priv->div > 2 || clk_priv->div < 1)
+ return -EINVAL;
+ if (set)
+ return ad9361_spi_writef(spi, REG_TX_ENABLE_FILTER_CTRL,
+ THB1_EN, clk_priv->div - 1);
+ break;
+ case TX_SAMPL_CLK:
+ if (clk_priv->mult != 1 || clk_priv->div > 4 ||
+ clk_priv->div < 1 || clk_priv->div == 3)
+ return -EINVAL;
+
+ if (clk_priv->phy->bypass_tx_fir)
+ tmp = 0;
+ else
+ tmp = ilog2(clk_priv->div) + 1;
+
+ if (set)
+ return ad9361_spi_writef(spi, REG_TX_ENABLE_FILTER_CTRL,
+ TX_FIR_ENABLE_INTERPOLATION(~0), tmp);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * Recalculate the clock rate.
+ * @param refclk_scale The refclk_scale structure.
+ * @param parent_rate The parent clock rate.
+ * @return The clock rate.
+ */
+uint32_t ad9361_clk_factor_recalc_rate(struct refclk_scale *clk_priv,
+ uint32_t parent_rate)
+{
+ uint64_t rate;
+
+ ad9361_get_clk_scaler(clk_priv);
+ rate = (parent_rate * clk_priv->mult) / clk_priv->div;
+
+ return (uint32_t)rate;
+}
+
+/**
+ * Calculate the closest possible clock rate that can be set.
+ * @param refclk_scale The refclk_scale structure.
+ * @param rate The clock rate.
+ * @param parent_rate The parent clock rate.
+ * @return The closest possible clock rate that can be set.
+ */
+int32_t ad9361_clk_factor_round_rate(struct refclk_scale *clk_priv, uint32_t rate,
+ uint32_t *prate)
+{
+ int32_t ret;
+
+ if (rate >= *prate) {
+ clk_priv->mult = DIV_ROUND_CLOSEST(rate, *prate);
+ clk_priv->div = 1;
+
+ }
+ else {
+ clk_priv->div = DIV_ROUND_CLOSEST(*prate, rate);
+ clk_priv->mult = 1;
+ if (!clk_priv->div) {
+ dev_err(&clk_priv->spi->dev, "%s: divide by zero",
+ __func__);
+ clk_priv->div = 1;
+ }
+ }
+
+ ret = ad9361_set_clk_scaler(clk_priv, false);
+ if (ret < 0)
+ return ret;
+
+ return (*prate / clk_priv->div) * clk_priv->mult;
+}
+
+/**
+ * Set the clock rate.
+ * @param refclk_scale The refclk_scale structure.
+ * @param rate The clock rate.
+ * @param parent_rate The parent clock rate.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_clk_factor_set_rate(struct refclk_scale *clk_priv, uint32_t rate,
+ uint32_t parent_rate)
+{
+ dev_dbg(&clk_priv->spi->dev, "%s: Rate %"PRIu32" Hz Parent Rate %"PRIu32" Hz",
+ __func__, rate, parent_rate);
+
+ if (rate >= parent_rate) {
+ clk_priv->mult = DIV_ROUND_CLOSEST(rate, parent_rate);
+ clk_priv->div = 1;
+ }
+ else {
+ clk_priv->div = DIV_ROUND_CLOSEST(parent_rate, rate);
+ clk_priv->mult = 1;
+ if (!clk_priv->div) {
+ dev_err(&clk_priv->spi->dev, "%s: divide by zero",
+ __func__);
+ clk_priv->div = 1;
+ }
+ }
+
+ return ad9361_set_clk_scaler(clk_priv, true);
+}
+
+/*
+ * BBPLL
+ */
+/**
+ * Recalculate the clock rate.
+ * @param refclk_scale The refclk_scale structure.
+ * @param parent_rate The parent clock rate.
+ * @return The clock rate.
+ */
+uint32_t ad9361_bbpll_recalc_rate(struct refclk_scale *clk_priv,
+ uint32_t parent_rate)
+{
+ uint64_t rate;
+ uint32_t fract, integer;
+ uint8_t buf[4];
+
+ ad9361_spi_readm(clk_priv->spi, REG_INTEGER_BB_FREQ_WORD, &buf[0],
+ REG_INTEGER_BB_FREQ_WORD - REG_FRACT_BB_FREQ_WORD_1 + 1);
+
+ fract = (buf[3] << 16) | (buf[2] << 8) | buf[1];
+ integer = buf[0];
+
+ rate = ((uint64_t)parent_rate * fract);
+ do_div(&rate, BBPLL_MODULUS);
+ rate += (uint64_t)parent_rate * integer;
+
+ return (uint32_t)rate;
+}
+
+/**
+ * Calculate the closest possible clock rate that can be set.
+ * @param refclk_scale The refclk_scale structure.
+ * @param rate The clock rate.
+ * @param parent_rate The parent clock rate.
+ * @return The closest possible clock rate that can be set.
+ */
+int32_t ad9361_bbpll_round_rate(struct refclk_scale *clk_priv, uint32_t rate,
+ uint32_t *prate)
+{
+ uint64_t tmp;
+ uint32_t fract, integer;
+ uint64_t temp;
+
+ if (clk_priv) {
+ // Unused variable - fix compiler warning
+ }
+
+ if (rate > MAX_BBPLL_FREQ)
+ return MAX_BBPLL_FREQ;
+
+ if (rate < MIN_BBPLL_FREQ)
+ return MIN_BBPLL_FREQ;
+
+ temp = rate;
+ tmp = do_div(&temp, *prate);
+ rate = temp;
+ tmp = tmp * BBPLL_MODULUS + (*prate >> 1);
+ do_div(&tmp, *prate);
+
+ integer = rate;
+ fract = tmp;
+
+ tmp = *prate * (uint64_t)fract;
+ do_div(&tmp, BBPLL_MODULUS);
+ tmp += *prate * integer;
+
+ return tmp;
+}
+
+/**
+ * Set the clock rate.
+ * @param refclk_scale The refclk_scale structure.
+ * @param rate The clock rate.
+ * @param parent_rate The parent clock rate.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_bbpll_set_rate(struct refclk_scale *clk_priv, uint32_t rate,
+ uint32_t parent_rate)
+{
+ struct spi_device *spi = clk_priv->spi;
+ uint64_t tmp;
+ uint32_t fract, integer;
+ int32_t icp_val;
+ uint8_t lf_defaults[3] = { 0x35, 0x5B, 0xE8 };
+ uint64_t temp;
+
+ dev_dbg(&spi->dev, "%s: Rate %"PRIu32" Hz Parent Rate %"PRIu32" Hz",
+ __func__, rate, parent_rate);
+
+ /*
+ * Setup Loop Filter and CP Current
+ * Scale is 150uA @ (1280MHz BBPLL, 40MHz REFCLK)
+ */
+ tmp = (rate >> 7) * 150ULL;
+ do_div(&tmp, (parent_rate >> 7) * 32UL);
+
+ /* 25uA/LSB, Offset 25uA */
+ icp_val = DIV_ROUND_CLOSEST((uint32_t)tmp, 25U) - 1;
+
+ icp_val = clamp(icp_val, 1, 64);
+
+ ad9361_spi_write(spi, REG_CP_CURRENT, icp_val);
+ ad9361_spi_writem(spi, REG_LOOP_FILTER_3, lf_defaults,
+ ARRAY_SIZE(lf_defaults));
+
+ /* Allow calibration to occur and set cal count to 1024 for max accuracy */
+ ad9361_spi_write(spi, REG_VCO_CTRL,
+ FREQ_CAL_ENABLE | FREQ_CAL_COUNT_LENGTH(3));
+ /* Set calibration clock to REFCLK/4 for more accuracy */
+ ad9361_spi_write(spi, REG_SDM_CTRL, 0x10);
+
+ /* Calculate and set BBPLL frequency word */
+ temp = rate;
+ tmp = do_div(&temp, parent_rate);
+ rate = temp;
+ tmp = tmp *(uint64_t)BBPLL_MODULUS + (parent_rate >> 1);
+ do_div(&tmp, parent_rate);
+
+ integer = rate;
+ fract = tmp;
+
+ ad9361_spi_write(spi, REG_INTEGER_BB_FREQ_WORD, integer);
+ ad9361_spi_write(spi, REG_FRACT_BB_FREQ_WORD_3, fract);
+ ad9361_spi_write(spi, REG_FRACT_BB_FREQ_WORD_2, fract >> 8);
+ ad9361_spi_write(spi, REG_FRACT_BB_FREQ_WORD_1, fract >> 16);
+
+ ad9361_spi_write(spi, REG_SDM_CTRL_1, INIT_BB_FO_CAL | BBPLL_RESET_BAR); /* Start BBPLL Calibration */
+ ad9361_spi_write(spi, REG_SDM_CTRL_1, BBPLL_RESET_BAR); /* Clear BBPLL start calibration bit */
+
+ ad9361_spi_write(spi, REG_VCO_PROGRAM_1, 0x86); /* Increase BBPLL KV and phase margin */
+ ad9361_spi_write(spi, REG_VCO_PROGRAM_2, 0x01); /* Increase BBPLL KV and phase margin */
+ ad9361_spi_write(spi, REG_VCO_PROGRAM_2, 0x05); /* Increase BBPLL KV and phase margin */
+
+ return ad9361_check_cal_done(clk_priv->phy, REG_CH_1_OVERFLOW,
+ BBPLL_LOCK, 1);
+}
+
+/*
+ * RFPLL
+ */
+
+/**
+ * Calculate the RFPLL frequency.
+ * @param parent_rate The parent clock rate.
+ * @param integer The integer value.
+ * @param fract The fractional value.
+ * @param vco_div The VCO divider.
+ * @return The RFPLL frequency.
+ */
+static uint64_t ad9361_calc_rfpll_int_freq(uint64_t parent_rate,
+ uint64_t integer,
+ uint64_t fract, uint32_t vco_div)
+{
+ uint64_t rate;
+
+ rate = parent_rate * fract;
+ do_div(&rate, RFPLL_MODULUS);
+ rate += parent_rate * integer;
+
+ return rate >> (vco_div + 1);
+}
+
+/**
+ * Calculate the RFPLL dividers.
+ * @param freq The RFPLL frequency.
+ * @param parent_rate The parent clock rate.
+ * @param integer The integer value.
+ * @param fract The fractional value.
+ * @param vco_div The VCO divider.
+ * @param vco_freq The VCO frequency.
+ * @return The RFPLL frequency.
+ */
+static int32_t ad9361_calc_rfpll_int_divder(struct ad9361_rf_phy *phy,
+ uint64_t freq, uint64_t parent_rate, uint32_t *integer,
+ uint32_t *fract, int32_t *vco_div, uint64_t *vco_freq)
+{
+ uint64_t tmp;
+ int32_t div, ret;
+
+ ret = ad9361_validate_rfpll(phy, freq);
+ if (ret)
+ return ret;
+
+ div = -1;
+
+ while (freq <= MIN_VCO_FREQ_HZ) {
+ freq <<= 1;
+ div++;
+ }
+
+ *vco_div = div;
+ *vco_freq = freq;
+ tmp = do_div(&freq, parent_rate);
+ tmp = tmp * RFPLL_MODULUS + (parent_rate >> 1);
+ do_div(&tmp, parent_rate);
+ *integer = freq;
+ *fract = tmp;
+
+ return 0;
+}
+
+/**
+ * Recalculate the clock rate.
+ * @param refclk_scale The refclk_scale structure.
+ * @param parent_rate The parent clock rate.
+ * @return The clock rate.
+ */
+uint32_t ad9361_rfpll_int_recalc_rate(struct refclk_scale *clk_priv,
+ uint32_t parent_rate)
+{
+ struct ad9361_rf_phy *phy = clk_priv->phy;
+ uint32_t fract, integer;
+ uint8_t buf[5];
+ uint32_t reg, div_mask, vco_div, profile;
+
+ dev_dbg(&clk_priv->spi->dev, "%s: Parent Rate %"PRIu32" Hz",
+ __func__, parent_rate);
+
+ switch (clk_priv->source) {
+ case RX_RFPLL_INT:
+ reg = REG_RX_FRACT_BYTE_2;
+ div_mask = RX_VCO_DIVIDER(~0);
+ profile = phy->fastlock.current_profile[0];
+ break;
+ case TX_RFPLL_INT:
+ reg = REG_TX_FRACT_BYTE_2;
+ div_mask = TX_VCO_DIVIDER(~0);
+ profile = phy->fastlock.current_profile[1];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (profile) {
+ bool tx = clk_priv->source == TX_RFPLL_INT;
+ profile = profile - 1;
+
+ buf[0] = ad9361_fastlock_readval(phy->spi, tx, profile, 4);
+ buf[1] = ad9361_fastlock_readval(phy->spi, tx, profile, 3);
+ buf[2] = ad9361_fastlock_readval(phy->spi, tx, profile, 2);
+ buf[3] = ad9361_fastlock_readval(phy->spi, tx, profile, 1);
+ buf[4] = ad9361_fastlock_readval(phy->spi, tx, profile, 0);
+ vco_div = ad9361_fastlock_readval(phy->spi, tx, profile, 12) & 0xF;
+
+ }
+ else {
+ ad9361_spi_readm(clk_priv->spi, reg, &buf[0], ARRAY_SIZE(buf));
+ vco_div = ad9361_spi_readf(clk_priv->spi, REG_RFPLL_DIVIDERS, div_mask);
+ }
+
+ fract = (SYNTH_FRACT_WORD(buf[0]) << 16) | (buf[1] << 8) | buf[2];
+ integer = (SYNTH_INTEGER_WORD(buf[3]) << 8) | buf[4];
+
+ return ad9361_to_clk(ad9361_calc_rfpll_int_freq(parent_rate, integer,
+ fract, vco_div));
+}
+
+/**
+ * Calculate the closest possible clock rate that can be set.
+ * @param refclk_scale The refclk_scale structure.
+ * @param rate The clock rate.
+ * @param parent_rate The parent clock rate.
+ * @return The closest possible clock rate that can be set.
+ */
+int32_t ad9361_rfpll_int_round_rate(struct refclk_scale *clk_priv, uint32_t rate,
+ uint32_t *prate)
+{
+ dev_dbg(&clk_priv->spi->dev, "%s: Rate %"PRIu32" Hz", __func__, rate);
+
+ if (prate) {
+ // Unused variable - fix compiler warning
+ }
+
+ if (clk_priv) {
+ // Unused variable - fix compiler warning
+ }
+
+ if (ad9361_from_clk(rate) > MAX_CARRIER_FREQ_HZ ||
+ ad9361_from_clk(rate) < MIN_CARRIER_FREQ_HZ)
+ return -EINVAL;
+
+ return rate;
+}
+
+/**
+ * Set the clock rate.
+ * @param refclk_scale The refclk_scale structure.
+ * @param rate The clock rate.
+ * @param parent_rate The parent clock rate.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_rfpll_int_set_rate(struct refclk_scale *clk_priv, uint32_t rate,
+ uint32_t parent_rate)
+{
+ struct ad9361_rf_phy *phy = clk_priv->phy;
+ uint64_t vco = 0;
+ uint8_t buf[5];
+ uint32_t reg, div_mask, lock_reg, fract = 0, integer = 0;
+ int32_t vco_div, ret, fixup_other;
+
+ dev_dbg(&clk_priv->spi->dev, "%s: %s Rate %"PRIu32" Hz Parent Rate %"PRIu32" Hz",
+ __func__, clk_priv->source == TX_RFPLL_INT ? "TX" : "RX",
+ rate, parent_rate);
+
+ ad9361_fastlock_prepare(phy, clk_priv->source == TX_RFPLL_INT, 0, false);
+
+ ret = ad9361_calc_rfpll_int_divder(phy, ad9361_from_clk(rate), parent_rate,
+ &integer, &fract, &vco_div, &vco);
+ if (ret < 0)
+ return ret;
+
+ switch (clk_priv->source) {
+ case RX_RFPLL_INT:
+ reg = REG_RX_FRACT_BYTE_2;
+ lock_reg = REG_RX_CP_OVERRANGE_VCO_LOCK;
+ div_mask = RX_VCO_DIVIDER(~0);
+ phy->cached_rx_rfpll_div = vco_div;
+ phy->current_rx_lo_freq = rate;
+ break;
+ case TX_RFPLL_INT:
+ reg = REG_TX_FRACT_BYTE_2;
+ lock_reg = REG_TX_CP_OVERRANGE_VCO_LOCK;
+ div_mask = TX_VCO_DIVIDER(~0);
+ phy->cached_tx_rfpll_div = vco_div;
+ phy->current_tx_lo_freq = rate;
+ break;
+ default:
+ return -EINVAL;
+
+ }
+
+ /* Option to skip VCO cal in TDD mode when moving from TX/RX to Alert */
+ if (phy->pdata->tdd_skip_vco_cal)
+ ad9361_trx_vco_cal_control(phy, clk_priv->source == TX_RFPLL_INT,
+ true);
+
+ do {
+ fixup_other = 0;
+ ad9361_rfpll_vco_init(phy, div_mask == TX_VCO_DIVIDER(~0),
+ vco, parent_rate);
+
+ buf[0] = SYNTH_FRACT_WORD(fract >> 16);
+ buf[1] = fract >> 8;
+ buf[2] = fract & 0xFF;
+ buf[3] = SYNTH_INTEGER_WORD(integer >> 8) |
+ (~SYNTH_INTEGER_WORD(~0) &
+ ad9361_spi_read(clk_priv->spi, reg - 3));
+ buf[4] = integer & 0xFF;
+
+ ad9361_spi_writem(clk_priv->spi, reg, buf, 5);
+ ad9361_spi_writef(clk_priv->spi, REG_RFPLL_DIVIDERS, div_mask, vco_div);
+
+ ret = ad9361_check_cal_done(phy, lock_reg, VCO_LOCK, 1);
+
+ /* In FDD mode with RX LO == TX LO frequency we use TDD tables to
+ * reduce VCO pulling
+ */
+
+ if (((phy->pdata->fdd && !phy->pdata->fdd_independent_mode) &&
+ (phy->current_tx_lo_freq == phy->current_rx_lo_freq) &&
+ (phy->current_tx_use_tdd_table != phy->current_rx_use_tdd_table)) ||
+ ((phy->pdata->fdd && !phy->pdata->fdd_independent_mode) &&
+ (phy->current_tx_lo_freq != phy->current_rx_lo_freq) &&
+ (phy->current_tx_use_tdd_table || phy->current_rx_use_tdd_table))) {
+ unsigned long _rate;
+
+ switch (clk_priv->source) {
+ case RX_RFPLL_INT:
+ reg = REG_TX_FRACT_BYTE_2;
+ lock_reg = REG_TX_CP_OVERRANGE_VCO_LOCK;
+ div_mask = TX_VCO_DIVIDER(~0);
+ _rate = phy->current_tx_lo_freq;
+ break;
+ case TX_RFPLL_INT:
+ reg = REG_RX_FRACT_BYTE_2;
+ lock_reg = REG_RX_CP_OVERRANGE_VCO_LOCK;
+ div_mask = RX_VCO_DIVIDER(~0);
+ _rate = phy->current_rx_lo_freq;
+ break;
+ default:
+ return -EINVAL;
+
+ }
+
+ if (phy->current_tx_lo_freq != phy->current_rx_lo_freq) {
+ ad9361_calc_rfpll_int_divder(phy, ad9361_from_clk(_rate),
+ parent_rate, &integer, &fract, &vco_div, &vco);
+
+ ad9361_fastlock_prepare(phy, clk_priv->source == RX_RFPLL_INT, 0, false);
+ }
+
+ fixup_other = 1;
+ }
+
+ } while (fixup_other);
+
+ if (phy->pdata->tdd_skip_vco_cal)
+ ad9361_trx_vco_cal_control(phy, clk_priv->source == TX_RFPLL_INT,
+ false);
+
+ return ret;
+}
+
+/**
+ * Recalculate the clock rate.
+ * @param refclk_scale The refclk_scale structure.
+ * @param parent_rate The parent clock rate.
+ * @return The clock rate.
+ */
+uint32_t ad9361_rfpll_dummy_recalc_rate(struct refclk_scale *clk_priv)
+{
+ struct ad9361_rf_phy *phy = clk_priv->phy;
+
+ return phy->clks[clk_priv->source]->rate;
+}
+
+/**
+ * Set the clock rate.
+ * @param refclk_scale The refclk_scale structure.
+ * @param rate The clock rate.
+ * @param parent_rate The parent clock rate.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_rfpll_dummy_set_rate(struct refclk_scale *clk_priv, uint32_t rate)
+{
+ struct ad9361_rf_phy *phy = clk_priv->phy;
+
+ phy->clks[clk_priv->source]->rate = rate;
+
+ return 0;
+}
+
+/**
+ * Recalculate the clock rate.
+ * @param refclk_scale The refclk_scale structure.
+ * @param parent_rate The parent clock rate.
+ * @return The clock rate.
+ */
+uint32_t ad9361_rfpll_recalc_rate(struct refclk_scale *clk_priv)
+{
+ struct ad9361_rf_phy *phy = clk_priv->phy;
+ uint32_t rate;
+
+ switch (clk_priv->source) {
+ case RX_RFPLL:
+ if (phy->pdata->use_ext_rx_lo) {
+ if (phy->ad9361_rfpll_ext_recalc_rate)
+ rate = phy->ad9361_rfpll_ext_recalc_rate(clk_priv);
+ else
+ rate = ad9361_rfpll_dummy_recalc_rate(phy->ref_clk_scale[RX_RFPLL_DUMMY]);
+ } else {
+ rate = ad9361_rfpll_int_recalc_rate(phy->ref_clk_scale[RX_RFPLL_INT],
+ phy->clks[RX_REFCLK]->rate);
+ }
+ break;
+ case TX_RFPLL:
+ if (phy->pdata->use_ext_tx_lo) {
+ if (phy->ad9361_rfpll_ext_recalc_rate)
+ rate = phy->ad9361_rfpll_ext_recalc_rate(clk_priv);
+ else
+ rate = ad9361_rfpll_dummy_recalc_rate(phy->ref_clk_scale[TX_RFPLL_DUMMY]);
+ } else {
+ rate = ad9361_rfpll_int_recalc_rate(phy->ref_clk_scale[TX_RFPLL_INT],
+ phy->clks[TX_REFCLK]->rate);
+ }
+ break;
+ default:
+ rate = 0;
+ break;
+ }
+
+ return rate;
+}
+
+/**
+ * Calculate the closest possible clock rate that can be set.
+ * @param refclk_scale The refclk_scale structure.
+ * @param rate The clock rate.
+ * @param parent_rate The parent clock rate.
+ * @return The closest possible clock rate that can be set.
+ */
+int32_t ad9361_rfpll_round_rate(struct refclk_scale *clk_priv, uint32_t rate)
+{
+ struct ad9361_rf_phy *phy = clk_priv->phy;
+ int32_t round_rate;
+
+ switch (clk_priv->source) {
+ case RX_RFPLL:
+ if (phy->pdata->use_ext_rx_lo) {
+ if (phy->ad9361_rfpll_ext_round_rate)
+ round_rate = phy->ad9361_rfpll_ext_round_rate(clk_priv, rate);
+ else
+ round_rate = rate;
+ } else {
+ round_rate = ad9361_rfpll_int_round_rate(phy->ref_clk_scale[RX_RFPLL_INT], rate,
+ &phy->clks[phy->ref_clk_scale[RX_RFPLL_INT]->parent_source]->rate);
+ }
+ case TX_RFPLL:
+ if (phy->pdata->use_ext_tx_lo) {
+ if (phy->ad9361_rfpll_ext_round_rate)
+ round_rate = phy->ad9361_rfpll_ext_round_rate(clk_priv, rate);
+ else
+ round_rate = rate;
+ } else {
+ round_rate = ad9361_rfpll_int_round_rate(phy->ref_clk_scale[TX_RFPLL_INT], rate,
+ &phy->clks[phy->ref_clk_scale[TX_RFPLL_INT]->parent_source]->rate);
+ }
+ break;
+ default:
+ round_rate = 0;
+ break;
+ }
+
+ return round_rate;
+}
+
+/**
+ * Set the clock rate.
+ * @param refclk_scale The refclk_scale structure.
+ * @param rate The clock rate.
+ * @param parent_rate The parent clock rate.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_rfpll_set_rate(struct refclk_scale *clk_priv, uint32_t rate)
+{
+ struct ad9361_rf_phy *phy = clk_priv->phy;
+ int32_t ret;
+
+ switch (clk_priv->source) {
+ case RX_RFPLL:
+ if (phy->pdata->use_ext_rx_lo) {
+ if (phy->ad9361_rfpll_ext_set_rate)
+ phy->ad9361_rfpll_ext_set_rate(clk_priv, rate);
+ else
+ ad9361_rfpll_dummy_set_rate(phy->ref_clk_scale[RX_RFPLL_DUMMY], rate);
+ } else {
+ ad9361_rfpll_int_set_rate(phy->ref_clk_scale[RX_RFPLL_INT], rate,
+ phy->clks[phy->ref_clk_scale[RX_RFPLL_INT]->parent_source]->rate);
+ }
+ /* Load Gain Table */
+ ret = ad9361_load_gt(phy, ad9361_from_clk(rate), GT_RX1 + GT_RX2);
+ if (ret < 0)
+ return ret;
+ break;
+ case TX_RFPLL:
+ if (phy->pdata->use_ext_tx_lo) {
+ if (phy->ad9361_rfpll_ext_set_rate)
+ phy->ad9361_rfpll_ext_set_rate(clk_priv, rate);
+ else
+ ad9361_rfpll_dummy_set_rate(phy->ref_clk_scale[TX_RFPLL_DUMMY], rate);
+ } else {
+ ad9361_rfpll_int_set_rate(phy->ref_clk_scale[TX_RFPLL_INT], rate,
+ phy->clks[phy->ref_clk_scale[TX_RFPLL_INT]->parent_source]->rate);
+ }
+ /* For RX LO we typically have the tracking option enabled
+ * so for now do nothing here.
+ */
+ if (phy->auto_cal_en && (clk_priv->source == TX_RFPLL_INT))
+ if (abs((int64_t)(phy->last_tx_quad_cal_freq - ad9361_from_clk(rate))) >
+ (int64_t)phy->cal_threshold_freq) {
+ ret = ad9361_do_calib_run(phy, TX_QUAD_CAL, -1);
+ if (ret < 0)
+ dev_err(&phy->spi->dev,
+ "%s: TX QUAD cal failed", __func__);
+ phy->last_tx_quad_cal_freq = ad9361_from_clk(rate);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * Set clock mux parent.
+ * @param refclk_scale The refclk_scale structure.
+ * @param index Index - Enable (1), disable (0) ext lo.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_clk_mux_set_parent(struct refclk_scale *clk_priv, uint8_t index)
+{
+ struct ad9361_rf_phy *phy = clk_priv->phy;
+ int32_t ret;
+
+ dev_dbg(&clk_priv->spi->dev, "%s: index %d", __func__, index);
+
+ ad9361_ensm_force_state(phy, ENSM_STATE_ALERT);
+
+ ret = ad9361_trx_ext_lo_control(phy, clk_priv->source == TX_RFPLL, index == 1);
+ if (ret >= 0)
+ clk_priv->mult = index;
+
+ ad9361_ensm_restore_prev_state(phy);
+
+ return ret;
+}
+
+/**
+ * Register and initialize a new clock.
+ * @param phy The AD9361 state structure.
+ * @param name The name of the new clock.
+ * @param parent_name The name of the parent clock.
+ * @param flags The flags.
+ * @param source The source of the new clock.
+ * @param parent_source The source of the parent clock.
+ * @return A struct clk for the new clock or a negative error code.
+ */
+static struct clk *ad9361_clk_register(struct ad9361_rf_phy *phy, const char *name,
+ const char *parent_name, uint32_t flags,
+ uint32_t source, uint32_t parent_source)
+{
+ struct refclk_scale *clk_priv;
+ struct clk *clk;
+
+ if (name) {
+ // Unused variable - fix compiler warning
+ }
+ if (parent_name) {
+ // Unused variable - fix compiler warning
+ }
+ if (flags) {
+ // Unused variable - fix compiler warning
+ }
+
+ clk_priv = (struct refclk_scale *)malloc(sizeof(*clk_priv));
+ if (!clk_priv) {
+ dev_err(&phy->spi->dev, "ad9361_clk_register: could not allocate fixed factor clk");
+ return (struct clk *)ERR_PTR(-ENOMEM);
+ }
+
+ /* struct refclk_scale assignments */
+ clk_priv->source = (enum ad9361_clocks)source;
+ clk_priv->parent_source = (enum ad9361_clocks)parent_source;
+ clk_priv->spi = phy->spi;
+ clk_priv->phy = phy;
+
+ phy->ref_clk_scale[source] = clk_priv;
+
+ clk = (struct clk *)malloc(sizeof(*clk));
+ if (!clk) {
+ free(clk_priv);
+ return (struct clk *)ERR_PTR(-ENOMEM);
+ }
+
+ switch (source) {
+ case TX_REFCLK:
+ clk->rate = ad9361_clk_factor_recalc_rate(clk_priv, phy->clk_refin->rate);
+ break;
+ case RX_REFCLK:
+ clk->rate = ad9361_clk_factor_recalc_rate(clk_priv, phy->clk_refin->rate);
+ break;
+ case BB_REFCLK:
+ clk->rate = ad9361_clk_factor_recalc_rate(clk_priv, phy->clk_refin->rate);
+ break;
+ case BBPLL_CLK:
+ clk->rate = ad9361_bbpll_recalc_rate(clk_priv, phy->clks[BB_REFCLK]->rate);
+ break;
+ case ADC_CLK:
+ clk->rate = ad9361_clk_factor_recalc_rate(clk_priv, phy->clks[BBPLL_CLK]->rate);
+ break;
+ case R2_CLK:
+ clk->rate = ad9361_clk_factor_recalc_rate(clk_priv, phy->clks[ADC_CLK]->rate);
+ break;
+ case R1_CLK:
+ clk->rate = ad9361_clk_factor_recalc_rate(clk_priv, phy->clks[R2_CLK]->rate);
+ break;
+ case CLKRF_CLK:
+ clk->rate = ad9361_clk_factor_recalc_rate(clk_priv, phy->clks[R1_CLK]->rate);
+ break;
+ case RX_SAMPL_CLK:
+ clk->rate = ad9361_clk_factor_recalc_rate(clk_priv, phy->clks[CLKRF_CLK]->rate);
+ break;
+ case DAC_CLK:
+ clk->rate = ad9361_clk_factor_recalc_rate(clk_priv, phy->clks[ADC_CLK]->rate);
+ break;
+ case T2_CLK:
+ clk->rate = ad9361_clk_factor_recalc_rate(clk_priv, phy->clks[DAC_CLK]->rate);
+ break;
+ case T1_CLK:
+ clk->rate = ad9361_clk_factor_recalc_rate(clk_priv, phy->clks[T2_CLK]->rate);
+ break;
+ case CLKTF_CLK:
+ clk->rate = ad9361_clk_factor_recalc_rate(clk_priv, phy->clks[T1_CLK]->rate);
+ break;
+ case TX_SAMPL_CLK:
+ clk->rate = ad9361_clk_factor_recalc_rate(clk_priv, phy->clks[CLKTF_CLK]->rate);
+ break;
+ case RX_RFPLL_INT:
+ clk->rate = ad9361_rfpll_int_recalc_rate(clk_priv, phy->clks[RX_REFCLK]->rate);
+ break;
+ case TX_RFPLL_INT:
+ clk->rate = ad9361_rfpll_int_recalc_rate(clk_priv, phy->clks[TX_REFCLK]->rate);
+ break;
+ case RX_RFPLL_DUMMY:
+ clk->rate = phy->pdata->rx_synth_freq;
+ break;
+ case TX_RFPLL_DUMMY:
+ clk->rate = phy->pdata->tx_synth_freq;
+ break;
+ case RX_RFPLL:
+ clk->rate = ad9361_rfpll_recalc_rate(clk_priv);
+ break;
+ case TX_RFPLL:
+ clk->rate = ad9361_rfpll_recalc_rate(clk_priv);
+ }
+
+ return clk;
+}
+
+/**
+ * Register and initialize all the system clocks.
+ * @param phy The AD9361 state structure.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t register_clocks(struct ad9361_rf_phy *phy)
+{
+ uint32_t flags = CLK_GET_RATE_NOCACHE;
+
+ phy->clk_data.clks = (struct clk **)malloc(sizeof(*phy->clk_data.clks) *
+ NUM_AD9361_CLKS);
+ if (!phy->clk_data.clks) {
+ dev_err(&phy->spi->dev, "could not allocate memory");
+ return -ENOMEM;
+ }
+
+ phy->clk_data.clk_num = NUM_AD9361_CLKS;
+
+ /* Scaled Reference Clocks */
+ phy->clks[TX_REFCLK] = ad9361_clk_register(phy,
+ "tx_refclk", "ad9361_ext_refclk",
+ flags | CLK_IGNORE_UNUSED,
+ TX_REFCLK, EXT_REF_CLK);
+
+ phy->clks[RX_REFCLK] = ad9361_clk_register(phy,
+ "rx_refclk", "ad9361_ext_refclk",
+ flags | CLK_IGNORE_UNUSED,
+ RX_REFCLK, EXT_REF_CLK);
+
+ phy->clks[BB_REFCLK] = ad9361_clk_register(phy,
+ "bb_refclk", "ad9361_ext_refclk",
+ flags | CLK_IGNORE_UNUSED,
+ BB_REFCLK, EXT_REF_CLK);
+
+ /* Base Band PLL Clock */
+ phy->clks[BBPLL_CLK] = ad9361_clk_register(phy,
+ "bbpll_clk", "bb_refclk",
+ flags | CLK_IGNORE_UNUSED,
+ BBPLL_CLK, BB_REFCLK);
+
+ phy->clks[ADC_CLK] = ad9361_clk_register(phy,
+ "adc_clk", "bbpll_clk",
+ flags | CLK_IGNORE_UNUSED,
+ ADC_CLK, BBPLL_CLK);
+
+ phy->clks[R2_CLK] = ad9361_clk_register(phy,
+ "r2_clk", "adc_clk",
+ flags | CLK_IGNORE_UNUSED,
+ R2_CLK, ADC_CLK);
+
+ phy->clks[R1_CLK] = ad9361_clk_register(phy,
+ "r1_clk", "r2_clk",
+ flags | CLK_IGNORE_UNUSED,
+ R1_CLK, R2_CLK);
+
+ phy->clks[CLKRF_CLK] = ad9361_clk_register(phy,
+ "clkrf_clk", "r1_clk",
+ flags | CLK_IGNORE_UNUSED,
+ CLKRF_CLK, R1_CLK);
+
+ phy->clks[RX_SAMPL_CLK] = ad9361_clk_register(phy,
+ "rx_sampl_clk", "clkrf_clk",
+ flags | CLK_IGNORE_UNUSED,
+ RX_SAMPL_CLK, CLKRF_CLK);
+
+
+ phy->clks[DAC_CLK] = ad9361_clk_register(phy,
+ "dac_clk", "adc_clk",
+ flags | CLK_IGNORE_UNUSED,
+ DAC_CLK, ADC_CLK);
+
+ phy->clks[T2_CLK] = ad9361_clk_register(phy,
+ "t2_clk", "dac_clk",
+ flags | CLK_IGNORE_UNUSED,
+ T2_CLK, DAC_CLK);
+
+ phy->clks[T1_CLK] = ad9361_clk_register(phy,
+ "t1_clk", "t2_clk",
+ flags | CLK_IGNORE_UNUSED,
+ T1_CLK, T2_CLK);
+
+ phy->clks[CLKTF_CLK] = ad9361_clk_register(phy,
+ "clktf_clk", "t1_clk",
+ flags | CLK_IGNORE_UNUSED,
+ CLKTF_CLK, T1_CLK);
+
+ phy->clks[TX_SAMPL_CLK] = ad9361_clk_register(phy,
+ "tx_sampl_clk", "clktf_clk",
+ flags | CLK_IGNORE_UNUSED,
+ TX_SAMPL_CLK, CLKTF_CLK);
+
+ phy->clks[RX_RFPLL_INT] = ad9361_clk_register(phy,
+ "rx_rfpll", "rx_refclk",
+ flags | CLK_IGNORE_UNUSED,
+ RX_RFPLL_INT, RX_REFCLK);
+
+ phy->clks[TX_RFPLL_INT] = ad9361_clk_register(phy,
+ "tx_rfpll", "tx_refclk",
+ flags | CLK_IGNORE_UNUSED,
+ TX_RFPLL_INT, TX_REFCLK);
+
+ phy->clks[RX_RFPLL_DUMMY] = ad9361_clk_register(phy,
+ "rx_rfpll_dummy", NULL,
+ flags | CLK_IGNORE_UNUSED,
+ RX_RFPLL_DUMMY, 0);
+
+ phy->clks[TX_RFPLL_DUMMY] = ad9361_clk_register(phy,
+ "tx_rfpll_dummy", NULL,
+ flags | CLK_IGNORE_UNUSED,
+ TX_RFPLL_DUMMY, 0);
+
+ phy->clks[RX_RFPLL] = ad9361_clk_register(phy,
+ "rx_rfpll", NULL,
+ flags | CLK_IGNORE_UNUSED,
+ RX_RFPLL, 0);
+
+ phy->clks[TX_RFPLL] = ad9361_clk_register(phy,
+ "tx_rfpll", NULL,
+ flags | CLK_IGNORE_UNUSED,
+ TX_RFPLL, 0);
+
+ return 0;
+}
+
+/**
+ * Perform an RSSI gain step calibration.
+ * Note: Before running the function, provide a single tone within the channel
+ * bandwidth and monitor the received data. Adjust the tone amplitude until
+ * the received data is within a few dB of full scale but not overloading.
+ * @param phy The AD9361 state structure.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_rssi_gain_step_calib(struct ad9361_rf_phy *phy)
+{
+ uint32_t lna_error[4];
+ uint32_t mixer_error[15];
+ uint64_t lo_freq_hz;
+ uint8_t lo_index;
+ uint8_t i;
+
+ lo_freq_hz = ad9361_from_clk(clk_get_rate(phy,
+ phy->ref_clk_scale[RX_RFPLL]));
+ if (lo_freq_hz < 1300000000ULL)
+ lo_index = 0;
+ else
+ if (lo_freq_hz < 3300000000ULL)
+ lo_index = 1;
+ else
+ if (lo_freq_hz < 4100000000ULL)
+ lo_index = 2;
+ else
+ lo_index = 3;
+
+ /* Put the AD9361 into the Alert state. */
+ ad9361_ensm_force_state(phy, ENSM_STATE_ALERT);
+
+ /* Program the directly-addressable register values. */
+ ad9361_spi_write(phy->spi, REG_MAX_MIXER_CALIBRATION_GAIN_INDEX,
+ MAX_MIXER_CALIBRATION_GAIN_INDEX(0x0F));
+ ad9361_spi_write(phy->spi, REG_MEASURE_DURATION,
+ GAIN_CAL_MEAS_DURATION(0x0E));
+ ad9361_spi_write(phy->spi, REG_SETTLE_TIME,
+ SETTLE_TIME(0x3F));
+ ad9361_spi_write(phy->spi, REG_RSSI_CONFIG,
+ RSSI_MODE_SELECT(0x3) | DEFAULT_RSSI_MEAS_MODE);
+ ad9361_spi_write(phy->spi, REG_MEASURE_DURATION_01,
+ MEASUREMENT_DURATION_0(0x0E));
+ ad9361_spi_write(phy->spi, REG_LNA_GAIN,
+ gain_step_calib_reg_val[lo_index][0]);
+
+ /* Program the LNA gain step words into the internal table. */
+ ad9361_spi_write(phy->spi, REG_CONFIG,
+ CALIB_TABLE_SELECT(0x3) | START_CALIB_TABLE_CLOCK);
+ for(i = 0; i < 4; i++) {
+ ad9361_spi_write(phy->spi, REG_WORD_ADDRESS, i);
+ ad9361_spi_write(phy->spi, REG_GAIN_DIFF_WORDERROR_WRITE,
+ gain_step_calib_reg_val[lo_index][i+1]);
+ ad9361_spi_write(phy->spi, REG_CONFIG,
+ CALIB_TABLE_SELECT(0x3) | WRITE_LNA_GAIN_DIFF | START_CALIB_TABLE_CLOCK);
+ udelay(3); //Wait for data to fully write to internal table
+ }
+
+ ad9361_spi_write(phy->spi, REG_CONFIG, START_CALIB_TABLE_CLOCK);
+ ad9361_spi_write(phy->spi, REG_CONFIG, 0x00);
+
+ /* Run and wait until the calibration completes. */
+ ad9361_run_calibration(phy, RX_GAIN_STEP_CAL);
+
+ /* Read the LNA and Mixer error terms into nonvolatile memory. */
+ ad9361_spi_write(phy->spi, REG_CONFIG, CALIB_TABLE_SELECT(0x1) | READ_SELECT);
+ for(i = 0; i < 4; i++) {
+ ad9361_spi_write(phy->spi, REG_WORD_ADDRESS, i);
+ lna_error[i] = ad9361_spi_read(phy->spi, REG_GAIN_ERROR_READ);
+ }
+ ad9361_spi_write(phy->spi, REG_CONFIG, CALIB_TABLE_SELECT(0x1));
+ for(i = 0; i < 15; i++) {
+ ad9361_spi_write(phy->spi, REG_WORD_ADDRESS, i);
+ mixer_error[i] = ad9361_spi_read(phy->spi, REG_GAIN_ERROR_READ);
+ }
+ ad9361_spi_write(phy->spi, REG_CONFIG, 0x00);
+
+ /* Programming gain step errors into the AD9361 in the field */
+ ad9361_spi_write(phy->spi,
+ REG_CONFIG, CALIB_TABLE_SELECT(0x3) | START_CALIB_TABLE_CLOCK);
+ for(i = 0; i < 4; i++) {
+ ad9361_spi_write(phy->spi, REG_WORD_ADDRESS, i);
+ ad9361_spi_write(phy->spi, REG_GAIN_DIFF_WORDERROR_WRITE, lna_error[i]);
+ ad9361_spi_write(phy->spi, REG_CONFIG,
+ CALIB_TABLE_SELECT(0x3) | WRITE_LNA_ERROR_TABLE | START_CALIB_TABLE_CLOCK);
+ }
+ ad9361_spi_write(phy->spi, REG_CONFIG,
+ CALIB_TABLE_SELECT(0x3) | START_CALIB_TABLE_CLOCK);
+ for(i = 0; i < 15; i++) {
+ ad9361_spi_write(phy->spi, REG_WORD_ADDRESS, i);
+ ad9361_spi_write(phy->spi, REG_GAIN_DIFF_WORDERROR_WRITE, mixer_error[i]);
+ ad9361_spi_write(phy->spi, REG_CONFIG,
+ CALIB_TABLE_SELECT(0x3) | WRITE_MIXER_ERROR_TABLE | START_CALIB_TABLE_CLOCK);
+ }
+ ad9361_spi_write(phy->spi, REG_CONFIG, 0x00);
+
+ ad9361_ensm_restore_prev_state(phy);
+
+ return 0;
+}
diff --git a/Radio/HW/BladeRF/common/thirdparty/ad936x/ad9361.h b/Radio/HW/BladeRF/common/thirdparty/ad936x/ad9361.h
new file mode 100644
index 0000000..1a3d45d
--- /dev/null
+++ b/Radio/HW/BladeRF/common/thirdparty/ad936x/ad9361.h
@@ -0,0 +1,3521 @@
+/***************************************************************************//**
+ * @file ad9361.h
+ * @brief Header file of AD9361 Driver.
+********************************************************************************
+ * Copyright 2014(c) Analog Devices, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of Analog Devices, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * - The use of this software may or may not infringe the patent rights
+ * of one or more patent holders. This license does not release you
+ * from the requirement that you obtain separate licenses from these
+ * patent holders to use this software.
+ * - Use of the software either in source or binary form, must be run
+ * on or directly connected to an Analog Devices Inc. component.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+#ifndef IIO_FREQUENCY_AD9361_H_
+#define IIO_FREQUENCY_AD9361_H_
+
+/******************************************************************************/
+/***************************** Include Files **********************************/
+/******************************************************************************/
+#include <stdint.h>
+#include "common.h"
+
+/******************************************************************************/
+/********************** Macros and Constants Definitions **********************/
+/******************************************************************************/
+#define REG_SPI_CONF 0x000 /* SPI Configuration */
+#define REG_MULTICHIP_SYNC_AND_TX_MON_CTRL 0x001 /* Multi-Chip Sync and Tx Mon Control */
+#define REG_TX_ENABLE_FILTER_CTRL 0x002 /* Tx Enable & Filter Control */
+#define REG_RX_ENABLE_FILTER_CTRL 0x003 /* Rx Enable & Filter Control */
+#define REG_INPUT_SELECT 0x004 /* Input Select */
+#define REG_RFPLL_DIVIDERS 0x005 /* RFPLL Dividers */
+#define REG_RX_CLOCK_DATA_DELAY 0x006 /* Rx Clock & Data Delay */
+#define REG_TX_CLOCK_DATA_DELAY 0x007 /* Tx Clock & Data Delay */
+#define REG_CLOCK_ENABLE 0x009 /* Clock Enable */
+#define REG_BBPLL 0x00A /* BBPLL */
+#define REG_TEMP_OFFSET 0x00B /* Offset */
+#define REG_START_TEMP_READING 0x00C /* Start Temp Reading */
+#define REG_TEMP_SENSE2 0x00D /* Temp Sense2 */
+#define REG_TEMPERATURE 0x00E /* Temperature */
+#define REG_TEMP_SENSOR_CONFIG 0x00F /* Temp Sensor Config */
+#define REG_PARALLEL_PORT_CONF_1 0x010 /* Parallel Port Configuration 1 */
+#define REG_PARALLEL_PORT_CONF_2 0x011 /* Parallel Port Configuration 2 */
+#define REG_PARALLEL_PORT_CONF_3 0x012 /* Parallel Port Configuration 3 */
+#define REG_ENSM_MODE 0x013 /* ENSM Mode */
+#define REG_ENSM_CONFIG_1 0x014 /* ENSM Config 1 */
+#define REG_ENSM_CONFIG_2 0x015 /* ENSM Config 2 */
+#define REG_CALIBRATION_CTRL 0x016 /* Calibration Control */
+#define REG_STATE 0x017 /* State */
+#define REG_AUXDAC_1_WORD 0x018 /* AuxDAC 1 Word */
+#define REG_AUXDAC_2_WORD 0x019 /* AuxDAC 2 Word */
+#define REG_AUXDAC_1_CONFIG 0x01A /* AuxDAC 1 Config */
+#define REG_AUXDAC_2_CONFIG 0x01B /* AuxDAC 2 Config */
+#define REG_AUXADC_CLOCK_DIVIDER 0x01C /* AuxADC Clock Divider */
+#define REG_AUXADC_CONFIG 0x01D /* Aux ADC Config */
+#define REG_AUXADC_WORD_MSB 0x01E /* AuxADC Word MSB */
+#define REG_AUXADC_LSB 0x01F /* AuxADC LSB */
+#define REG_AUTO_GPO 0x020 /* Auto GPO */
+#define REG_AGC_GAIN_LOCK_DELAY 0x021 /* AGC Gain Lock Delay */
+#define REG_AGC_ATTACK_DELAY 0x022 /* AGC Attack Delay */
+#define REG_AUXDAC_ENABLE_CTRL 0x023 /* AuxDAC Enable Control */
+#define REG_RX_LOAD_SYNTH_DELAY 0x024 /* RX Load Synth Delay */
+#define REG_TX_LOAD_SYNTH_DELAY 0x025 /* TX Load Synth Delay */
+#define REG_EXTERNAL_LNA_CTRL 0x026 /* External LNA control */
+#define REG_GPO_FORCE_AND_INIT 0x027 /* GPO Force and Init */
+#define REG_GPO0_RX_DELAY 0x028 /* GPO0 Rx delay */
+#define REG_GPO1_RX_DELAY 0x029 /* GPO1 Rx delay */
+#define REG_GPO2_RX_DELAY 0x02A /* GPO2 Rx delay */
+#define REG_GPO3_RX_DELAY 0x02B /* GPO3 Rx delay */
+#define REG_GPO0_TX_DELAY 0x02C /* GPO0 Tx Delay */
+#define REG_GPO1_TX_DELAY 0x02D /* GPO1 Tx Delay */
+#define REG_GPO2_TX_DELAY 0x02E /* GPO2 Tx Delay */
+#define REG_GPO3_TX_DELAY 0x02F /* GPO3 Tx Delay */
+#define REG_AUXDAC1_RX_DELAY 0x030 /* AuxDAC1 Rx Delay */
+#define REG_AUXDAC1_TX_DELAY 0x031 /* AuxDAC1 Tx Delay */
+#define REG_AUXDAC2_RX_DELAY 0x032 /* AuxDAC2 Rx Delay */
+#define REG_AUXDAC2_TX_DELAY 0x033 /* AuxDAC2 Tx Delay */
+#define REG_CTRL_OUTPUT_POINTER 0x035 /* Control Output Pointer */
+#define REG_CTRL_OUTPUT_ENABLE 0x036 /* Control Output Enable */
+#define REG_PRODUCT_ID 0x037 /* Product ID */
+#define REG_REFERENCE_CLOCK_CYCLES 0x03A /* Reference Clock Cycles */
+#define REG_DIGITAL_IO_CTRL 0x03B /* Digital I/O Control */
+#define REG_LVDS_BIAS_CTRL 0x03C /* LVDS Bias control */
+#define REG_LVDS_INVERT_CTRL1 0x03D /* LVDS Invert control1 */
+#define REG_LVDS_INVERT_CTRL2 0x03E /* LVDS Invert control2 */
+#define REG_SDM_CTRL_1 0x03F /* SDM Control 1 */
+#define REG_FRACT_BB_FREQ_WORD_1 0x041 /* Fractional BB Freq Word 1 */
+#define REG_FRACT_BB_FREQ_WORD_2 0x042 /* Fractional BB Freq Word 2 */
+#define REG_FRACT_BB_FREQ_WORD_3 0x043 /* Fractional BB Freq Word 3 */
+#define REG_INTEGER_BB_FREQ_WORD 0x044 /* Integer BB Freq Word */
+#define REG_CLOCK_CTRL 0x045 /* Clock Control */
+#define REG_CP_CURRENT 0x046 /* CP Current */
+#define REG_CP_BLEED_CURRENT 0x047 /* CP Bleed Current */
+#define REG_LOOP_FILTER_1 0x048 /* Loop Filter 1 */
+#define REG_LOOP_FILTER_2 0x049 /* Loop Filter 2 */
+#define REG_LOOP_FILTER_3 0x04A /* Loop Filter 3 */
+#define REG_VCO_CTRL 0x04B /* VCO Control */
+#define REG_VCO_PROGRAM_1 0x04C
+#define REG_VCO_PROGRAM_2 0x04D
+#define REG_SDM_CTRL 0x04E /* SDM Control */
+#define REG_RX_SYNTH_POWER_DOWN_OVERRIDE 0x050 /* Rx Synth Power Down Override */
+#define REG_TX_SYNTH_POWER_DOWN_OVERRIDE 0x051 /* TX Synth Power Down Override */
+#define REG_RX_ANALOG_POWER_DOWN_OVERRIDE_1 0x052 /* Rx Analog Power Down Override 1 */
+#define REG_RX_ANALOG_POWER_DOWN_OVERRIDE_2 0x053 /* Rx Analog Power Down Override 2 */
+#define REG_RX1_ADC_POWER_DOWN_OVERRIDE 0x054 /* Rx1 ADC Power Down Override */
+#define REG_RX2_ADC_POWER_DOWN_OVERRIDE 0x055 /* Rx2 ADC Power Down Override */
+#define REG_TX_ANALOG_POWER_DOWN_OVERRIDE_1 0x056 /* Tx Analog Power Down Override 1 */
+#define REG_ANALOG_POWER_DOWN_OVERRIDE 0x057 /* Analog Power Down Override */
+#define REG_MISC_POWER_DOWN_OVERRIDE 0x058 /* Misc Power Down Override */
+#define REG_CH_1_OVERFLOW 0x05E /* CH 1 Overflow */
+#define REG_CH_2_OVERFLOW 0x05F /* CH 2 Overflow */
+#define REG_TX_FILTER_COEF_ADDR 0x060 /* TX Filter Coefficient Address */
+#define REG_TX_FILTER_COEF_WRITE_DATA_1 0x061 /* TX Filter Coefficient Write Data 1 */
+#define REG_TX_FILTER_COEF_WRITE_DATA_2 0x062 /* TX Filter Coefficient Write Data 2 */
+#define REG_TX_FILTER_COEF_READ_DATA_1 0x063 /* TX Filter Coefficient Read Data 1 */
+#define REG_TX_FILTER_COEF_READ_DATA_2 0x064 /* TX Filter Coefficient Read Data 2 */
+#define REG_TX_FILTER_CONF 0x065 /* TX Filter Configuration */
+#define REG_TX_MON_LOW_GAIN 0x067 /* Tx Mon Low Gain */
+#define REG_TX_MON_HIGH_GAIN 0x068 /* Tx Mon High Gain */
+#define REG_TX_MON_DELAY 0x069 /* Tx Mon Delay */
+#define REG_TX_LEVEL_THRESH 0x06A /* Tx Level Threshold */
+#define REG_TX_RSSI1 0x06B /* TX RSSI1 */
+#define REG_TX_RSSI2 0x06C /* TX RSSI2 */
+#define REG_TX_RSSI_LSB 0x06D /* TX RSSI LSB */
+#define REG_TPM_MODE_ENABLE 0x06E /* TPM Mode Enable */
+#define REG_TX_MON_TEMP_GAIN_COEF 0x06F /* Temp Gain Coefficient */
+#define REG_TX_MON_1_CONFIG 0x070 /* Tx Mon 1 Config */
+#define REG_TX_MON_2_CONFIG 0x071 /* Tx Mon 2 Config */
+#define REG_TX1_ATTEN_0 0x073 /* Tx1 Atten 0 */
+#define REG_TX1_ATTEN_1 0x074 /* Tx1 Atten 1 */
+#define REG_TX2_ATTEN_0 0x075 /* Tx2 Atten 0 */
+#define REG_TX2_ATTEN_1 0x076 /* Tx2 Atten 1 */
+#define REG_TX_ATTEN_OFFSET 0x077 /* Tx Atten Offset */
+#define REG_TX_ATTEN_THRESH 0x078 /* Tx Atten Threshold */
+#define REG_TX1_DIG_ATTEN 0x079 /* Tx1 Dig Attenuation */
+#define REG_TX2_DIG_ATTEN 0x07C /* Tx2 Dig Attenuation */
+#define REG_TX1_SYMBOL_ATTEN 0x07F /* TX1 Symbol Attenuation */
+#define REG_TX2_SYMBOL_ATTEN 0x080 /* TX2 Symbol Attenuation */
+#define REG_TX_SYMBOL_ATTEN_CONFIG 0x081 /* TX Symbol Atten Config */
+#define REG_TX1_OUT_1_PHASE_CORR 0x08E /* Tx1 Out 1 Phase Corr */
+#define REG_TX1_OUT_1_GAIN_CORR 0x08F /* Tx1 Out 1 Gain Corr */
+#define REG_TX2_OUT_1_PHASE_CORR 0x090 /* Tx2 Out 1 Phase Corr */
+#define REG_TX2_OUT_1_GAIN_CORR 0x091 /* Tx2 Out 1 Gain Corr */
+#define REG_TX1_OUT_1_OFFSET_I 0x092 /* Tx1 Out 1 Offset I */
+#define REG_TX1_OUT_1_OFFSET_Q 0x093 /* Tx1 Out 1 Offset Q */
+#define REG_TX2_OUT_1_OFFSET_I 0x094 /* Tx2 Out 1 Offset I */
+#define REG_TX2_OUT_1_OFFSET_Q 0x095 /* Tx2 Out 1 Offset Q */
+#define REG_TX1_OUT_2_PHASE_CORR 0x096 /* Tx1 Out 2 Phase Corr */
+#define REG_TX1_OUT_2_GAIN_CORR 0x097 /* Tx1 Out 2 Gain Corr */
+#define REG_TX2_OUT_2_PHASE_CORR 0x098 /* Tx2 Out 2 Phase Corr */
+#define REG_TX2_OUT_2_GAIN_CORR 0x099 /* Tx2 Out 2 Gain Corr */
+#define REG_TX1_OUT_2_OFFSET_I 0x09A /* Tx1 Out 2 Offset I */
+#define REG_TX1_OUT_2_OFFSET_Q 0x09B /* Tx1 Out 2 Offset Q */
+#define REG_TX2_OUT_2_OFFSET_I 0x09C /* Tx2 Out 2 Offset I */
+#define REG_TX2_OUT_2_OFFSET_Q 0x09D /* Tx2 Out 2 Offset Q */
+#define REG_TX_FORCE_BITS 0x09F /* Force Bits */
+#define REG_QUAD_CAL_NCO_FREQ_PHASE_OFFSET 0x0A0 /* Quad Cal NCO Freq & Phase Offset */
+#define REG_QUAD_CAL_CTRL 0x0A1 /* Quad Cal Control */
+#define REG_KEXP_1 0x0A2 /* Kexp 1 */
+#define REG_KEXP_2 0x0A3 /* Kexp 2 */
+#define REG_QUAD_SETTLE_COUNT 0x0A4 /* QUAD Settle count */
+#define REG_MAG_FTEST_THRESH 0x0A5 /* Mag. Ftest Thresh */
+#define REG_MAG_FTEST_THRESH_2 0x0A6 /* Mag. Ftest Thresh 2 */
+#define REG_QUAD_CAL_STATUS_TX1 0x0A7 /* Quad cal status Tx1 */
+#define REG_QUAD_CAL_STATUS_TX2 0x0A8 /* Quad cal status Tx2 */
+#define REG_QUAD_CAL_COUNT 0x0A9 /* Quad cal Count */
+#define REG_TX_QUAD_FULL_LMT_GAIN 0x0AA /* Tx Quad Full/LMT Gain */
+#define REG_SQUARER_CONFIG 0x0AB /* Squarer Config */
+#define REG_TX_QUAD_CAL_ATTEN 0x0AC /* TX Quad Cal Atten */
+#define REG_THRESH_ACCUM 0x0AD /* Thresh Accum */
+#define REG_TX_QUAD_LPF_GAIN 0x0AE /* Tx Quad LPF Gain */
+#define REG_TXDAC_VDS_I 0x0B0 /* TxDAC Vds I */
+#define REG_TXDAC_VDS_Q 0x0B1 /* TxDAC Vds Q */
+#define REG_TXDAC_GN_I 0x0B2 /* TxDAC gn I */
+#define REG_TXDAC_GN_Q 0x0B3 /* TxDAC gn Q */
+#define REG_TXBBF_OPAMP_A 0x0C0 /* TxBBF OpAmp A */
+#define REG_TXBBF_OPAMP_B 0x0C1 /* TxBBF OpAmp B */
+#define REG_TX_BBF_R1 0x0C2 /* Tx BBF R1 */
+#define REG_TX_BBF_R2 0x0C3 /* Tx BBF R2 */
+#define REG_TX_BBF_R3 0x0C4 /* Tx BBF R3 */
+#define REG_TX_BBF_R4 0x0C5 /* Tx BBF R4 */
+#define REG_TX_BBF_RP 0x0C6 /* Tx BBF RP */
+#define REG_TX_BBF_C1 0x0C7 /* Tx BBF C1 */
+#define REG_TX_BBF_C2 0x0C8 /* Tx BBF C2 */
+#define REG_TX_BBF_CP 0x0C9 /* Tx BBF Cp */
+#define REG_TX_TUNE_CTRL 0x0CA /* Tx Tune Control */
+#define REG_TX_BBF_R2B 0x0CB /* Tx BBF R2b */
+#define REG_TX_BBF_TUNE 0x0CC /* Tx BBF Tune */
+#define REG_CONFIG0 0x0D0 /* Config0 */
+#define REG_RESISTOR 0x0D1 /* Resistor */
+#define REG_CAPACITOR 0x0D2 /* Capacitor */
+#define REG_LO_CM 0x0D3 /* LO CM */
+#define REG_TX_BBF_TUNE_DIVIDER 0x0D6 /* TX BBF Tune Divider */
+#define REG_TX_BBF_TUNE_MODE 0x0D7 /* TX BBF Tune Mode */
+#define REG_RX_FILTER_COEF_ADDR 0x0F0 /* Rx Filter Coeff Addr */
+#define REG_RX_FILTER_COEF_DATA_1 0x0F1 /* Rx Filter Coeff Data 1 */
+#define REG_RX_FILTER_COEF_DATA_2 0x0F2 /* Rx Filter Coeff Data 2 */
+#define REG_RX_FILTER_COEF_READ_DATA_1 0x0F3 /* Rx Filter Coeff Read Data 1 */
+#define REG_RX_FILTER_COEF_READ_DATA_2 0x0F4 /* Rx Filter Coeff Read Data 2 */
+#define REG_RX_FILTER_CONFIG 0x0F5 /* Rx Filter Config */
+#define REG_RX_FILTER_GAIN 0x0F6 /* Rx Filter Gain */
+#define REG_AGC_CONFIG_1 0x0FA /* AGC Config1 */
+#define REG_AGC_CONFIG_2 0x0FB /* AGC config2 */
+#define REG_AGC_CONFIG_3 0x0FC /* AGC Config3 */
+#define REG_MAX_LMT_FULL_GAIN 0x0FD /* Max LMT/Full Gain */
+#define REG_PEAK_WAIT_TIME 0x0FE /* Peak Wait Time */
+#define REG_DIGITAL_GAIN 0x100 /* Digital Gain */
+#define REG_AGC_LOCK_LEVEL 0x101 /* AGC Lock Level */
+#define REG_ADC_NOISE_CORRECTION_FACTOR 0x102 /* ADC noise Correction Factor */
+#define REG_GAIN_STP_CONFIG1 0x103 /* Gain Step Config1 */
+#define REG_ADC_SMALL_OVERLOAD_THRESH 0x104 /* ADC Small Overload Threshold */
+#define REG_ADC_LARGE_OVERLOAD_THRESH 0x105 /* ADC Large Overload Threshold */
+#define REG_GAIN_STP_CONFIG_2 0x106 /* Gain Step Config 2 */
+#define REG_SMALL_LMT_OVERLOAD_THRESH 0x107 /* Small LMT Overload Threshold */
+#define REG_LARGE_LMT_OVERLOAD_THRESH 0x108 /* Large LMT Overload Threshold */
+#define REG_RX1_MANUAL_LMT_FULL_GAIN 0x109 /* Rx1 Manual LMT/Full Gain */
+#define REG_RX1_MANUAL_LPF_GAIN 0x10A /* Rx1 Manual LPF gain */
+#define REG_RX1_MANUAL_DIGITALFORCED_GAIN 0x10B /* Rx1 Manual Digital/Forced Gain */
+#define REG_RX2_MANUAL_LMT_FULL_GAIN 0x10C /* Rx2 Manual LMT/Full Gain */
+#define REG_RX2_MANUAL_LPF_GAIN 0x10D /* Rx2 Manual LPF Gain */
+#define REG_RX2_MANUAL_DIGITALFORCED_GAIN 0x10E /* Rx2 Manual Digital/Forced Gain */
+#define REG_FAST_CONFIG_1 0x110 /* Config 1 */
+#define REG_FAST_CONFIG_2_SETTLING_DELAY 0x111 /* Config 2 & Settling Delay */
+#define REG_FAST_ENERGY_LOST_THRESH 0x112 /* Energy Lost Threshold */
+#define REG_FAST_STRONGER_SIGNAL_THRESH 0x113 /* Stronger Signal Threshold */
+#define REG_FAST_LOW_POWER_THRESH 0x114 /* Low Power Threshold */
+#define REG_FAST_STRONG_SIGNAL_FREEZE 0x115 /* Strong Signal Freeze */
+#define REG_FAST_FINAL_OVER_RANGE_AND_OPT_GAIN 0x116 /* Final Over Range and Opt Gain */
+#define REG_FAST_ENERGY_DETECT_COUNT 0x117 /* Energy Detect Count */
+#define REG_FAST_AGCLL_UPPER_LIMIT 0x118 /* AGCLL Upper Limit */
+#define REG_FAST_GAIN_LOCK_EXIT_COUNT 0x119 /* Gain Lock Exit Count */
+#define REG_FAST_INITIAL_LMT_GAIN_LIMIT 0x11A /* Initial LMT Gain Limit */
+#define REG_FAST_INCREMENT_TIME 0x11B /* Increment Time */
+#define REG_AGC_INNER_LOW_THRESH 0x120 /* AGC Inner Low Threshold */
+#define REG_LMT_OVERLOAD_COUNTERS 0x121 /* LMT Overload Counters */
+#define REG_ADC_OVERLOAD_COUNTERS 0x122 /* ADC Overload Counters */
+#define REG_GAIN_STP1 0x123 /* Gain Step1 */
+#define REG_GAIN_UPDATE_COUNTER1 0x124 /* Gain Update Counter1 */
+#define REG_GAIN_UPDATE_COUNTER2 0x125 /* Gain Update Counter2 */
+#define REG_DIGITAL_SAT_COUNTER 0x128 /* Digital Sat Counter */
+#define REG_OUTER_POWER_THRESHS 0x129 /* Outer Power Thresholds */
+#define REG_GAIN_STP_2 0x12A /* Gain Step 2 */
+#define REG_EXT_LNA_HIGH_GAIN 0x12C /* Ext LNA High Gain */
+#define REG_EXT_LNA_LOW_GAIN 0x12D /* Ext LNA Low Gain */
+#define REG_GAIN_TABLE_ADDRESS 0x130 /* Gain Table Address */
+#define REG_GAIN_TABLE_WRITE_DATA1 0x131 /* Gain Table Write Data1 */
+#define REG_GAIN_TABLE_WRITE_DATA2 0x132 /* Gain Table Write Data2 */
+#define REG_GAIN_TABLE_WRITE_DATA3 0x133 /* Gain Table Write Data 3 */
+#define REG_GAIN_TABLE_READ_DATA1 0x134 /* Gain Table Read Data 1 */
+#define REG_GAIN_TABLE_READ_DATA2 0x135 /* Gain Table Read Data 2 */
+#define REG_GAIN_TABLE_READ_DATA3 0x136 /* Gain Table Read Data 3 */
+#define REG_GAIN_TABLE_CONFIG 0x137 /* Gain Table Config */
+#define REG_GM_SUB_TABLE_ADDRESS 0x138 /* Gm Sub Table Address */
+#define REG_GM_SUB_TABLE_GAIN_WRITE 0x139 /* Gm Sub Table Gain Word Write */
+#define REG_GM_SUB_TABLE_BIAS_WRITE 0x13A /* Gm Sub Table Bias Word Write */
+#define REG_GM_SUB_TABLE_CTRL_WRITE 0x13B /* Gm Sub Table Control Word Write */
+#define REG_GM_SUB_TABLE_GAIN_READ 0x13C /* Gm Sub Table Gain Word Read */
+#define REG_GM_SUB_TABLE_BIAS_READ 0x13D /* Gm Sub Table Bias Word Read */
+#define REG_GM_SUB_TABLE_CTRL_READ 0x13E /* Gm Sub Table Control Word Read */
+#define REG_GM_SUB_TABLE_CONFIG 0x13F /* Gm Sub Table Config */
+#define REG_WORD_ADDRESS 0x140 /* Word Address */
+#define REG_GAIN_DIFF_WORDERROR_WRITE 0x141 /* Gain Diff Word/Error Write */
+#define REG_GAIN_ERROR_READ 0x142 /* Gain Error Read */
+#define REG_CONFIG 0x143 /* Config */
+#define REG_LNA_GAIN_DIFF_READ_BACK 0x144 /* LNA Gain Diff Read Back */
+#define REG_MAX_MIXER_CALIBRATION_GAIN_INDEX 0x145 /* Max Mixer Calibration Gain Index */
+#define REG_TEMP_GAIN_COEF 0x146 /* Temp Gain Coefficient */
+#define REG_SETTLE_TIME 0x147 /* Settle Time */
+#define REG_MEASURE_DURATION 0x148 /* Measure Duration */
+#define REG_CAL_TEMP_SENSOR_WORD 0x149 /* Cal Temp sensor word */
+#define REG_MEASURE_DURATION_01 0x150 /* Measure Duration 0&1 */
+#define REG_MEASURE_DURATION_23 0x151 /* Measure Duration 2&3 */
+#define REG_RSSI_WEIGHT_0 0x152 /* RSSI Weight 0 */
+#define REG_RSSI_WEIGHT_1 0x153 /* RSSI Weight 1 */
+#define REG_RSSI_WEIGHT_2 0x154 /* RSSI Weight 2 */
+#define REG_RSSI_WEIGHT_3 0x155 /* RSSI Weight 3 */
+#define REG_RSSI_DELAY 0x156 /* RSSI delay */
+#define REG_RSSI_WAIT_TIME 0x157 /* RSSI wait time */
+#define REG_RSSI_CONFIG 0x158 /* RSSI Config */
+#define REG_ADC_MEASURE_DURATION_01 0x159 /* ADC Measure Duration 0&1 */
+#define REG_ADC_WEIGHT_0 0x15A /* ADC Weight 0 */
+#define REG_ADC_WEIGHT_1 0x15B /* ADC Weight 1 */
+#define REG_DEC_POWER_MEASURE_DURATION_0 0x15C /* Dec Power Measure Duration 0 */
+#define REG_LNA_GAIN 0x15D /* LNA Gain */
+#define REG_CH1_ADC_POWER 0x160 /* CH1 ADC Power */
+#define REG_CH1_RX_FILTER_POWER 0x161 /* CH1 Rx filter Power */
+#define REG_CH2_ADC_POWER 0x162 /* CH2 ADC Power */
+#define REG_CH2_RX_FILTER_POWER 0x163 /* CH2 Rx filter Power */
+#define REG_RX_QUAD_CAL_LEVEL 0x168 /* Rx Quad Cal Level */
+#define REG_CALIBRATION_CONFIG_1 0x169 /* Calibration Config 1 */
+#define REG_CALIBRATION_CONFIG_2 0x16A /* Calibration config2 */
+#define REG_CALIBRATION_CONFIG_3 0x16B /* Calibration config3 */
+#define REG_CALIB_COUNT 0x16C /* Calib count */
+#define REG_SETTLE_COUNT 0x16D /* Settle count */
+#define REG_RX_QUAD_GAIN1 0x16E /* Rx Quad gain1 */
+#define REG_RX_QUAD_GAIN2 0x16F /* Rx Quad gain2 */
+#define REG_RX1_INPUT_A_PHASE_CORR 0x170 /* Rx1 Input A Phase Corr */
+#define REG_RX1_INPUT_A_GAIN_CORR 0x171 /* Rx1 Input A Gain Corr */
+#define REG_RX2_INPUT_A_PHASE_CORR 0x172 /* Rx2 Input A Phase Corr */
+#define REG_RX2_INPUT_A_GAIN_CORR 0x173 /* Rx2 Input A Gain Corr */
+#define REG_RX1_INPUT_A_Q_OFFSET 0x174 /* Rx1 Input A Q" Offset */
+#define REG_RX1_INPUT_A_OFFSETS 0x175 /* Rx1 Input A Offsets */
+#define REG_INPUT_A_OFFSETS_1 0x176 /* Input A Offsets 1 */
+#define REG_RX2_INPUT_A_OFFSETS 0x177 /* Rx2 Input A Offsets */
+#define REG_RX2_INPUT_A_I_OFFSET 0x178 /* Rx2 Input A "I" Offset */
+#define REG_RX1_INPUT_BC_PHASE_CORR 0x179 /* Rx1 Input B&C Phase Corr */
+#define REG_RX1_INPUT_BC_GAIN_CORR 0x17A /* Rx1 Input B&C Gain Corr */
+#define REG_RX2_INPUT_BC_PHASE_CORR 0x17B /* Rx2 Input B&C Phase Corr */
+#define REG_RX2_INPUT_BC_GAIN_CORR 0x17C /* Rx2 Input B&C Gain Corr */
+#define REG_RX1_INPUT_BC_Q_OFFSET 0x17D /* Rx1 Input B&C "Q" Offset */
+#define REG_RX1_INPUT_BC_OFFSETS 0x17E /* Rx1 Input B&C Offsets */
+#define REG_INPUT_BC_OFFSETS_1 0x17F /* Input B&C Offsets 1 */
+#define REG_RX2_INPUT_BC_OFFSETS 0x180 /* Rx2 Input B&C Offsets */
+#define REG_RX2_INPUT_BC_I_OFFSET 0x181 /* Rx2 Input B&C "I" Offset */
+#define REG_FORCE_BITS 0x182 /* Force Bits */
+#define REG_WAIT_COUNT 0x185 /* Wait Count */
+#define REG_RF_DC_OFFSET_COUNT 0x186 /* RF DC Offset Count */
+#define REG_RF_DC_OFFSET_CONFIG_1 0x187 /* RF DC Offset Config1 */
+#define REG_RF_DC_OFFSET_ATTEN 0x188 /* RF DC Offset Attenuation */
+#define REG_INVERT_BITS 0x189 /* Invert Bits */
+#define REG_DC_OFFSET_CONFIG2 0x18B /* DC Offset Config2 */
+#define REG_RF_CAL_GAIN_INDEX 0x18C /* RF Cal Gain Index */
+#define REG_SOI_THRESH 0x18D /* SOI Threshold */
+#define REG_BB_DC_OFFSET_SHIFT 0x190 /* BB DC Offset Shift */
+#define REG_BB_DC_OFFSET_FAST_SETTLE_SHIFT 0x191 /* BB DC Offset Fast Settle Shift */
+#define REG_BB_FAST_SETTLE_DUR 0x192 /* BB Fast Settle Dur */
+#define REG_BB_DC_OFFSET_COUNT 0x193 /* BB DC Offset Count */
+#define REG_BB_DC_OFFSET_ATTEN 0x194 /* BB DC Offset Attenuation */
+#define REG_RX1_BB_DC_WORD_I_MSB 0x19A /* RX1 BB DC word I MSB */
+#define REG_RX1_BB_DC_WORD_I_LSB 0x19B /* RX1 BB DC word I LSB */
+#define REG_RX1_BB_DC_WORD_Q_MSB 0x19C /* RX1 BB DC word Q MSB */
+#define REG_RX1_BB_DC_WORD_Q_LSB 0x19D /* RX1 BB DC word Q LSB */
+#define REG_RX2_BB_DC_WORD_I_MSB 0x19E /* RX2 BB DC word I MSB */
+#define REG_RX2_BB_DC_WORD_I_LSB 0x19F /* RX2 BB DC word I LSB */
+#define REG_RX2_BB_DC_WORD_Q_MSB 0x1A0 /* RX2 BB DC word Q MSB */
+#define REG_RX2_BB_DC_WORD_Q_LSB 0x1A1 /* RX2 BB DC word Q LSB */
+#define REG_BB_TRACK_CORR_WORD_I_MSB 0x1A2 /* BB Track corr word I MSB */
+#define REG_BB_TRACK_CORR_WORD_I_LSB 0x1A3 /* BB Track corr word I LSB */
+#define REG_BB_TRACK_CORR_WORD_Q_MSB 0x1A4 /* BB Track corr word Q MSB */
+#define REG_BB_TRACK_CORR_WORD_Q_LSB 0x1A5 /* BB Track corr word Q LSB */
+#define REG_RX1_RSSI_SYMBOL 0x1A7 /* Rx1 RSSI Symbol */
+#define REG_RX1_RSSI_PREAMBLE 0x1A8 /* Rx1 RSSI preamble */
+#define REG_RX2_RSSI_SYMBOL 0x1A9 /* Rx2 RSSI symbol */
+#define REG_RX2_RSSI_PREAMBLE 0x1AA /* Rx2 RSSI preamble */
+#define REG_SYMBOL_LSB 0x1AB /* Symbol LSB */
+#define REG_PREAMBLE_LSB 0x1AC /* Preamble LSB */
+#define REG_RX_PATH_GAIN_MSB 0x1AD /* Rx Path Gain */
+#define REG_RX_PATH_GAIN_LSB 0x1AE /* Rx Path Gain */
+#define REG_RX_DIFF_LNA_FORCE 0x1B0 /* Rx Diff LNA Force */
+#define REG_RX_LNA_BIAS_COARSE 0x1B1 /* Rx LNA Bias Coarse */
+#define REG_RX_LNA_BIAS_FINE_0 0x1B2 /* Rx LNA Bias Fine 0 */
+#define REG_RX_LNA_BIAS_FINE_1 0x1B3 /* Rx LNA Bias Fine 1 */
+#define REG_RX_MIX_GM_CONFIG 0x1C0 /* Rx Mix Gm Config */
+#define REG_RX1_MIX_GM_FORCE 0x1C1 /* Rx1 Mix Gm Force */
+#define REG_RX1_MIX_GM_BIAS_FORCE 0x1C2 /* Rx1 Mix Gm Bias (Force) */
+#define REG_RX2_MIX_GM_FORCE 0x1C3 /* Rx2 Mix Gm Force */
+#define REG_RX2_MIX_GM_BIAS_FORCE 0x1C4 /* Rx2 Mix Gm Bias (Force) */
+#define REG_INPUT_A_MSBS 0x1C8 /* Input A MSBs */
+#define REG_INPUT_A_RX1_I 0x1C9 /* Input A RX1 I */
+#define REG_INPUT_A_RX1_Q 0x1CA /* Input A RX1 Q */
+#define REG_INPUT_A_RX2_I 0x1CB /* Input A RX2 I */
+#define REG_INPUT_A_RX2_Q 0x1CC /* Input A RX2 Q */
+#define REG_INPUTS_BC_RX1_I 0x1CD /* Inputs B&C RX1 I */
+#define REG_BAND1_RX1_Q 0x1CE /* Band1 RX1 Q */
+#define REG_INPUTS_BC_RX2_I 0x1CF /* Inputs B&C RX2 I */
+#define REG_INPUTS_BC_RX2_Q 0x1D0 /* Inputs B&C RX2 Q */
+#define REG_INPUTS_BC_MSBS 0x1D1 /* Inputs B&C MSBs */
+#define REG_FORCE_OS_DAC 0x1D2 /* Force OS DAC */
+#define REG_RX_MIX_LO_CM 0x1D5 /* Rx Mix LO CM */
+#define REG_RX_CGB_SEG_ENABLE 0x1D6 /* Rx CGB Seg Enable */
+#define REG_RX_MIX_INPUTBIAS 0x1D7 /* Rx Mix Input/Bias */
+#define REG_RX_TIA_CONFIG 0x1DB /* Rx TIA Config */
+#define REG_TIA1_C_LSB 0x1DC /* TIA1 C LSB */
+#define REG_TIA1_C_MSB 0x1DD /* TIA1 C MSB */
+#define REG_TIA2_C_LSB 0x1DE /* TIA2 C LSB */
+#define REG_TIA2_C_MSB 0x1DF /* TIA2 C MSB */
+#define REG_RX1_BBF_R1A 0x1E0 /* Rx1 BBF R1A */
+#define REG_RX2_BBF_R1A 0x1E1 /* Rx2 BBF R1A */
+#define REG_RX1_TUNE_CTRL 0x1E2 /* Rx1 Tune Control */
+#define REG_RX2_TUNE_CTRL 0x1E3 /* Rx2 Tune Control */
+#define REG_RX1_BBF_R5 0x1E4 /* Rx1 BBF R5 */
+#define REG_RX2_BBF_R5 0x1E5 /* Rx2 BBF R5 */
+#define REG_RX_BBF_R2346 0x1E6 /* Rx BBF R2346 */
+#define REG_RX_BBF_C1_MSB 0x1E7 /* Rx BBF C1 MSB */
+#define REG_RX_BBF_C1_LSB 0x1E8 /* Rx BBF C1 LSB */
+#define REG_RX_BBF_C2_MSB 0x1E9 /* Rx BBF C2 MSB */
+#define REG_RX_BBF_C2_LSB 0x1EA /* Rx BBF C2 LSB */
+#define REG_RX_BBF_C3_MSB 0x1EB /* Rx BBF C3 MSB */
+#define REG_RX_BBF_C3_LSB 0x1EC /* Rx BBF C3 LSB */
+#define REG_RX_BBF_CC1_CTR 0x1ED /* Rx BBF CC1 Ctr */
+#define REG_RX_BBF_POW_RZ_BYTE0 0x1EE /* Rx BBF Pow Rz Byte0 */
+#define REG_RX_BBF_CC2_CTR 0x1EF /* Rx BBF CC2 Ctr */
+#define REG_RX_BBF_POW_RZ_BYTE1 0x1F0 /* Rx BBF Pow Rz Byte1 */
+#define REG_RX_BBF_CC3_CTR 0x1F1 /* Rx BBF CC3 Ctr */
+#define REG_RX_BBF_R5_TUNE 0x1F2 /* Rx BBF R5 Tune */
+#define REG_RX_BBF_TUNE 0x1F3 /* Rx BBF Tune */
+#define REG_RX1_BBF_MAN_GAIN 0x1F4 /* Rx1 BBF Man Gain */
+#define REG_RX2_BBF_MAN_GAIN 0x1F5 /* Rx2 BBF Man Gain */
+#define REG_RX_BBF_TUNE_DIVIDE 0x1F8 /* RX BBF Tune Divide */
+#define REG_RX_BBF_TUNE_CONFIG 0x1F9 /* RX BBF Tune Config */
+#define REG_POLE_GAIN 0x1FA /* Pole gain */
+#define REG_RX_BBBW_MHZ 0x1FB /* Rx BBBW MHz */
+#define REG_RX_BBBW_KHZ 0x1FC /* Rx BBBW kHz */
+#define REG_FB_DAC_CLK_DELAY1 0x201 /* FB DAC Clk Delay1 */
+#define REG_FB_DAC_CLK_DELAY2 0x202 /* FB DAC Clk Delay2 */
+#define REG_FLASH_SAMPLE_CLK_DELAY_3P 0x203 /* Flash Sample Clk Delay 3p */
+#define REG_FLASH_SAMPLE_CLK_DELAY_3N 0x204 /* Flash Sample Clk Delay 3n */
+#define REG_TEST_MUX_2I 0x205 /* Test MUX 2i */
+#define REG_TEST_MUX_2Q 0x206 /* Test MUX 2q */
+#define REG_INTEGRATOR_1_RESISTANCE 0x207 /* Integrator 1 Resistance */
+#define REG_INTEGRATOR_1_CAPACITANCE 0x208 /* Integrator 1 Capacitance */
+#define REG_INTEGRATOR_23_RESISTANCE 0x209 /* Integrator 23 Resistance */
+#define REG_INTEGRATOR_2_RESISTANCE 0x20A /* Integrator 2 Resistance */
+#define REG_INTEGRATOR_2_CAPACITANCE 0x20B /* Integrator 2 Capacitance */
+#define REG_INTEGRATOR_3_RESISTANCE 0x20C /* Integrator 3 Resistance */
+#define REG_INTEGRATOR_3_CAPACITANCE 0x20D /* Integrator 3 Capacitance */
+#define REG_INTEGRATOR_AMP_CC 0x20E /* Integrator Amp Cc */
+#define REG_INT_1_FB_DAC_NMOS_CURRENT_SOURCE 0x20F /* Int 1 FB DAC NMOS Current Source */
+#define REG_INT_1_FB_DAC_NMOS_CASOADE_BIAS_CURRENT 0x210 /* Int 1 FB DAC NMOS Casoade Bias Current */
+#define REG_INT_1_FB_DAC_PMOS_CURRENT_SOURCE 0x211 /* Int 1 FB DAC PMOS Current Source */
+#define REG_INT_2_FB_DAC_NMOS_CURRENT_SOURCE 0x212 /* Int 2 FB DAC NMOS Current Source */
+#define REG_INT_2_FB_DAC_NMOS_CASCODE_BIAS_CURRENT 0x213 /* Int 2 FB DAC NMOS Cascode Bias Current */
+#define REG_INT_2_FB_DAC_PMOS_CURRENT_SOURCE 0x214 /* Int 2 FB DAC PMOS Current Source */
+#define REG_INT_3_FB_DAC_NMOS_CURRENT_SOURCE 0x215 /* Int 3 FB DAC NMOS Current Source */
+#define REG_INT_3_FB_DAC_NMOS_CASCODE_BIAS_CURRENT 0x216 /* Int 3 FB DAC NMOS Cascode Bias Current */
+#define REG_INT_3_FB_DAC_PMOS_CURRENT_SOURCE 0x217 /* Int 3 FB DAC PMOS Current Source */
+#define REG_FB_DAC_BIAS_CURRENT 0x218 /* FB DAC Bias Current */
+#define REG_INT_1_1ST_STAGE_CURRENT 0x219 /* Int 1 1st Stage Current */
+#define REG_INT_1_1ST_STAGE_CASCODE_CURRENT 0x21A /* Int 1 1st Stage Cascode Current */
+#define REG_INT_1_2ND_STAGE_CURRENT 0x21B /* Int 1 2nd Stage Current */
+#define REG_INTEGRATOR_2_1ST_STAGE_CURRENT 0x21C /* Integrator 2 1st Stage Current */
+#define REG_INT_2_1ST_STAGE_CASCODE_CURRENT 0x21D /* Int 2 1st Stage Cascode Current */
+#define REG_INT_2_2ND_STAGE_CURRENT 0x21E /* Int 2 2nd Stage Current */
+#define REG_INT_3_1ST_STAGE_CURRENT 0x21F /* Int 3 1st Stage Current */
+#define REG_INT_3_1ST_STAGE_CASCODE_CURRENT 0x220 /* Int 3 1st Stage Cascode Current */
+#define REG_INT_3_2ND_STAGE_CURRENT 0x221 /* Int 3 2nd Stage Current */
+#define REG_FLASH_BIAS_CURRENT 0x222 /* Flash Bias Current */
+#define REG_FLASH_LADDER_BIAS 0x223 /* Flash Ladder Bias */
+#define REG_FLASH_LADDER_CASCODE_CURRENT 0x224 /* Flash Ladder Cascode Current */
+#define REG_FLASH_LADDER_BIAS2 0x225 /* Flash Ladder Bias2 */
+#define REG_RESET 0x226 /* Reset */
+#define REG_RX_PFD_CONFIG 0x230 /* RX PFD Config */
+#define REG_RX_INTEGER_BYTE_0 0x231 /* RX Integer Byte 0 */
+#define REG_RX_INTEGER_BYTE_1 0x232 /* RX Integer Byte 1 */
+#define REG_RX_FRACT_BYTE_0 0x233 /* RX Fractional Byte 0 */
+#define REG_RX_FRACT_BYTE_1 0x234 /* RX Fractional Byte 1 */
+#define REG_RX_FRACT_BYTE_2 0x235 /* RX Fractional Byte 2 */
+#define REG_RX_FORCE_ALC 0x236 /* RX Force ALC */
+#define REG_RX_FORCE_VCO_TUNE_0 0x237 /* RX Force VCO Tune 0 */
+#define REG_RX_FORCE_VCO_TUNE_1 0x238 /* RX Force VCO Tune 1 */
+#define REG_RX_ALC_VARACTOR 0x239 /* RX ALC/Varactor */
+#define REG_RX_VCO_OUTPUT 0x23A /* RX VCO Output */
+#define REG_RX_CP_CURRENT 0x23B /* RX CP Current */
+#define REG_RX_CP_OFFSET 0x23C /* RX CP Offset */
+#define REG_RX_CP_CONFIG 0x23D /* RX CP Config */
+#define REG_RX_LOOP_FILTER_1 0x23E /* RX Loop Filter 1 */
+#define REG_RX_LOOP_FILTER_2 0x23F /* RX Loop Filter 2 */
+#define REG_RX_LOOP_FILTER_3 0x240 /* RX Loop Filter 3 */
+#define REG_RX_DITHERCP_CAL 0x241 /* RX Dither/CP Cal */
+#define REG_RX_VCO_BIAS_1 0x242 /* RX VCO Bias 1 */
+#define REG_RX_CAL_STATUS 0x244 /* RX Cal Status */
+#define REG_RX_VCO_CAL_REF 0x245 /* RX VCO Cal Ref */
+#define REG_RX_VCO_PD_OVERRIDES 0x246 /* RX VCO Pd Overrides */
+#define REG_RX_CP_OVERRANGE_VCO_LOCK 0x247 /* RX CP Over Range/VCO Lock */
+#define REG_RX_VCO_LDO 0x248 /* RX VCO LDO */
+#define REG_RX_VCO_CAL 0x249 /* RX VCO Cal */
+#define REG_RX_LOCK_DETECT_CONFIG 0x24A /* RX Lock Detect Config */
+#define REG_RX_CP_LEVEL_DETECT 0x24B /* RX CP Level Detect */
+#define REG_RX_DSM_SETUP_0 0x24C /* RX DSM Setup 0 */
+#define REG_RX_DSM_SETUP_1 0x24D /* RX DSM Setup 1 */
+#define REG_RX_CORRECTION_WORD0 0x24E /* RX Correction Word0 */
+#define REG_RX_CORRECTION_WORD1 0x24F /* RX Correction Word1 */
+#define REG_RX_VCO_VARACTOR_CTRL_0 0x250 /* RX VCO Varactor Control 0 */
+#define REG_RX_VCO_VARACTOR_CTRL_1 0x251 /* RX VCO Varactor Control 1 */
+#define REG_RX_FAST_LOCK_SETUP 0x25A /* Rx Fast Lock Setup */
+#define REG_RX_FAST_LOCK_SETUP_INIT_DELAY 0x25B /* Rx Fast Lock Setup Init Delay */
+#define REG_RX_FAST_LOCK_PROGRAM_ADDR 0x25C /* Rx Fast Lock Program Addr */
+#define REG_RX_FAST_LOCK_PROGRAM_DATA 0x25D /* Rx Fast Lock Program Data */
+#define REG_RX_FAST_LOCK_PROGRAM_READ 0x25E /* Rx Fast Lock Program Read */
+#define REG_RX_FAST_LOCK_PROGRAM_CTRL 0x25F /* Rx Fast Lock Program Control */
+#define REG_RX_LO_GEN_POWER_MODE 0x261 /* Rx LO Gen Power Mode */
+#define REG_TX_PFD_CONFIG 0x270 /* TX PFD Config */
+#define REG_TX_INTEGER_BYTE_0 0x271 /* TX Integer Byte 0 */
+#define REG_TX_INTEGER_BYTE_1 0x272 /* TX Integer Byte 1 */
+#define REG_TX_FRACT_BYTE_0 0x273 /* TX Fractional Byte 0 */
+#define REG_TX_FRACT_BYTE_1 0x274 /* TX Fractional Byte 1 */
+#define REG_TX_FRACT_BYTE_2 0x275 /* TX Fractional Byte 2 */
+#define REG_TX_FORCE_ALC 0x276 /* TX Force ALC */
+#define REG_TX_FORCE_VCO_TUNE_0 0x277 /* TX Force VCO Tune 0 */
+#define REG_TX_FORCE_VCO_TUNE_1 0x278 /* TX Force VCO Tune 1 */
+#define REG_TX_ALCVARACT_OR 0x279 /* TX ALC/Varact or */
+#define REG_TX_VCO_OUTPUT 0x27A /* TX VCO Output */
+#define REG_TX_CP_CURRENT 0x27B /* TX CP Current */
+#define REG_TX_CP_OFFSET 0x27C /* TX CP Offset */
+#define REG_TX_CP_CONFIG 0x27D /* TX CP Config */
+#define REG_TX_LOOP_FILTER_1 0x27E /* TX Loop Filter 1 */
+#define REG_TX_LOOP_FILTER_2 0x27F /* TX Loop Filter 2 */
+#define REG_TX_LOOP_FILTER_3 0x280 /* TX Loop Filter 3 */
+#define REG_TX_DITHERCP_CAL 0x281 /* TX Dither/CP Cal */
+#define REG_TX_VCO_BIAS_1 0x282 /* TX VCO Bias 1 */
+#define REG_TX_VCO_BIAS_2 0x283 /* TX VCO Bias 2 */
+#define REG_TX_CAL_STATUS 0x284 /* TX Cal Status */
+#define REG_TX_VCO_CAL_REF 0x285 /* TX VCO Cal Ref */
+#define REG_TX_VCO_PD_OVERRIDES 0x286 /* TX VCO Pd Overrides */
+#define REG_TX_CP_OVERRANGE_VCO_LOCK 0x287 /* TX CP Over Range/VCO Lock */
+#define REG_TX_VCO_LDO 0x288 /* TX VCO LDO */
+#define REG_TX_VCO_CAL 0x289 /* TX VCO Cal */
+#define REG_TX_LOCK_DETECT_CONFIG 0x28A /* TX Lock Detect Config */
+#define REG_TX_CP_LEVEL_DETECT 0x28B /* TX CP Level Detect */
+#define REG_TX_DSM_SETUP_0 0x28C /* TX DSM Setup 0 */
+#define REG_TX_DSM_SETUP_1 0x28D /* TX DSM Setup 1 */
+#define REG_TX_CORRECTION_WORD0 0x28E /* TX Correction Word0 */
+#define REG_TX_CORRECTION_WORD1 0x28F /* TX Correction Word1 */
+#define REG_TX_VCO_VARACTOR_CTRL_0 0x290 /* TX VCO Varactor Control 0 */
+#define REG_TX_VCO_VARACTOR_CTRL_1 0x291 /* TX VCO Varactor Control 1 */
+#define REG_DCXO_COARSE_TUNE 0x292 /* DCXO Coarse Tune */
+#define REG_DCXO_FINE_TUNE_HIGH 0x293 /* DCXO Fine Tune2 */
+#define REG_DCXO_FINE_TUNE_LOW 0x294 /* DCXO Fine Tune1 */
+#define REG_DCXO_CONFIG 0x295 /* DCXO Config */
+#define REG_DCXO_TEMPCO_WRITE 0x296 /* DCXO Tempco Write */
+#define REG_DCXO_TEMPCO_READ 0x297 /* DCXO Tempco Read */
+#define REG_DCXO_TEMPCO_ADDR 0x298 /* DCXO Tempco Addr */
+#define REG_DELTA_T_READ 0x299 /* Delta T Read */
+#define REG_TX_FAST_LOCK_SETUP 0x29A /* Tx Fast Lock Setup */
+#define REG_TX_FAST_LOCK_SETUP_INIT_DELAY 0x29B /* Tx Fast Lock Setup Init Delay */
+#define REG_TX_FAST_LOCK_PROGRAM_ADDR 0x29C /* Tx Fast Lock Program Addr */
+#define REG_TX_FAST_LOCK_PROGRAM_DATA 0x29D /* Tx Fast Lock Program Data */
+#define REG_TX_FAST_LOCK_PROGRAM_READ 0x29E /* Tx Fast Lock Program Read */
+#define REG_TX_FAST_LOCK_PROGRAM_CTRL 0x29F /* Tx Fast Lock Program Ctrl */
+#define REG_TX_LO_GEN_POWER_MODE 0x2A1 /* Tx LO Gen Power Mode */
+#define REG_BANDGAP_CONFIG0 0x2A6 /* Bandgap Config0 */
+#define REG_BANDGAP_CONFIG1 0x2A8 /* Bandgap Config1 */
+#define REG_REF_DIVIDE_CONFIG_1 0x2AB /* Ref Divide Config 1 */
+#define REG_REF_DIVIDE_CONFIG_2 0x2AC /* Ref Divide Config 2 */
+#define REG_GAIN_RX1 0x2B0 /* Gain Rx1 */
+#define REG_LPF_GAIN_RX1 0x2B1 /* LPF Gain Rx1 */
+#define REG_DIG_GAIN_RX1 0x2B2 /* Dig gain Rx1 */
+#define REG_FAST_ATTACK_STATE 0x2B3 /* Fast Attack State */
+#define REG_SLOW_LOOP_STATE 0x2B4 /* Slow Loop State */
+#define REG_GAIN_RX2 0x2B5 /* Gain Rx2 */
+#define REG_LPF_GAIN_RX2 0x2B6 /* LPF Gain Rx2 */
+#define REG_DIG_GAIN_RX2 0x2B7 /* Dig Gain Rx2 */
+#define REG_OVRG_SIGS_RX1 0x2B8 /* Ovrg Sigs Rx1 */
+#define REG_OVRG_SIGS_RX2 0x2B9 /* Ovrg Sigs Rx2 */
+#define REG_CTRL 0x3DF /* Control */
+#define REG_BIST_CONFIG 0x3F4 /* BIST Config */
+#define REG_OBSERVE_CONFIG 0x3F5 /* Observe Config */
+#define REG_BIST_AND_DATA_PORT_TEST_CONFIG 0x3F6 /* BIST and Data Port Test Config */
+#define REG_DAC_TEST_0 0x3FC /* DAC Test 0 */
+#define REG_DAC_TEST_1 0x3FD /* DAC Test 1 */
+#define REG_DAC_TEST_2 0x3FE /* DAC Test 2 */
+
+/*
+* REG_SPI_CONF
+*/
+#define SOFT_RESET (1 << 7) /* Soft Reset */
+#define WIRE3_SPI (1 << 6) /* 3-Wire SPI */
+#define LSB_FIRST (1 << 5) /* LSB First */
+#define _LSB_FIRST (1 << 2) /* LSB First */
+#define _WIRE3_SPI (1 << 1) /* 3-Wire SPI */
+#define _SOFT_RESET (1 << 0) /* Soft reset */
+
+/*
+* REG_MULTICHIP_SYNC_AND_TX_MON_CTRL
+*/
+#define TX2_MONITOR_ENABLE (1 << 6) /* Tx2 Monitor Enable */
+#define TX1_MONITOR_ENABLE (1 << 5) /* Tx1 Monitor Enable */
+#define MCS_RF_ENABLE (1 << 3) /* MCS RF Enable */
+#define MCS_BBPLL_ENABLE (1 << 2) /* MCS BBPLL enable */
+#define MCS_DIGITAL_CLK_ENABLE (1 << 1) /* MCS Digital CLK Enable */
+#define MCS_BB_ENABLE (1 << 0) /* MCS BB Enable */
+
+/*
+* REG_TX_ENABLE_FILTER_CTRL
+*/
+#define THB2_EN (1 << 3) /* THB2 Enable */
+#define THB1_EN (1 << 2) /* THB1 Enable */
+#define TX_CHANNEL_ENABLE(x) (((x) & 0x3) << 6) /* Tx channel Enable<1:0> */
+#define THB3_ENABLE_INTERP(x) (((x) & 0x3) << 4) /* THB3 Enable & Interp<1:0> */
+#define TX_FIR_ENABLE_INTERPOLATION(x) (((x) & 0x3) << 0) /* Tx FIR Enable & Interpolation<1:0> */
+#define TX_1 1
+#define TX_2 2
+#define TX_ENABLE 1
+#define TX_DISABLE 0
+
+/*
+* REG_RX_ENABLE_FILTER_CTRL
+*/
+#define RHB2_EN (1 << 3) /* RHB2 Enable */
+#define RHB1_EN (1 << 2) /* RHB1 Enable */
+#define RX_CHANNEL_ENABLE(x) (((x) & 0x3) << 6) /* Rx channel Enable<1:0> */
+#define DEC3_ENABLE_DECIMATION(x) (((x) & 0x3) << 4) /* DEC3 Enable & Decimation<1:0> */
+#define RX_FIR_ENABLE_DECIMATION(x) (((x) & 0x3) << 0) /* Rx FIR Enable & Decimation<1:0> */
+#define RX_1 1
+#define RX_2 2
+#define RX_ENABLE 1
+#define RX_DISABLE 0
+
+/*
+* REG_INPUT_SELECT
+*/
+#define TX_OUTPUT (1 << 6) /* TX Output */
+#define RX_INPUT(x) (((x) & 0x3F) << 0) /* RX Input <5:0> */
+
+/*
+* REG_RFPLL_DIVIDERS
+*/
+#define TX_VCO_DIVIDER(x) (((x) & 0xF) << 4) /* TX VCO Divider<3:0> */
+#define RX_VCO_DIVIDER(x) (((x) & 0xF) << 0) /* RX VCO Divider<3:0> */
+
+/*
+* REG_RX_CLOCK_DATA_DELAY
+*/
+#define DATA_CLK_DELAY(x) (((x) & 0xF) << 4) /* DATA_CLK Delay<3:0> */
+#define RX_DATA_DELAY(x) (((x) & 0xF) << 0) /* Rx Data Delay <3:0> */
+
+/*
+* REG_TX_CLOCK_DATA_DELAY
+*/
+#define FB_CLK_DELAY(x) (((x) & 0xF) << 4) /* FB_CLK Delay<3:0> */
+#define TX_DATA_DELAY(x) (((x) & 0xF) << 0) /* Tx Data Delay <3:0> */
+
+/*
+* REG_CLOCK_ENABLE
+*/
+#define XO_BYPASS (1 << 4) /* XO Bypass */
+#define DIGITAL_POWER_UP (1 << 2) /* Digital Power Up */
+#define CLOCK_ENABLE_DFLT (1 << 1) /* Set to 1 */
+#define BBPLL_ENABLE (1 << 0) /* BBPLL Enable */
+
+/*
+* REG_BBPLL
+*/
+#define CLKOUT_ENABLE (1 << 4) /* CLKOUT Enable */
+#define DAC_CLK_DIV2 (1 << 3) /* DAC Clk div2 */
+#define CLKOUT_SELECT(x) (((x) & 0x7) << 5) /* CLKOUT Select<2:0> */
+#define BBPLL_DIVIDER(x) (((x) & 0x7) << 0) /* BBPLL Divider <2:0> */
+
+/*
+* REG_START_TEMP_READING
+*/
+#define START_TEMP_READING (1 << 0) /* Start Temp Reading */
+
+/*
+* REG_TEMP_SENSE2
+*/
+#define TEMP_SENSE_PERIODIC_ENABLE (1 << 0) /* Temp Sense Periodic Enable */
+#define MEASUREMENT_TIME_INTERVAL(x) (((x) & 0x7F) << 1) /* Measurement Time Interval<6:0> */
+
+/*
+* REG_TEMP_SENSOR_CONFIG
+*/
+#define TEMP_SENSOR_DECIMATION(x) (((x) & 0x7) << 0) /* Temp Sensor Decimation<2:0> */
+
+/*
+* REG_PARALLEL_PORT_CONF_1
+*/
+#define PP_TX_SWAP_IQ (1 << 7) /* PP Tx Swap IQ */
+#define PP_RX_SWAP_IQ (1 << 6) /* PP Rx Swap IQ */
+#define TX_CHANNEL_SWAP (1 << 5) /* Tx Channel swap */
+#define RX_CHANNEL_SWAP (1 << 4) /* Rx Channel swap */
+#define RX_FRAME_PULSE_MODE (1 << 3) /* Rx Frame Pulse Mode */
+#define R2T2_TIMING (1 << 2) /* 2R2T Timing */
+#define INVERT_DATA_BUS (1 << 1) /* Invert data bus */
+#define INVERT_DATA_CLK (1 << 0) /* Invert DATA CLK */
+
+/*
+* REG_PARALLEL_PORT_CONF_2
+*/
+#define FDD_ALT_WORD_ORDER (1 << 7) /* FDD Alt Word Order */
+#define INVERT_RX1 (1 << 6) /* Invert Rx1 */
+#define INVERT_RX2 (1 << 5) /* Invert Rx2 */
+#define INVERT_TX1 (1 << 4) /* Invert Tx1 */
+#define INVERT_TX2 (1 << 3) /* Invert Tx2 */
+#define INVERT_RX_FRAME (1 << 2) /* Invert Rx Frame */
+#define DELAY_RX_DATA(x) (((x) & 0x3) << 0) /* Delay Rx Data<1:0> */
+
+/*
+* REG_PARALLEL_PORT_CONF_3
+*/
+#define FDD_RX_RATE_2TX_RATE (1 << 7) /* FDD Rx Rate = 2*Tx Rate */
+#define SWAP_PORTS (1 << 6) /* Swap Ports */
+#define SINGLE_DATA_RATE (1 << 5) /* Single Data Rate */
+#define LVDS_MODE (1 << 4) /* LVDS Mode */
+#define HALF_DUPLEX_MODE (1 << 3) /* Half Duplex Mode */
+#define SINGLE_PORT_MODE (1 << 2) /* Single Port Mode */
+#define FULL_PORT (1 << 1) /* Full Port */
+#define FULL_DUPLEX_SWAP_BITS (1 << 0) /* Full Duplex Swap Bits */
+
+/*
+* REG_ENSM_MODE
+*/
+#define FDD_MODE (1 << 0) /* FDD Mode */
+
+/*
+* REG_ENSM_CONFIG_1
+*/
+#define ENABLE_RX_DATA_PORT_FOR_CAL (1 << 7) /* Enable Rx Data Port for Cal */
+#define FORCE_RX_ON (1 << 6) /* Force Rx On */
+#define FORCE_TX_ON (1 << 5) /* Force Tx On */
+#define ENABLE_ENSM_PIN_CTRL (1 << 4) /* Enable ENSM Pin Control */
+#define LEVEL_MODE (1 << 3) /* Level Mode */
+#define FORCE_ALERT_STATE (1 << 2) /* Force Alert State */
+#define AUTO_GAIN_LOCK (1 << 1) /* Auto Gain Lock */
+#define TO_ALERT (1 << 0) /* To Alert */
+
+/*
+* REG_ENSM_CONFIG_2
+*/
+#define FDD_EXTERNAL_CTRL_ENABLE (1 << 7) /* FDD External Control Enable */
+#define POWER_DOWN_RX_SYNTH (1 << 6) /* Power Down Rx Synth */
+#define POWER_DOWN_TX_SYNTH (1 << 5) /* Power Down Tx Synth */
+#define TXNRX_SPI_CTRL (1 << 4) /* TXNRX SPI Control */
+#define SYNTH_ENABLE_PIN_CTRL_MODE (1 << 3) /* Synth Enable Pin Control Mode */
+#define DUAL_SYNTH_MODE (1 << 2) /* Dual Synth Mode */
+#define RX_SYNTH_READY_MASK (1 << 1) /* Rx Synth Ready Mask */
+#define TX_SYNTH_READY_MASK (1 << 0) /* Tx Synth Ready Mask */
+
+/*
+* REG_CALIBRATION_CTRL
+*/
+#define RX_BB_TUNE_CAL (1 << 7) /* Rx BB Tune */
+#define TX_BB_TUNE_CAL (1 << 6) /* Tx BB Tune */
+#define RX_QUAD_CAL (1 << 5) /* Rx Quad Cal */
+#define TX_QUAD_CAL (1 << 4) /* Tx Quad Cal */
+#define RX_GAIN_STEP_CAL (1 << 3) /* Rx Gain Step Cal */
+#define TXMON_CAL (1 << 2)
+#define RFDC_CAL (1 << 1) /* DC Cal RF Start */
+#define BBDC_CAL (1 << 0) /* DC cal BB Start */
+
+
+/*
+* REG_STATE
+*/
+#define CALIBRATION_SEQUENCE_STATE(x) (((x) & 0xF) << 4) /* Calibration Sequence State<3:0> */
+#define ENSM_STATE(x) (((x) & 0xF) << 0) /* ENSM State<3:0> */
+#define ENSM_STATE_SLEEP_WAIT 0x0
+#define ENSM_STATE_ALERT 0x5
+#define ENSM_STATE_TX 0x6
+#define ENSM_STATE_TX_FLUSH 0x7
+#define ENSM_STATE_RX 0x8
+#define ENSM_STATE_RX_FLUSH 0x9
+#define ENSM_STATE_FDD 0xA
+#define ENSM_STATE_FDD_FLUSH 0xB
+#define ENSM_STATE_INVALID 0xFF
+#define ENSM_STATE_SLEEP 0x80
+
+/*
+* REG_AUXDAC_2_WORD
+*/
+#define AUXDAC_2_WORD_MSB(x) (((x) & 0x3F) << 2) /* AuxDAC 2 Word<9:2> */
+#define AUXDAC_1_WORD(x) (((x) & 0x3) << 0) /* AuxDAC 1 Word <1:0> */
+
+/*
+* REG_AUXDAC_1_CONFIG
+*/
+#define COMP_CTRL_1 (1 << 5) /* Comp Ctrl 1 */
+#define AUXDAC1_STP_FACTOR (1 << 4) /* AuxDAC1 Step Factor */
+#define AUXDAC_1_VREF(x) (((x) & 0x3) << 2) /* AuxDAC 1 Vref<1:0> */
+#define AUXDAC_1_WORD_LSB(x) (((x) & 0x3) << 0) /* AuxDAC 2 Word <1:0> */
+
+/*
+* REG_AUXDAC_2_CONFIG
+*/
+#define COMP_CTRL_2 (1 << 5) /* Comp Ctrl 2 */
+#define AUXDAC2_STP_FACTOR (1 << 4) /* AuxDAC2 Step Factor */
+#define AUXDAC_2_VREF(x) (((x) & 0xF) << 2) /* AuxDAC 2 Vref<1:0> */
+#define AUXDAC_2_WORD_LSB(x) (((x) & 0x3) << 0) /* AuxDAC 2 Word <1:0> */
+
+/*
+* REG_AUXADC_CLOCK_DIVIDER
+*/
+#define AUXADC_CLOCK_DIVIDER(x) (((x) & 0x3F) << 0) /* AuxADC Clock Divider<5:0> */
+
+/*
+* REG_AUXADC_CONFIG
+*/
+#define AUXADC_POWER_DOWN (1 << 0) /* AuxADC Power Down */
+#define AUX_ADC_DECIMATION(x) (((x) & 0x7) << 1) /* Aux ADC Decimation<2:0> */
+
+/*
+* REG_AUXADC_LSB
+*/
+#define AUXADC_WORD_LSB(x) (((x) & 0xF) << 0) /* AuxADC Word LSB<3:0> */
+
+/*
+* REG_AUTO_GPO
+*/
+#define GPO_ENABLE_AUTO_RX(x) (((x) & 0xF) << 4) /* GPO Enable Auto Rx<3:0> */
+#define GPO_ENABLE_AUTO_TX(x) (((x) & 0xF) << 0) /* GPO Enable Auto Tx<3:0> */
+
+/*
+* REG_AGC_ATTACK_DELAY
+*/
+#define INVERT_BYPASSED_LNA_POLARITY (1 << 6) /* Invert Bypassed LNA Polarity */
+#define AGC_ATTACK_DELAY(x) (((x) & 0x3F) << 0) /* AGC Attack Delay<5:0> */
+
+/*
+* REG_AUXDAC_ENABLE_CTRL
+*/
+#define AUXDAC_MANUAL_BAR(x) (((x) & 0x3) << 6) /* AuxDac Manual Bar<1:0> */
+#define AUXDAC_AUTO_TX_BAR(x) (((x) & 0x3) << 4) /* AuxDAC Auto Tx Bar<1:0> */
+#define AUXDAC_AUTO_RX_BAR(x) (((x) & 0x3) << 2) /* AuxDAC Auto Rx Bar<1:0> */
+#define AUXDAC_INIT_BAR(x) (((x) & 0x3) << 0) /* AuxDAC Init Bar<1:0> */
+
+/*
+* REG_EXTERNAL_LNA_CTRL
+*/
+#define AUXDAC_MANUAL_SELECT (1 << 7) /* AuxDAC Manual Select */
+#define EXTERNAL_LNA2_CTRL (1 << 6) /* External LNA2 control */
+#define EXTERNAL_LNA1_CTRL (1 << 5) /* External LNA1 control */
+#define GPO_MANUAL_SELECT (1 << 4) /* GPO manual select */
+#define OPEN(x) (((x) & 0xF) << 0) /* Open<3:0> */
+
+/*
+* REG_GPO_FORCE_AND_INIT
+*/
+#define GPO_MANUAL_CTRL(x) (((x) & 0xF) << 4) /* GPO Manual Control<3:0> */
+#define GPO_INIT_STATE(x) (((x) & 0xF) << 0) /* GPO Init State<3:0> */
+
+/*
+* REG_CTRL_OUTPUT_ENABLE
+*/
+#define EN_CTRL7 (1 << 7) /* En ctrl7 */
+#define EN_CTRL6 (1 << 6) /* En ctrl6 */
+#define EN_CTRL5 (1 << 5) /* En ctrl5 */
+#define EN_CTRL4 (1 << 4) /* En ctrl4 */
+#define EN_CTRL3 (1 << 3) /* En ctrl3 */
+#define EN_CTRL2 (1 << 2) /* En ctrl2 */
+#define EN_CTRL1 (1 << 1) /* En ctrl1 */
+#define EN_CTRL0 (1 << 0) /* En ctrl0 */
+
+/*
+* REG_PRODUCT_ID
+*/
+#define PRODUCT_ID_MASK 0xF8
+#define PRODUCT_ID_9361 0x08
+#define REV_MASK 0x07
+
+/*
+* REG_REFERENCE_CLOCK_CYCLES
+*/
+#define REFERENCE_CLOCK_CYCLES_PER_US(x) (((x) & 0x7F) << 0) /* Reference Clock Cycles per us<6:0> */
+
+/*
+* REG_DIGITAL_IO_CTRL
+*/
+#define CLK_OUT_DRIVE (1 << 7) /* CLK Out Drive */
+#define DATACLK_DRIVE (1 << 6) /* DATACLK drive */
+#define DATA_PORT_DRIVE (1 << 2) /* Data Port Drive */
+#define DATACLK_SLEW(x) (((x) & 0x3) << 4) /* DATACLK slew <1:0> */
+#define DATA_PORT_SLEW(x) (((x) & 0x3) << 0) /* Data Port Slew<1:0> */
+
+/*
+* REG_LVDS_BIAS_CTRL
+*/
+#define RX_ON_CHIP_TERM (1 << 5) /* Rx On Chip Term */
+#define LVDS_BYPASS_BIAS_R (1 << 4) /* Bypass Bias R */
+#define LVDS_TX_LO_VCM (1 << 3) /* LVDS Tx LO VCM */
+#define CLK_OUT_SLEW(x) (((x) & 0x3) << 6) /* CLK Out Slew<1:0> */
+#define LVDS_BIAS(x) (((x) & 0x7) << 0) /* LVDS Bias <2:0> */
+
+/*
+* REG_SDM_CTRL_1
+*/
+#define INIT_BB_FO_CAL (1 << 2) /* Init BB FO CAL */
+#define BBPLL_RESET_BAR (1 << 0) /* BBPLL Reset Bar */
+
+/*
+* REG_CLOCK_CTRL
+*/
+#define REF_FREQ_SCALER(x) (((x) & 0x3) << 0) /* Ref Frequency Scaler */
+
+/*
+* REG_CP_CURRENT
+*/
+#define CHARGE_PUMP_CURRENT(x) (((x) & 0x3F) << 0) /* Charge Pump Current<5:0> */
+
+/*
+* REG_CP_BLEED_CURRENT
+*/
+#define MCS_REFCLK_SCALE_EN (1 << 7) /* MCS refclk Scale En */
+
+/*
+* REG_LOOP_FILTER_1
+*/
+#define C1_WORD(x) (((x) & 0x7) << 5) /* C1 Word<2:0> */
+#define R1_WORD(x) (((x) & 0x1F) << 0) /* R1 Word<4:0> */
+
+/*
+* REG_LOOP_FILTER_2
+*/
+#define R2_WORD (1 << 7) /* R2 Word<0> */
+#define C2_WORD(x) (((x) & 0x1F) << 2) /* C2 Word<4:0> */
+#define C1_WORD_LSB(x) (((x) & 0x3) << 0) /* C1 Word<4:3> */
+
+/*
+* REG_LOOP_FILTER_3
+*/
+#define BYPASS_C3 (1 << 7) /* Bypass C3 */
+#define BYPASS_R2 (1 << 6) /* Bypass R2 */
+#define C3_WORD(x) (((x) & 0xF) << 2) /* C3 Word<3:0> */
+#define R2_WORD_LSB(x) (((x) & 0x3) << 0) /* R2 Word<2:1> */
+
+/*
+* REG_VCO_CTRL
+*/
+#define FREQ_CAL_ENABLE (1 << 7) /* Freq Cal Enable */
+#define FREQ_CAL_RESET (1 << 4) /* Freq Cal Reset */
+#define FREQ_CAL_COUNT_LENGTH(x) (((x) & 0x3) << 5) /* Freq Cal Count Length<1:0> */
+
+/*
+* REG_SDM_CTRL
+*/
+#define CAL_CLOCK_DIV_4 (1 << 4) /* Cal Clock div 4 */
+
+/*
+* REG_RX_SYNTH_POWER_DOWN_OVERRIDE
+*/
+#define RX_LO_POWER_DOWN (1 << 4) /* Rx LO Power Down */
+#define RX_SYNTH_VCO_ALC_POWER_DOWN (1 << 3) /* Rx Synth VCO ALC Power Down */
+#define RX_SYNTH_PTAT_POWER_DOWN (1 << 2) /* Rx Synth PTAT Power Down */
+#define RX_SYNTH_VCO_POWER_DOWN (1 << 1) /* Rx Synth VCO Power Down */
+#define RX_SYNTH_VCO_LDO_POWER_DOWN (1 << 0) /* Rx Synth VCO LDO Power Down */
+
+/*
+* REG_TX_SYNTH_POWER_DOWN_OVERRIDE
+*/
+#define TX_LO_POWER_DOWN (1 << 4) /* Tx LO Power Down */
+#define TX_SYNTH_VCO_ALC_POWER_DOWN (1 << 3) /* Tx Synth VCO ALC Power Down */
+#define TX_SYNTH_PTAT_POWER_DOWN (1 << 2) /* Tx Synth PTAT Power Down */
+#define TX_SYNTH_VCO_POWER_DOWN (1 << 1) /* Tx Synth VCO Power Down */
+#define TX_SYNTH_VCO_LDO_POWER_DOWN (1 << 0) /* Tx Synth VCO LDO Power Down */
+
+/*
+* REG_RX_ANALOG_POWER_DOWN_OVERRIDE_1
+*/
+#define RX_OFFSET_DAC_CGIN_POWER_DOWN(x) (((x) & 0x3) << 6) /* Rx Offset DAC CGin Power Down<1:0> */
+#define RX_LMT_OVERLOAD_POWER_DOWN(x) (((x) & 0x3) << 4) /* Rx LMT Overload Power Down<1:0> */
+#define RX_MIXER_GM_POWER_DOWN(x) (((x) & 0x3) << 2) /* Rx Mixer Gm Power Down<1:0> */
+#define RX_CGB_POWER_DOWN(x) (((x) & 0x3) << 0) /* Rx CGB Power Down<1:0> */
+
+/*
+* REG_RX_ANALOG_POWER_DOWN_OVERRIDE_2
+*/
+#define RX_BBF_POWER_DOWN(x) (((x) & 0x3) << 6) /* Rx BBF Power Down<1:0> */
+#define RX_TIA_POWER_DOWN(x) (((x) & 0x3) << 4) /* Rx TIA Power Down<1:0> */
+#define RX_MIXER_POWER_DOWN(x) (((x) & 0x3) << 2) /* Rx Mixer Power Down<1:0> */
+#define RX_OFFSET_DAC_CGOUT_POWER_DOWN(x) (((x) & 0x3) << 0) /* Rx Offset DAC CGOut Power Down<1:0> */
+
+/*
+* REG_TX_ANALOG_POWER_DOWN_OVERRIDE_1
+*/
+#define TX_SECONDARY_FILTER_POWER_DOWN(x) (((x) & 0x3) << 6) /* Tx Secondary Filter Power Down<1:0> */
+#define TX_BBF_POWER_DOWN(x) (((x) & 0x3) << 4) /* Tx BBF Power Down<1:0> */
+#define TX_DAC_POWER_DOWN(x) (((x) & 0x3) << 2) /* Tx DAC Power Down<1:0> */
+#define TX_DAC_BIAS_POWER_DOWN(x) (((x) & 0x3) << 0) /* Tx DAC Bias Power Down<1:0> */
+
+/*
+* REG_ANALOG_POWER_DOWN_OVERRIDE
+*/
+#define RX_EXT_VCO_BUFFER_POWER_DOWN (1 << 5) /* Rx Ext VCO Buffer Power Down */
+#define TX_EXT_VCO_BUFFER_POWER_DOWN (1 << 4) /* Tx Ext VCO Buffer Power Down */
+#define TX_MONITOR_POWER_DOWN(x) (((x) & 0x3) << 2) /* Tx Monitor Power Down<1:0> */
+#define TX_UPCONVERTER_POWER_DOWN(x) (((x) & 0x3) << 0) /* Tx Upconverter Power Down<1:0> */
+
+/*
+* REG_MISC_POWER_DOWN_OVERRIDE
+*/
+#define RX_LNA_POWER_DOWN (1 << 6) /* Rx LNA Power Down */
+#define DCXO_POWER_DOWN (1 << 1) /* DCXO Power Down */
+#define MASTER_BIAS_POWER_DOWN (1 << 0) /* Master Bias Power Down */
+#define RX_CALIBRATION_POWER_DOWN(x) (((x) & 0x3) << 2) /* Rx Calibration Power Down<1:0> */
+
+/*
+* REG_CH_1_OVERFLOW
+*/
+#define BBPLL_LOCK (1 << 7) /* BBPLL Lock */
+#define CH_1_INT3 (1 << 6) /* CH 1 INT3 */
+#define CH1_HB3 (1 << 5) /* CH1 HB3 */
+#define CH1_HB2 (1 << 4) /* CH1 HB2 */
+#define CH1_QEC (1 << 3) /* CH1 QEC */
+#define CH1_HB1 (1 << 2) /* CH1 HB1 */
+#define CH1_TFIR (1 << 1) /* CH1 TFIR */
+#define CH1_RFIR (1 << 0) /* CH1 RFIR */
+
+/*
+* REG_CH_2_OVERFLOW
+*/
+#define CH2_INT3 (1 << 6) /* CH2 INT3 */
+#define CH2_HB3 (1 << 5) /* CH2 HB3 */
+#define CH2_HB2 (1 << 4) /* CH2 HB2 */
+#define CH2_QEC (1 << 3) /* CH2 QEC */
+#define CH2_HB1 (1 << 2) /* CH2 HB1 */
+#define CH2_TFIR (1 << 1) /* CH2 TFIR */
+#define CH2_RFIR (1 << 0) /* CH2 RFIR */
+
+/*
+* REG_TX_FILTER_CONF
+*/
+#define TX_FIR_GAIN_6DB (1 << 0) /* Filter Gain */
+#define FIR_START_CLK (1 << 1) /* Start Tx/Rx Clock */
+#define FIR_WRITE (1 << 2) /* Write Tx/Rx */
+#define FIR_SELECT(x) (((x) & 0x3) << 3) /* Select Tx/Rx CH<1:0> */
+#define FIR_NUM_TAPS(x) (((x) & 0x7) << 5) /* Number of Taps<2:0> */
+
+/*
+* REG_TX_MON_LOW_GAIN
+*/
+#define TX_MON_TRACK (1 << 5) /* Tx Mon Track */
+#define TX_MON_LOW_GAIN(x) (((x) & 0x1F) << 0) /* Tx Mon Low Gain<4:0> */
+
+/*
+* REG_TX_MON_HIGH_GAIN
+*/
+#define TX_MON_HIGH_GAIN(x) (((x) & 0x1F) << 0) /* Tx Mon High Gain<4:0> */
+
+/*
+* REG_TX_LEVEL_THRESH
+*/
+#define TX_LEVEL_THRESH(x) (((x) & 0x3F) << 2) /* Tx Level Threshold<5:0> */
+#define TX_MON_DELAY_COUNTER(x) (((x) & 0x3) << 0) /* Tx Mon Delay Counter<9:8> */
+
+/*
+* REG_TX_RSSI_LSB
+*/
+#define TX_RSSI_2 (1 << 1) /* Tx RSSI 2<0> */
+#define TX_RSSI_1 (1 << 0) /* TX RSSI 1<0> */
+
+/*
+* REG_TPM_MODE_ENABLE
+*/
+#define TX2_MON_ENABLE (1 << 7) /* Tx2 Monitor Enable */
+#define TX1_MON_ENABLE (1 << 5) /* Tx1 Monitor Enable */
+#define ONE_SHOT_MODE (1 << 6) /* One Shot Mode */
+#define TX_MON_DURATION(x) (((x) & 0xF) << 0) /* Tx Mon Duration<3:0> */
+
+/*
+* REG_TX_MON_1_CONFIG
+*/
+#define TX_MON_1_LO_CM(x) (((x) & 0x3F) << 2) /* Tx Mon 1 LO CM<5:0> */
+#define TX_MON_1_GAIN(x) (((x) & 0x3) << 0) /* Tx Mon 1 Gain<1:0> */
+
+/*
+* REG_TX_MON_2_CONFIG
+*/
+#define TX_MON_2_LO_CM(x) (((x) & 0x3F) << 2) /* Tx Mon 2 LO CM<5:0> */
+#define TX_MON_2_GAIN(x) (((x) & 0x3) << 0) /* Tx Mon 2 Gain<1:0> */
+
+/*
+* REG_TX1_ATTEN_1
+*/
+#define TX_1_ATTEN (1 << 0) /* Tx 1 Atten <8> */
+
+/*
+* REG_TX2_ATTEN_1
+*/
+#define TX_2_ATTEN (1 << 0) /* Tx 2 Atten <8> */
+
+/*
+* REG_TX_ATTEN_OFFSET
+*/
+#define MASK_CLR_ATTEN_UPDATE (1 << 6) /* Mask Clr Atten Update */
+#define TX_ATTEN_OFFSET(x) (((x) & 0x3F) << 0) /* Tx Atten Offset<5:0> */
+
+/*
+* REG_TX1_DIG_ATTEN
+*/
+#define SEL_TX1_TX2 (1 << 6) /* Sel Tx1 & Ttx2 */
+
+/*
+* REG_TX2_DIG_ATTEN
+*/
+#define IMMEDIATELY_UPDATE_TPC_ATTEN (1 << 6) /* Immediately Update TPC Atten */
+
+/*
+* REG_TX1_SYMBOL_ATTEN
+*/
+#define TX_1_SYMBOL_ATTEN(x) (((x) & 0x7F) << 0) /* Tx 1 Symbol Attenuation<6:0> */
+
+/*
+* REG_TX2_SYMBOL_ATTEN
+*/
+#define TX_2_SYMBOL_ATTEN(x) (((x) & 0x7F) << 0) /* Tx 2 Symbol Attenuation<6:0> */
+
+/*
+* REG_TX_SYMBOL_ATTEN_CONFIG
+*/
+#define USE_TX1_PIN_SYMBOL_ATTEN (1 << 3) /* Use Tx1 Pin & Symbol Atten */
+#define USE_CTRL_IN_FOR_SYMBOL_ATTEN (1 << 1) /* Use CTRL IN for symbol Atten */
+#define ENABLE_SYMBOL_ATTEN (1 << 0) /* Enable Symbol Atten */
+
+/*
+* REG_TX_FORCE_BITS
+*/
+#define FORCE_OUT_2_TX2_OFFSET (1 << 7) /* Force Out 2 Tx2 Offset */
+#define FORCE_OUT_2_TX1_OFFSET (1 << 6) /* Force Out 2 Tx1 Offset */
+#define FORCE_OUT_2_TX2_PHASE_GAIN (1 << 5) /* Force Out 2 Tx2 Phase & Gain */
+#define FORCE_OUT_2_TX1_PHASE_GAIN (1 << 4) /* Force Out 2 Tx1 Phase & Gain */
+#define FORCE_OUT_1_TX2_OFFSET (1 << 3) /* Force Out 1 Tx2 Offset */
+#define FORCE_OUT_1_TX1_OFFSET (1 << 2) /* Force Out 1 Tx1 Offset */
+#define FORCE_OUT_1_TX2_PHASE_GAIN (1 << 1) /* Force Out 1 Tx2 Phase & Gain */
+#define FORCE_OUT_1_TX1_PHASE_GAIN (1 << 0) /* Force Out 1 Tx1 Phase & Gain */
+
+/*
+* REG_QUAD_CAL_NCO_FREQ_PHASE_OFFSET
+*/
+#define RX_NCO_FREQ(x) (((x) & 0x3) << 5) /* Rx NCO Frequency<1:0> */
+#define RX_NCO_PHASE_OFFSET(x) (((x) & 0x1F) << 0) /* Rx NCO Phase Offset<4:0> */
+
+/*
+* REG_QUAD_CAL_CTRL
+*/
+#define FREE_RUN_ENABLE (1 << 7) /* Free Run Enable */
+#define SETTLE_MAIN_ENABLE (1 << 6) /* Settle Main Enable */
+#define DC_OFFSET_ENABLE (1 << 5) /* DC Offset Enable */
+#define GAIN_ENABLE (1 << 4) /* Gain Enable */
+#define PHASE_ENABLE (1 << 3) /* Phase Enable */
+#define QUAD_CAL_SOFT_RESET (1 << 2) /* Quad Cal Soft Reset */
+#define M_DECIM(x) (((x) & 0x3) << 0) /* M<1:0> */
+
+/*
+* REG_KEXP_1
+*/
+#define KEXP_TX(x) (((x) & 0x3) << 6) /* Kexp Tx<1:0> */
+#define KEXP_TX_COMP(x) (((x) & 0x3) << 4) /* Kexp Tx_comp <1:0> */
+#define KEXP_DC_I(x) (((x) & 0x3) << 2) /* Kexp DC I <1:0> */
+#define KEXP_DC_Q(x) (((x) & 0x3) << 0) /* Kexp DC Q <1:0> */
+
+/*
+* REG_KEXP_2
+*/
+#define INVERT_I_DATA (1 << 5) /* Invert I data */
+#define INVERT_Q_DATA (1 << 4) /* Invert Q data */
+#define TX_NCO_FREQ(x) (((x) & 0x3) << 6) /* Tx NCO frequency<1:0> */
+#define KEXP_PHASE(x) (((x) & 0x3) << 2) /* Kexp Phase <1:0> */
+#define KEXP_AMP(x) (((x) & 0x3) << 0) /* Kexp Amp <1:0> */
+
+/*
+* REG_QUAD_CAL_STATUS_TX1
+*/
+#define TX1_LO_CONV (1 << 1) /* Tx1 LO Conv */
+#define TX1_SSB_CONV (1 << 0) /* Tx1 SSB Conv */
+#define TX1_CONVERGENCE_COUNT(x) (((x) & 0x3F) << 2) /* Tx1 Convergence Count<5:0> */
+
+/*
+* REG_QUAD_CAL_STATUS_TX2
+*/
+#define TX2_LO_CONV (1 << 1) /* Tx2 LO Conv */
+#define TX2_SSB_CONV (1 << 0) /* Tx2 SSB Conv */
+#define TX2_CONVERGENCE_COUNT(x) (((x) & 0x3F) << 2) /* Tx2 Convergence Count<5:0> */
+
+/*
+* REG_TX_QUAD_FULL_LMT_GAIN
+*/
+#define RX_FULL_TABLELMT_TABLE_GAIN(x) (((x) & 0x7F) << 0) /* RX Full table/LMT table gain<6:0> */
+
+/*
+* REG_SQUARER_CONFIG
+*/
+#define GM_STAGE_TIME_CON_OVERRIDE (1 << 5) /* Gm Stage Time Con Override */
+#define GM_STAGE_MV_HP_POLE (1 << 4) /* Gm Stage MV HP Pole */
+#define GM_STAGE_LOWER_CM (1 << 3) /* Gm Stage Lower CM */
+#define BYPASS_BIAS_R (1 << 0) /* Bypass Bias R */
+#define VBIAS_CTRL(x) (((x) & 0x3) << 1) /* Vbias Control<1:0> */
+
+/*
+* REG_THRESH_ACCUM
+*/
+#define THRESH_ACCUMULATOR(x) (((x) & 0xF) << 0) /* Threshold Accumulator<3:0> */
+
+/*
+* REG_TX_QUAD_LPF_GAIN
+*/
+#define RX_LPF_GAIN(x) (((x) & 0x1F) << 0) /* RX LPF gain<4:0> */
+
+/*
+* REG_TXDAC_VDS_I
+*/
+#define TXDAC_VDS_I(x) (((x) & 0x3F) << 0) /* TxDAC Vds I<5:0> */
+
+/*
+* REG_TXDAC_VDS_Q
+*/
+#define TXDAC_VDS_Q(x) (((x) & 0x3F) << 0) /* TxDAC Vds Q<5:0> */
+
+/*
+* REG_TXDAC_GN_I
+*/
+#define TXDAC_GN_I(x) (((x) & 0x3F) << 0) /* txDAC_gn_I<5:0> */
+
+/*
+* REG_TXDAC_GN_Q
+*/
+#define TXDAC_GN_Q(x) (((x) & 0x3F) << 0) /* txDAC_gn_Q<5:0> */
+
+/*
+* REG_TXBBF_OPAMP_A
+*/
+#define OPAMPA_OUTPUT_BIAS(x) (((x) & 0x3) << 5) /* OpAmpA Output Bias<1:0> */
+#define OPAMPA_RZ(x) (((x) & 0x3) << 3) /* OpAmpA RZ<1:0> */
+#define OPAMP_A_CC(x) (((x) & 0x7) << 0) /* OpAmp A CC<2:0> */
+
+/*
+* REG_TXBBF_OPAMP_B
+*/
+#define OPAMPB_OUTPUT_BIAS(x) (((x) & 0x3) << 5) /* OpAmpB Output Bias<1:0> */
+#define OPAMPB_RZ(x) (((x) & 0x3) << 3) /* OpAmpB RZ<1:0> */
+#define OPAMP_B_CC(x) (((x) & 0x7) << 0) /* OpAmp B CC<2:0> */
+
+/*
+* REG_TX_BBF_R1
+*/
+#define OVERRIDE_ENABLE (1 << 7) /* Override enable */
+#define R1(x) (((x) & 0x1F) << 0) /* R1<4:0> */
+
+/*
+* REG_TX_BBF_R2
+*/
+#define R2(x) (((x) & 0x1F) << 0) /* R2<4:0> */
+
+/*
+* REG_TX_BBF_R3
+*/
+#define R3(x) (((x) & 0x1F) << 0) /* R3<4:0> */
+
+/*
+* REG_TX_BBF_R4
+*/
+#define R4(x) (((x) & 0x1F) << 0) /* R4<4:0> */
+
+/*
+* REG_TX_BBF_RP
+*/
+#define RP(x) (((x) & 0x1F) << 0) /* Rp<4:0> */
+
+/*
+* REG_TX_BBF_C1
+*/
+#define C1(x) (((x) & 0x3F) << 0) /* C1<5:0> */
+
+/*
+* REG_TX_BBF_C2
+*/
+#define C2(x) (((x) & 0x3F) << 0) /* C2<5:0> */
+
+/*
+* REG_TX_BBF_CP
+*/
+#define CP(x) (((x) & 0x3F) << 0) /* Cp<5:0> */
+
+/*
+* REG_TX_TUNE_CTRL
+*/
+#define PD_TUNE (1 << 2) /* PD Tune */
+#define TUNER_RESAMPLE (1 << 1) /* Tuner Resample */
+#define TUNER_RESAMPLE_PHASE (1 << 0) /* Tuner Resample Phase */
+#define TUNE_CTRL(x) (((x) & 0x3) << 5) /* Tune Control<1:0> */
+
+/*
+* REG_TX_BBF_R2B
+*/
+#define TX_BBF_BYPASS_BIAS_R (1 << 7) /* Bypass Bias R */
+#define R2B_OVR (1 << 5) /* R2b Ovr */
+#define R2B(x) (((x) & 0x1F) << 0) /* R2b<4:0> */
+
+/*
+* REG_TX_BBF_TUNE
+*/
+#define BBF1_COMP_I (1 << 3) /* BBF1 Comp I */
+#define BBF1_COMP_Q (1 << 2) /* BBF1 Comp Q */
+#define BBF2_COMP_I (1 << 1) /* BBF2 Comp I */
+#define BBF2_COMP_Q (1 << 0) /* BBF2 Comp Q */
+
+/*
+* REG_CONFIG0
+*/
+#define BIAS(x) (((x) & 0x3) << 6) /* Bias<1:0> */
+#define RGM(x) (((x) & 0x3) << 4) /* Rgm<1:0> */
+#define CC(x) (((x) & 0x3) << 2) /* Cc<1:0> */
+#define AMPBIAS(x) (((x) & 0x3) << 0) /* AmpBias<1:0> */
+
+/*
+* REG_RESISTOR
+*/
+#define RESISTOR(x) (((x) & 0xF) << 0) /* Resistor<3:0> */
+
+/*
+* REG_CAPACITOR
+*/
+#define CAPACITOR(x) (((x) & 0x3F) << 0) /* Capacitor<5:0> */
+
+/*
+* REG_LO_CM
+*/
+#define LO_COMMON_MODE(x) (((x) & 0x3) << 5) /* LO Common Mode<1:0> */
+
+/*
+* REG_TX_BBF_TUNE_MODE
+*/
+#define EVALTIME (1 << 4) /* EvalTime */
+#define TX_BBF_TUNE_DIVIDER (1 << 0) /* TX BBF Tune Divider<8> */
+#define TUNE_COMP_MASK(x) (((x) & 0x3) << 5) /* Tune Comp Mask<1:0> */
+#define TUNER_MODE(x) (((x) & 0x7) << 1) /* Tuner Mode<2:0> */
+
+/*
+* REG_RX_FILTER_CONFIG
+*/
+#define WRITE_RX (1 << 2) /* Write Rx */
+#define START_RX_CLOCK (1 << 1) /* Start Rx Clock */
+#define NUMBER_OF_TAPS(x) (((x) & 0x7) << 5) /* Number of Taps */
+#define SELECT_RX_CH(x) (((x) & 0x3) << 3) /* Select Rx Ch<1:0> */
+
+/*
+* REG_RX_FILTER_GAIN
+*/
+#define FILTER_GAIN(x) (((x) & 0x3) << 0) /* Filter gain<1:0> */
+
+/*
+* REG_AGC_CONFIG_1
+*/
+#define DEC_PWR_FOR_LOW_PWR (1 << 7) /* Dec Pwr for Low Pwr */
+#define DEC_PWR_FOR_LOCK_LEVEL (1 << 6) /* Dec Pwr for Lock Level */
+#define DEC_PWR_FOR_GAIN_LOCK_EXIT (1 << 5) /* Dec Pwr for Gain Lock Exit */
+#define SLOW_ATTACK_HYBRID_MODE (1 << 4) /* Slow Attack Hybrid Mode */
+#define RX2_GAIN_CTRL_SETUP(x) (((x) & 0x3) << 2) /* Rx 2 Gain Control Setup<1:0> */
+#define RX1_GAIN_CTRL_SETUP(x) (((x) & 0x3) << 0) /* Rx 1 Gain Control Setup<1:0> */
+#define RX_GAIN_CTL_MASK 0x03
+#define RX2_GAIN_CTRL_SHIFT 2
+#define RX1_GAIN_CTRL_SHIFT 0
+#define RX_GAIN_CTL_MGC 0x00
+#define RX_GAIN_CTL_AGC_FAST_ATK 0x01
+#define RX_GAIN_CTL_AGC_SLOW_ATK 0x02
+#define RX_GAIN_CTL_AGC_SLOW_ATK_HYBD 0x03
+
+/*
+* REG_AGC_CONFIG_2
+*/
+#define AGC_SOFT_RESET (1 << 7) /* Soft Reset */
+#define AGC_GAIN_UNLOCK_CTRL (1 << 6) /* Gain Unlock Control */
+#define AGC_USE_FULL_GAIN_TABLE (1 << 3) /* Use Full Gain Table */
+#define DIG_GAIN_EN (1 << 2) /* Enable Digital Gain */
+#define MAN_GAIN_CTRL_RX2 (1 << 1) /* Manual Gain Control Rx 2 */
+#define MAN_GAIN_CTRL_RX1 (1 << 0) /* Manual Gain Control Rx 1 */
+
+/*
+* REG_AGC_CONFIG_3
+*/
+#define INCDEC_LMT_GAIN (1 << 4) /* Inc/Dec LMT Gain */
+#define USE_AGC_FOR_LMTLPF_GAIN (1 << 3) /* Use AGC for LMT/LPF Gain */
+#define MANUAL_INCR_STEP_SIZE(x) (((x) & 0x7) << 5) /* Manual (CTRL_IN) Incr Gain Step Size<2:0> */
+#define ADC_OVERRANGE_SAMPLE_SIZE(x) (((x) & 0x7) << 0) /* ADC Overrange Sample Size<2:0> */
+
+/*
+* REG_MAX_LMT_FULL_GAIN
+*/
+#define MAXIMUM_FULL_TABLELMT_TABLE_INDEX(x) (((x) & 0x7F) << 0) /* Maximum Full Table/LMT Table Index<6:0> */
+
+/*
+* REG_PEAK_WAIT_TIME
+*/
+#define MANUAL_CTRL_IN_DECR_GAIN_STP_SIZE(x) (((x) & 0x7) << 5) /* Manual (CTRL_IN) Decr Gain Step Size<2:0> */
+#define PEAK_OVERLOAD_WAIT_TIME(x) (((x) & 0x1F) << 0) /* Peak Overload Wait Time<4:0> */
+
+/*
+* REG_DIGITAL_GAIN
+*/
+#define DIG_GAIN_STP_SIZE(x) (((x) & 0x7) << 5) /* Dig Gain Step Size<2:0> */
+#define MAXIMUM_DIGITAL_GAIN(x) (((x) & 0x1F) << 0) /* Maximum Digital Gain<4:0> */
+
+/*
+* REG_AGC_LOCK_LEVEL
+*/
+#define ENABLE_DIG_SAT_OVRG (1 << 7) /* Enable Dig Sat Ovrg */
+#define AGC_LOCK_LEVEL_FAST_AGC_INNER_HIGH_THRESH_SLOW(x) (((x) & 0x7F) << 0) /* AGC Lock Level (Fast)/ AGC Inner High Threshold (Slow) <6:0> */
+
+/*
+* REG_GAIN_STP_CONFIG1
+*/
+#define LMT_DETECTOR_SETTLING_TIME(x) (((x) & 0x7) << 5) /* LMT Detector Settling Time<2:0> */
+#define DEC_STP_SIZE_FOR_LARGE_LMT_OVERLOAD(x) (((x) & 0x7) << 2) /* Dec Step Size for: Large LMT Overload/ Full Table Case #3 <2:0> */
+#define ADC_NOISE_CORRECTION_FACTOR(x) (((x) & 0x3) << 0) /* ADC Noise Correction Factor<1:0> */
+
+/*
+* REG_GAIN_STP_CONFIG_2
+*/
+#define DECREMENT_STP_SIZE_FOR_SMALL_LPF_GAIN_CHANGE(x) (((x) & 0x7) << 4) /* Fast Attack Only. Decrement Step Size for: Small LPF Gain Change / Full Table Case #2 <2:0> */
+#define LARGE_LPF_GAIN_STEP(x) (((x) & 0xF) << 0) /* Decrement Step Size for: Large LPF Gain Change / Full Table Case #1<3:0> */
+
+/*
+* REG_SMALL_LMT_OVERLOAD_THRESH
+*/
+#define FORCE_PD_RESET_RX2 (1 << 7) /* Force PD Reset Rx2 */
+#define FORCE_PD_RESET_RX1 (1 << 6) /* Force PD Reset Rx1 */
+#define SMALL_LMT_OVERLOAD_THRESH(x) (((x) & 0x3F) << 0) /* Small LMT Overload Threshold<5:0> */
+
+/*
+* REG_LARGE_LMT_OVERLOAD_THRESH
+*/
+#define LARGE_LMT_OVERLOAD_THRESH(x) (((x) & 0x3F) << 0) /* Large LMT Overload Threshold<5:0> */
+
+/*
+* REG_RX1_MANUAL_LMT_FULL_GAIN
+*/
+#define POWER_MEAS_IN_STATE_5_MSB (1 << 7) /* Power Meas in State 5 <3> */
+#define RX1_MANUAL_FULL_TABLE_LMT_TABLE_GAIN_INDEX(x) (((x) & 0x7F) << 0) /* Rx1 Manual Full table/LMT table Gain Index<6:0> */
+#define RX_FULL_TBL_IDX_MASK RX1_MANUAL_FULL_TABLE_LMT_TABLE_GAIN_INDEX(~0)
+
+/*
+* REG_RX1_MANUAL_LPF_GAIN
+*/
+#define POWER_MEAS_IN_STATE_5(x) (((x) & 0x7) << 5) /* Power Meas in State 5<2:0> */
+#define RX1_MANUAL_LPF_GAIN(x) (((x) & 0x1F) << 0) /* Rx1 Manual LPF Gain <4:0> */
+#define RX_LPF_IDX_MASK RX1_MANUAL_LPF_GAIN(~0)
+
+/*
+* REG_RX1_MANUAL_DIGITALFORCED_GAIN
+*/
+#define FORCE_RX1_DIGITAL_GAIN (1 << 5) /* Force Rx1 Digital Gain */
+#define RX1_MANUALFORCED_DIGITAL_GAIN(x) (((x) & 0x1F) << 0) /* Rx1 Manual/Forced Digital Gain<4:0> */
+#define RX_DIGITAL_IDX_MASK RX1_MANUALFORCED_DIGITAL_GAIN(~0)
+/*
+* REG_RX2_MANUAL_LMT_FULL_GAIN
+*/
+#define RX2_MANUAL_FULL_TABLE_LMT_TABLE_GAIN_INDEX(x) (((x) & 0x7F) << 0) /* Rx2 Manual Full table/ LMT table Gain Index<6:0> */
+
+/*
+* REG_RX2_MANUAL_LPF_GAIN
+*/
+#define RX2_MANUAL_LPF_GAIN(x) (((x) & 0x1F) << 0) /* Rx2 Manual LPF Gain<4:0> */
+
+/*
+* REG_RX2_MANUAL_DIGITALFORCED_GAIN
+*/
+#define FORCE_RX2_DIGITAL_GAIN (1 << 5) /* Force Rx2 Digital Gain */
+#define RX2_MANUALFORCED_DIGITAL_GAIN(x) (((x) & 0x1F) << 0) /* Rx2 Manual/Forced Digital Gain<4:0> */
+
+/*
+* REG_FAST_CONFIG_1
+*/
+#define ENABLE_GAIN_INC_AFTER_GAIN_LOCK (1 << 7) /* Enable Gain Inc after Gain Lock */
+#define GOTO_OPT_GAIN_IF_ENERGY_LOST_OR_EN_AGC_HIGH (1 << 6) /* Goto Opt Gain if Energy Lost or EN_AGC High */
+#define GOTO_SET_GAIN_IF_EN_AGC_HIGH (1 << 5) /* Goto Set Gain if EN_AGC High */
+#define GOTO_SET_GAIN_IF_EXIT_RX_STATE (1 << 4) /* Goto Set Gain if Exit Rx State */
+#define DONT_UNLOCK_GAIN_IF_ENERGY_LOST (1 << 3) /* Don't Unlock Gain if Energy Lost */
+#define GOTO_OPTIMIZED_GAIN_IF_EXIT_RX_STATE (1 << 2) /* Goto Optimized Gain if Exit Rx State */
+#define DONT_UNLOCK_GAIN_IF_LG_ADC_OR_LMT_OVRG (1 << 1) /* Don't Unlock Gain If Lg ADC or LMT Ovrg */
+#define ENABLE_INCR_GAIN (1 << 0) /* Enable Incr Gain */
+
+/*
+* REG_FAST_CONFIG_2_SETTLING_DELAY
+*/
+#define USE_LAST_LOCK_LEVEL_FOR_SET_GAIN (1 << 7) /* Use Last Lock Level for Set Gain */
+#define ENABLE_LMT_GAIN_INC_FOR_LOCK_LEVEL (1 << 6) /* Enable LMT Gain Inc for Lock Level */
+#define GOTO_MAX_GAIN_OR_OPT_GAIN_IF_EN_AGC_HIGH (1 << 5) /* Goto Max Gain or Opt Gain if EN_AGC High */
+#define SETTLING_DELAY(x) (((x) & 0x1F) << 0) /* Settling Delay<4:0> */
+
+/*
+* REG_FAST_ENERGY_LOST_THRESH
+*/
+#define POST_LOCK_LEVEL_STP_SIZE_FOR_LPF_TABLE_FULL_TABLE(x) (((x) & 0x3) << 6) /* Post Lock Level Step Size for: LPF Table/ Full Table <1:0> */
+#define ENERGY_LOST_THRESH(x) (((x) & 0x3F) << 0) /* Energy lost threshold<5:0> */
+
+/*
+* REG_FAST_STRONGER_SIGNAL_THRESH
+*/
+#define POST_LOCK_LEVEL_STP_FOR_LMT_TABLE(x) (((x) & 0x3) << 6) /* Post Lock Level Step for LMT Table <1:0> */
+#define STRONGER_SIGNAL_THRESH(x) (((x) & 0x3F) << 0) /* Stronger Signal Threshold<5:0> */
+
+/*
+* REG_FAST_LOW_POWER_THRESH
+*/
+#define DONT_UNLOCK_GAIN_IF_ADC_OVRG (1 << 7) /* Don't unlock gain if ADC Ovrg */
+#define LOW_POWER_THRESH(x) (((x) & 0x7F) << 0) /* Low Power Threshold<6:0> */
+
+/*
+* REG_FAST_STRONG_SIGNAL_FREEZE
+*/
+#define DONT_UNLOCK_GAIN_IF_STRONGER_SIGNAL (1 << 7) /* Don't unlock gain if Stronger Signal */
+
+/*
+* REG_FAST_FINAL_OVER_RANGE_AND_OPT_GAIN
+*/
+#define FINAL_OVER_RANGE_COUNT(x) (((x) & 0x7) << 5) /* Final Over Range Count<2:0> */
+#define OPTIMIZE_GAIN_OFFSET(x) (((x) & 0xF) << 0) /* Optimize Gain Offset<3:0> */
+
+/*
+* REG_FAST_ENERGY_DETECT_COUNT
+*/
+#define INCREMENT_GAIN_STP_LPFLMT(x) (((x) & 0x7) << 5) /* Increment Gain Step (LPF/LMT)<2:0> */
+#define ENERGY_DETECT_COUNT(x) (((x) & 0x1F) << 0) /* Energy Detect count<4:0> */
+
+/*
+* REG_FAST_AGCLL_UPPER_LIMIT
+*/
+#define AGCLL_MAX_INCREASE(x) (((x) & 0x3F) << 0) /* AGCLL Max Increase<5:0> */
+
+/*
+* REG_FAST_GAIN_LOCK_EXIT_COUNT
+*/
+#define GAIN_LOCK_EXIT_COUNT(x) (((x) & 0x3F) << 0) /* Gain Lock Exit Count<5:0> */
+
+/*
+* REG_FAST_INITIAL_LMT_GAIN_LIMIT
+*/
+#define INITIAL_LMT_GAIN_LIMIT(x) (((x) & 0x7F) << 0) /* Initial LMT Gain Limit<6:0> */
+
+/*
+* REG_AGC_INNER_LOW_THRESH
+*/
+#define PREVENT_GAIN_INC (1 << 7) /* Prevent Gain Inc */
+#define AGC_INNER_LOW_THRESH(x) (((x) & 0x7F) << 0) /* AGC Inner Low Threshold<6:0> */
+
+/*
+* REG_LMT_OVERLOAD_COUNTERS
+*/
+#define LARGE_LMT_OVERLOAD_EXED_COUNTER(x) (((x) & 0xF) << 4) /* Large LMT Overload Exceeded Counter<3:0> */
+#define SMALL_LMT_OVERLOAD_EXED_COUNTER(x) (((x) & 0xF) << 0) /* Small LMT Overload Exceeded Counter<3:0> */
+
+/*
+* REG_ADC_OVERLOAD_COUNTERS
+*/
+#define LARGE_ADC_OVERLOAD_EXED_COUNTER(x) (((x) & 0xF) << 4) /* Large ADC Overload Exceeded Counter<3:0> */
+#define SMALL_ADC_OVERLOAD_EXED_COUNTER(x) (((x) & 0xF) << 0) /* Small ADC Overload Exceeded Counter<3:0> */
+
+/*
+* REG_GAIN_STP1
+*/
+#define IMMED_GAIN_CHANGE_IF_LG_LMT_OVERLOAD (1 << 7) /* Immed. Gain Change if Lg LMT Overload */
+#define IMMED_GAIN_CHANGE_IF_LG_ADC_OVERLOAD (1 << 3) /* Immed. Gain Change if Lg ADC Overload */
+#define AGC_INNER_HIGH_THRESH_EXED_STP_SIZE(x) (((x) & 0x7) << 4) /* AGC Inner High Threshold Exceeded Step Size<2:0> */
+#define AGC_INNER_LOW_THRESH_EXED_STP_SIZE(x) (((x) & 0x7) << 0) /* AGC Inner Low Threshold Exceeded Step Size<2:0> */
+
+/*
+* REG_DIGITAL_SAT_COUNTER
+*/
+#define DOUBLE_GAIN_COUNTER (1 << 5) /* Double Gain Counter */
+#define ENABLE_SYNC_FOR_GAIN_COUNTER (1 << 4) /* Enable Sync for Gain Counter */
+#define DIG_SATURATION_EXED_COUNTER(x) (((x) & 0xF) << 0) /* Dig Saturation Exceeded Counter<3:0> */
+
+/*
+* REG_OUTER_POWER_THRESHS
+*/
+#define AGC_OUTER_HIGH_THRESH(x) (((x) & 0xF) << 4) /* AGC Outer High Threshold<3:0> */
+#define AGC_OUTER_LOW_THRESH(x) (((x) & 0xF) << 0) /* AGC Outer Low Threshold<3:0> */
+
+/*
+* REG_GAIN_STP_2
+*/
+#define AGC_OUTER_HIGH_THRESH_EXED_STP_SIZE(x) (((x) & 0xF) << 4) /* AGC outer High Threshold Exceeded Step Size<3:0> */
+#define AGC_OUTER_LOW_THRESH_EXED_STP_SIZE(x) (((x) & 0xF) << 0) /* AGC Outer Low Threshold Exceeded Step Size<3:0> */
+
+/*
+* REG_EXT_LNA_HIGH_GAIN
+*/
+#define EXT_LNA_HIGH_GAIN(x) (((x) & 0x3F) << 0) /* Ext LNA High Gain<5:0> */
+
+/*
+* REG_EXT_LNA_LOW_GAIN
+*/
+#define EXT_LNA_LOW_GAIN(x) (((x) & 0x3F) << 0) /* Ext LNA Low Gain<5:0> */
+
+/*
+* REG_GAIN_TABLE_ADDRESS
+*/
+#define GAIN_TABLE_ADDRESS(x) (((x) & 0x7F) << 0) /* Gain Table Address<6:0> */
+
+/*
+* REG_GAIN_TABLE_WRITE_DATA1
+*/
+#define EXT_LNA_CTRL (1 << 7) /* Ext LNA Ctrl */
+#define LNA_GAIN(x) (((x) & 0x3) << 5) /* LNA Gain <1:0> */
+#define MIXER_GM_GAIN(x) (((x) & 0x1F) << 0) /* Mixer Gm Gain <4:0> */
+
+/*
+* REG_GAIN_TABLE_WRITE_DATA2
+*/
+#define TIA_GAIN (1 << 5) /* TIA Gain */
+#define LPF_GAIN(x) (((x) & 0x1F) << 0) /* LPF Gain <4:0> */
+
+/*
+* REG_GAIN_TABLE_WRITE_DATA_3
+*/
+#define RF_DC_CAL (1 << 5) /* RF DC Cal */
+#define DIGITAL_GAIN(x) (((x) & 0x1F) << 0) /* Digital Gain <4:0> */
+
+/*
+* REG_GAIN_TABLE_READ_DATA_1
+*/
+#define TO_LNA_GAIN(x) (((x) >> 5) & 0x3) /* LNA Gain <1:0> */
+#define TO_MIXER_GM_GAIN(x) (((x) >> 0) & 0x1F) /* Mixer Gm Gain <4:0> */
+
+/*
+* REG_GAIN_TABLE_READ_DATA_2
+*/
+#define TO_LPF_GAIN(x) (((x) >> 0) & 0x1F) /* LPF Gain <4:0> */
+
+/*
+* REG_GAIN_TABLE_READ_DATA_3
+*/
+#define TO_DIGITAL_GAIN(x) (((x) >> 0) & 0x1F) /* Digital Gain <4:0> */
+
+/*
+* REG_GAIN_TABLE_CONFIG
+*/
+#define WRITE_GAIN_TABLE (1 << 2) /* Write Gain Table */
+#define START_GAIN_TABLE_CLOCK (1 << 1) /* Start Gain Table Clock */
+#define RECEIVER_SELECT(x) (((x) & 0x3) << 3) /* Receiver Select<1:0> */
+#define GT_RX1 1
+#define GT_RX2 2
+
+
+/*
+* REG_GM_SUB_TABLE_GAIN_WRITE
+*/
+#define GM_SUB_TABLE_GAIN_WRITE(x) (((x) & 0x7F) << 0) /* Gm Sub Table Gain Word Write<6:0> */
+
+/*
+* REG_GM_SUB_TABLE_BIAS_WRITE
+*/
+#define GM_SUB_TABLE_BIAS_WRITE(x) (((x) & 0x1F) << 0) /* Gm Sub Table Bias Word Write<4:0> */
+
+/*
+* REG_GM_SUB_TABLE_CTRL_WRITE
+*/
+#define GM_SUB_TABLE_CTRL_WRITE(x) (((x) & 0x3F) << 0) /* Gm Sub Table Control Word Write<5:0> */
+
+/*
+* REG_GM_SUB_TABLE_GAIN_READ
+*/
+#define GM_SUB_TABLE_GAIN_READ(x) (((x) & 0x7F) << 0) /* Gm Sub Table Gain Word Read<6:0> */
+
+/*
+* REG_GM_SUB_TABLE_BIAS_READ
+*/
+#define GM_SUB_TABLE_BIAS_READ(x) (((x) & 0x1F) << 0) /* Gm Sub Table Bias Word Read<4:0> */
+
+/*
+* REG_GM_SUB_TABLE_CTRL_READ
+*/
+#define GM_SUB_TABLE_CTRL_READ(x) (((x) & 0x3F) << 0) /* Gm Sub Table Control Word Read<5:0> */
+
+/*
+* REG_GM_SUB_TABLE_CONFIG
+*/
+#define WRITE_GM_SUB_TABLE (1 << 2) /* Write Gm Sub Table */
+#define START_GM_SUB_TABLE_CLOCK (1 << 1) /* Start Gm Sub Table Clock */
+
+/*
+* REG_GAIN_DIFF_WORDERROR_WRITE
+*/
+#define CALIB_TABLE_GAIN_DIFFERROR_WORD(x) (((x) & 0x3F) << 0) /* Calib Table Gain Diff/Error Word<5:0> */
+
+/*
+* REG_GAIN_ERROR_READ
+*/
+#define CALIB_TABLE_GAIN_ERROR(x) (((x) & 0x1F) << 0) /* Calib Table Gain Error<4:0> */
+
+/*
+* REG_CONFIG
+*/
+#define READ_SELECT (1 << 4) /* Read Select */
+#define WRITE_MIXER_ERROR_TABLE (1 << 3) /* Write Mixer Error Table */
+#define WRITE_LNA_ERROR_TABLE (1 << 2) /* Write LNA Error Table */
+#define WRITE_LNA_GAIN_DIFF (1 << 1) /* Write LNA Gain Diff */
+#define START_CALIB_TABLE_CLOCK (1 << 0) /* Start Calib Table Clock */
+#define CALIB_TABLE_SELECT(x) (((x) & 0x3) << 5) /* Calib Table Select<1:0> */
+
+/*
+* REG_LNA_GAIN_DIFF_READ_BACK
+*/
+#define LNA_CALIB_TABLE_GAIN_DIFFERENCE_WORD(x) (((x) & 0x3F) << 0) /* LNA Calib Table Gain Difference Word<5:0> */
+
+/*
+* REG_MAX_MIXER_CALIBRATION_GAIN_INDEX
+*/
+#define MAX_MIXER_CALIBRATION_GAIN_INDEX(x) (((x) & 0x1F) << 0) /* Max Mixer Calibration Gain Index<4:0> */
+
+/*
+* REG_SETTLE_TIME
+*/
+#define ENABLE_DIG_GAIN_CORR (1 << 7) /* Enable Dig Gain Corr */
+#define FORCE_TEMP_SENSOR_FOR_CAL (1 << 6) /* Force Temp Sensor for Cal */
+#define SETTLE_TIME(x) (((x) & 0x3F) << 0) /* Settle Time<5:0> */
+
+/*
+* REG_MEASURE_DURATION
+*/
+#define GAIN_CAL_MEAS_DURATION(x) (((x) & 0xF) << 0) /* Gain Cal Meas Duration<3:0> */
+
+/*
+* REG_MEASURE_DURATION_01
+*/
+#define MEASUREMENT_DURATION_1(x) (((x) & 0xF) << 4) /* Measurement duration 1 <3:0> */
+#define MEASUREMENT_DURATION_0(x) (((x) & 0xF) << 0) /* Measurement duration 0 <3:0> */
+
+/*
+* REG_MEASURE_DURATION_23
+*/
+#define MEASUREMENT_DURATION_3(x) (((x) & 0xF) << 4) /* Measurement duration 3 <3:0> */
+#define MEASUREMENT_DURATION_2(x) (((x) & 0xF) << 0) /* Measurement duration 2 <3:0> */
+
+/*
+* REG_RSSI_CONFIG
+*/
+#define START_RSSI_MEAS (1 << 5) /* Start RSSI Meas (Mode 4) */
+#define ENABLE_ADC_POWER_MEAS (1 << 1) /* Enable ADC Power Meas. */
+#define DEFAULT_RSSI_MEAS_MODE (1 << 0) /* Default RSSI Meas Mode */
+#define RFIR_FOR_RSSI_MEASUREMENT(x) (((x) & 0x3) << 6) /* RFIR for RSSI measurement<1:0> */
+#define RSSI_MODE_SELECT(x) (((x) & 0x7) << 2) /* RSSI Mode Select<2:0> */
+
+/*
+* REG_ADC_MEASURE_DURATION_01
+*/
+#define ADC_POWER_MEASUREMENT_DURATION_1(x) (((x) & 0xF) << 4) /* ADC Power Measurement Duration 1<3:0> */
+#define ADC_POWER_MEASUREMENT_DURATION_0(x) (((x) & 0xF) << 0) /* ADC Power Measurement Duration 0 <3:0> */
+
+/*
+* REG_DEC_POWER_MEASURE_DURATION_0
+*/
+#define USE_HB3_OUT_FOR_ADC_PWR_MEAS (1 << 7) /* Use HB3 Out for ADC Pwr Meas */
+#define USE_HB1_OUT_FOR_DEC_PWR_MEAS (1 << 6) /* Use HB1 Out for Dec pwr Meas */
+#define ENABLE_DEC_PWR_MEAS (1 << 5) /* Enable Dec Pwr Meas */
+#define DEFAULT_MODE_ADC_POWER (1 << 4) /* Default Mode ADC Power */
+#define DEC_POWER_MEASUREMENT_DURATION(x) (((x) & 0xF) << 0) /* Dec Power Measurement Duration <3:0> */
+
+/*
+* REG_LNA_GAIN
+*/
+#define DB_GAIN_READBACK_CHANNEL (1 << 0) /* dB Gain Read-back Channel */
+#define MAX_LNA_GAIN(x) (((x) & 0x7F) << 1) /* Max LNA Gain<6:0> */
+
+/*
+* REG_RX_QUAD_CAL_LEVEL
+*/
+#define RX_QUAD_CAL_LEVEL(x) (((x) & 0xF) << 0) /* Rx Quad Cal Level <3 :0> */
+
+/*
+* REG_CALIBRATION_CONFIG_1
+*/
+#define ENABLE_PHASE_CORR (1 << 7) /* Enable Phase Corr */
+#define ENABLE_GAIN_CORR (1 << 6) /* Enable Gain Corr */
+#define USE_SETTLE_COUNT_FOR_DC_CAL_WAIT (1 << 5) /* Use Settle Count for DC Cal Wait */
+#define FIXED_DC_CAL_WAIT_TIME (1 << 4) /* Fixed DC Cal Wait Time */
+#define FREE_RUN_MODE (1 << 3) /* Free Run Mode */
+#define ENABLE_CORR_WORD_DECIMATION (1 << 2) /* Enable Corr Word Decimation */
+#define ENABLE_TRACKING_MODE_CH2 (1 << 1) /* Enable Tracking Mode CH2 */
+#define ENABLE_TRACKING_MODE_CH1 (1 << 0) /* Enable Tracking Mode CH1 */
+
+/*
+* REG_CALIBRATION_CONFIG_2
+*/
+#define SOFT_RESET (1 << 7) /* Soft Reset */
+#define CALIBRATION_CONFIG2_DFLT (0x3 << 5) /* Must be 2'b11 */
+#define K_EXP_PHASE(x) (((x) & 0x1F) << 0) /* K exp Phase<4:0> */
+
+/*
+* REG_CALIBRATION_CONFIG_3
+*/
+#define PREVENT_POS_LOOP_GAIN (1 << 7) /* Prevent Pos Loop Gain */
+#define K_EXP_AMPLITUDE(x) (((x) & 0x1F) << 0) /* K exp Amplitude<4:0> */
+
+/*
+* REG_RX_QUAD_GAIN1
+*/
+#define RX_FULL_TABLELMT_TABLE_GAIN(x) (((x) & 0x7F) << 0) /* Rx Full table/LMT table gain<6:0> */
+
+/*
+* REG_RX_QUAD_GAIN2
+*/
+#define CORRECTION_WORD_DECIMATION_M(x) (((x) & 0x7) << 5) /* Correction Word Decimation M<2:0> */
+#define RX_LPF_GAIN(x) (((x) & 0x1F) << 0) /* Rx LPF gain<4:0> */
+
+/*
+* REG_RX1_INPUT_A_OFFSETS
+*/
+#define RX1_INPUT_A_I_DC_OFFSET_LSB(x) (((x) & 0x3F) << 2) /* Rx1 Input A "I" DC Offset<5:0> */
+#define RX1_INPUT_A_Q_DC_OFFSET(x) (((x) & 0x3) << 0) /* Rx1 Input A "Q" DC Offset<9:8> */
+
+/*
+* REG_INPUT_A_OFFSETS_1
+*/
+#define RX2_INPUT_A_Q_DC_OFFSET_LSB(x) (((x) & 0xF) << 4) /* Rx2 Input A "Q" DC Offset<3:0> */
+#define RX1_INPUT_A_I_DC_OFFSET_MSB(x) (((x) & 0xF) << 0) /* Rx1 Input A "I" DC Offset<9:6> */
+
+/*
+* REG_RX2_INPUT_A_OFFSETS
+*/
+#define RX2_INPUT_A_I_DC_OFFSET(x) (((x) & 0x3) << 6) /* Rx2 Input A "I" DC Offset<1:0> */
+#define RX2_INPUT_A_Q_DC_OFFSET_MSB(x) (((x) & 0x3F) << 0) /* Rx2 Input A "Q" DC Offset<9:4> */
+
+/*
+* REG_RX1_INPUT_BC_OFFSETS
+*/
+#define RX1_INPUT_BC_I_DC_OFFSET_LSB(x) (((x) & 0x3F) << 2) /* Rx1 Input B&C "I" DC Offset<5:0> */
+#define RX1_INPUT_BC_Q_DC_OFFSET(x) (((x) & 0x3) << 0) /* Rx1 Input B&C "Q" DC Offset<9:8> */
+
+/*
+* REG_INPUT_BC_OFFSETS_1
+*/
+#define RX2_INPUT_BC_Q_DC_OFFSET_LSB(x) (((x) & 0xF) << 4) /* Rx2 Input B&C "Q" DC Offset<3:0> */
+#define RX1_INPUT_BC_I_DC_OFFSET_MSB(x) (((x) & 0xF) << 0) /* Rx1 Input B&C "I" DC Offset<9:6> */
+
+/*
+* REG_RX2_INPUT_BC_OFFSETS
+*/
+#define RX2_INPUT_BC_I_DC_OFFSET(x) (((x) & 0x3) << 6) /* Rx2 Input B&C "I" DC Offset<1:0> */
+#define RX2_INPUT_BC_Q_DC_OFFSET_MSB(x) (((x) & 0x3F) << 0) /* Rx2 Input B&C "Q" DC Offset<9:4> */
+
+/*
+* REG_FORCE_BITS
+*/
+#define RX2_INPUT_BC_FORCE_OFFSET (1 << 7) /* Rx2 Input B&C Force offset */
+#define RX1_INPUT_BC_FORCE_OFFSET (1 << 6) /* Rx1 Input B&C Force offset */
+#define RX2_INPUT_BC_FORCE_PHGAIN (1 << 5) /* Rx2 Input B&C Force Ph/Gain */
+#define RX1_INPUT_BC_FORCE_PHGAIN (1 << 4) /* Rx1 Input B&C Force Ph/Gain */
+#define RX2_INPUT_A_FORCE_OFFSET (1 << 3) /* Rx2 Input A Force offset */
+#define RX1_INPUT_A_FORCE_OFFSET (1 << 2) /* Rx1 Input A Force offset */
+#define RX2_INPUT_A_FORCE_PHGAIN (1 << 1) /* Rx2 Input A Force Ph/Gain */
+#define RX1_INPUT_A_FORCE_PHGAIN (1 << 0) /* Rx1 Input A Force Ph/Gain */
+
+/*
+* REG_RF_DC_OFFSET_CONFIG_1
+*/
+#define DAC_FS(x) (((x) & 0x3) << 4) /* DAC FS<1:0> */
+#define RF_DC_CALIBRATION_COUNT(x) (((x) & 0xF) << 0) /* RF DC Calibration Count<3:0> */
+
+/*
+* REG_RF_DC_OFFSET_ATTEN
+*/
+#define RF_DC_OFFSET_TABLE_UPDATE_COUNT(x) (((x) & 0x7) << 5) /* RF DC Offset Table Update Count<2:0> */
+#define RF_DC_OFFSET_ATTEN(x) (((x) & 0x1F) << 0) /* RF DC Offset Attenuation<4:0> */
+
+/*
+* REG_INVERT_BITS
+*/
+#define INVERT_RX2_RF_DC_CGIN_WORD (1 << 7) /* Invert Rx2 RF DC CGin Word */
+#define INVERT_RX1_RF_DC_CGIN_WORD (1 << 6) /* Invert Rx1 RF DC CGin Word */
+#define INVERT_RX2_RF_DC_CGOUT_WORD (1 << 5) /* Invert Rx2 RF DC CGout Word */
+#define INVERT_RX1_RF_DC_CGOUT_WORD (1 << 4) /* Invert Rx1 RF DC CGout Word */
+
+/*
+* REG_DC_OFFSET_CONFIG2
+*/
+#define USE_WAIT_COUNTER_FOR_RF_DC_INIT_CAL (1 << 7) /* Use Wait Counter for RF DC Init Cal */
+#define ENABLE_FAST_SETTLE_MODE (1 << 6) /* Enable Fast Settle Mode */
+#define ENABLE_BB_DC_OFFSET_TRACKING (1 << 5) /* Enable BB DC Offset Tracking */
+#define RESET_ACC_ON_GAIN_CHANGE (1 << 4) /* Reset Acc on Gain Change */
+#define ENABLE_RF_OFFSET_TRACKING (1 << 3) /* Enable RF Offset Tracking */
+#define DC_OFFSET_UPDATE(x) (((x) & 0x7) << 0) /* DC Offset Update<2:0> */
+
+/*
+* REG_RF_CAL_GAIN_INDEX
+*/
+#define RF_MINIMUM_CALIBRATION_GAIN_INDEX(x) (((x) & 0x7F) << 0) /* RF Minimum Calibration Gain Index<6:0> */
+
+/*
+* REG_SOI_THRESH
+*/
+#define RF_SOI_THRESH(x) (((x) & 0x7F) << 0) /* RF SOI Threshold<6:0> */
+
+/*
+* REG_BB_DC_OFFSET_SHIFT
+*/
+#define INCREASE_COUNT_DURATION (1 << 7) /* Increase Count Duration */
+#define BB_TRACKING_DECIMATE(x) (((x) & 0x3) << 5) /* BB Tracking Decimate<1:0> */
+#define BB_DC_M_SHIFT(x) (((x) & 0x1F) << 0) /* BB DC M Shift<4:0> */
+
+/*
+* REG_BB_DC_OFFSET_FAST_SETTLE_SHIFT
+*/
+#define READ_BACK_CH_SEL (1 << 7) /* Read Back CH Sel */
+#define UPDATE_TRACKING_WORD (1 << 6) /* Update Tracking Word */
+#define FORCE_RX_NULL (1 << 5) /* Force Rx Null */
+#define BB_DC_TRACKING_FAST_SETTLE_M_SHIFT(x) (((x) & 0x1F) << 0) /* BB DC Tracking Fast Settle M Shift<4:0> */
+
+/*
+* REG_BB_DC_OFFSET_ATTEN
+*/
+#define BB_DC_OFFSET_ATTEN(x) (((x) & 0xF) << 0) /* BB DC Offset Atten<3:0> */
+
+/*
+* REG_RX1_BB_DC_WORD_I_MSB
+*/
+#define RX1_BB_DC_OFFSET_CORRECTION_WORD_I(x) (((x) & 0x7F) << 0) /* RX1 BB DC Offset Correction word I<14:8> */
+
+/*
+* REG_RX1_BB_DC_WORD_Q_MSB
+*/
+#define RX1_BB_DC_OFFSET_CORRECTION_WORD_Q(x) (((x) & 0x7F) << 0) /* RX1 BB DC Offset Correction word Q<14:8> */
+
+/*
+* REG_RX2_BB_DC_WORD_I_MSB
+*/
+#define RX2_BB_DC_OFFSET_CORRECTION_WORD_I(x) (((x) & 0x7F) << 0) /* RX2 BB DC Offset Correction word I<14:8> */
+
+/*
+* REG_RX2_BB_DC_WORD_Q_MSB
+*/
+#define RX2_BB_DC_OFFSET_CORRECTION_WORD_Q(x) (((x) & 0x7F) << 0) /* RX2 BB DC Offset Correction word Q<14:8> */
+
+/*
+* REG_BB_TRACK_CORR_WORD_I_MSB
+*/
+#define RX1RX2_BB_DC_OFFSET_TRACKING_CORRECTION_WORD_I(x) (((x) & 0x7F) << 0) /* RX1/RX2 BB DC Offset Tracking correction word I<14:8> */
+
+/*
+* REG_BB_TRACK_CORR_WORD_Q_MSB
+*/
+#define RX1RX2_BB_DC_OFFSET_TRACKING_CORRECTION_WORD_Q(x) (((x) & 0x7F) << 0) /* RX1/RX2 BB DC Offset Tracking correction word Q<14:8> */
+
+/*
+* REG_SYMBOL_LSB
+*/
+#define RX2_RSSI_SYMBOL (1 << 1) /* Rx2 RSSI symbol <0> */
+#define RX1_RSSI_SYMBOL (1 << 0) /* Rx1 RSSI symbol <0> */
+
+/*
+* REG_PREAMBLE_LSB
+*/
+#define RX2_RSSI_PREAMBLE (1 << 1) /* Rx2 RSSI preamble <0> */
+#define RX1_RSSI_PREAMBLE (1 << 0) /* Rx1 RSSI preamble <0> */
+
+/*
+* REG_RX1_RSSI_SYMBOL, REG_RX1_RSSI_PREAMBLE,
+* REG_RX2_RSSI_SYMBOL, REG_RX2_RSSI_PREAMBLE
+*/
+#define RSSI_LSB_SHIFT 1
+#define RSSI_LSB_MASK1 0x01
+#define RSSI_LSB_MASK2 0x02
+
+/*
+* REG_RX_PATH_GAIN_LSB
+*/
+#define RX_PATH_GAIN (1 << 0) /* Rx Path Gain<0> */
+
+/*
+* REG_RX_DIFF_LNA_FORCE
+*/
+#define FORCE_RX2_LNA_GAIN (1 << 7) /* Force Rx2 LNA Gain */
+#define RX2_LNA_BYPASS (1 << 6) /* Rx2 LNA Bypass */
+#define FORCE_RX1_LNA_GAIN (1 << 3) /* Force Rx1 LNA Gain */
+#define RX1_LNA_BYPASS (1 << 2) /* Rx1 LNA Bypass */
+#define RX2_LNA_GAIN(x) (((x) & 0x3) << 4) /* Rx2 LNA Gain<1:0> */
+#define RX1_LNA_GAIN(x) (((x) & 0x3) << 0) /* Rx1 LNA Gain<1:0> */
+
+/*
+* REG_RX_LNA_BIAS_COARSE
+*/
+#define RX_LNA_BIAS_COARSE(x) (((x) & 0xF) << 0) /* Rx LNA Bias Coarse<3:0> */
+
+/*
+* REG_RX_LNA_BIAS_FINE_0
+*/
+#define RX_LNA_PCASCODE_BIAS(x) (((x) & 0x7) << 5) /* Rx LNA p-Cascode Bias<2:0> */
+#define RX_LNA_BIAS(x) (((x) & 0x1F) << 0) /* Rx LNA Bias<4:0> */
+
+/*
+* REG_RX_LNA_BIAS_FINE_1
+*/
+#define RX_LNA_P_CASCODE_BIAS_FINE(x) (((x) & 0x3) << 0) /* Rx LNA p- Cascode Bias Fine<4:3> */
+
+/*
+* REG_RX_MIX_GM_CONFIG
+*/
+#define RX_MIX_GM_CM_OUT(x) (((x) & 0x7) << 5) /* Rx Mix Gm CM Out<2:0> */
+#define RX_MIX_GM_PLOAD(x) (((x) & 0x3) << 0) /* Rx Mix Gm pload <1:0> */
+
+/*
+* REG_RX1_MIX_GM_FORCE
+*/
+#define FORCE_RX1_MIX_GM (1 << 6) /* Force Rx1 Mix Gm */
+#define RX1_MIX_GM_GAIN(x) (((x) & 0x3F) << 0) /* Rx1 Mix Gm Gain<5:0> */
+
+/*
+* REG_RX1_MIX_GM_BIAS_FORCE
+*/
+#define RX1_MIX_GM_BIAS(x) (((x) & 0x1F) << 0) /* Rx1 Mix Gm Bias<4:0> */
+
+/*
+* REG_RX2_MIX_GM_FORCE
+*/
+#define FORCE_RX2_MIX_GM (1 << 6) /* Force Rx2 Mix Gm */
+#define RX2_MIX_GM_GAIN(x) (((x) & 0x3F) << 0) /* Rx2 Mix Gm Gain<5:0> */
+
+/*
+* REG_RX2_MIX_GM_BIAS_FORCE
+*/
+#define RX2_MIX_GM_BIAS(x) (((x) & 0x1F) << 0) /* Rx2 Mix Gm Bias<4:0> */
+
+/*
+* REG_INPUT_A_MSBS
+*/
+#define INPUT_A_RX1_Q(x) (((x) & 0x3) << 6) /* Input A RX1 Q<9:8> */
+#define INPUT_A_RX1_I(x) (((x) & 0x3) << 4) /* Input A RX1 I<9:8> */
+#define INPUT_A_RX2_I(x) (((x) & 0x3) << 2) /* Input A RX2 I<9:8> */
+#define INPUT_A_RX2_Q(x) (((x) & 0x3) << 0) /* Input A RX2 Q<9:8> */
+
+/*
+* REG_INPUTS_BC_MSBS
+*/
+#define INPUTS_BC_RX1_Q(x) (((x) & 0x3) << 6) /* Inputs B&C RX1 Q<9:8> */
+#define INPUTS_BC_RX1_I(x) (((x) & 0x3) << 4) /* Inputs B&C RX1 I<9:8> */
+#define INPUTS_BC_RX2_I(x) (((x) & 0x3) << 2) /* Inputs B&C RX2 I<9:8> */
+#define INPUTS_BC_RX2_Q(x) (((x) & 0x3) << 0) /* Inputs B&C RX2 Q<9:8> */
+
+/*
+* REG_FORCE_OS_DAC
+*/
+#define FORCE_CGIN_DAC (1 << 2) /* Force CGin DAC */
+
+/*
+* REG_RX_MIX_LO_CM
+*/
+#define RX_MIX_LO_CM(x) (((x) & 0x3F) << 0) /* Rx Mix LO CM<5:0> */
+
+/*
+* REG_RX_CGB_SEG_ENABLE
+*/
+#define RX_CGB_SEG_ENABLE(x) (((x) & 0x3F) << 0) /* Rx CGB Seg Enable<5:0> */
+
+/*
+* REG_RX_MIX_INPUTBIAS
+*/
+#define RX_CGB_INPUT_CM_SEL(x) (((x) & 0x3) << 4) /* Rx CGB Input CM Sel<1:0> */
+#define RX_CGB_BIAS(x) (((x) & 0xF) << 0) /* Rx CGB Bias<3:0> */
+
+/*
+* REG_RX_TIA_CONFIG
+*/
+#define TIA2_OVERRIDE_C (1 << 3) /* TIA2 Override C */
+#define TIA2_OVERRIDE_R (1 << 2) /* TIA2 Override R */
+#define TIA1_OVERRIDE_C (1 << 1) /* TIA1 Override C */
+#define TIA1_OVERRIDE_R (1 << 0) /* TIA1 Override R */
+#define TIA_SEL_CC(x) (((x) & 0x7) << 5) /* TIA Sel CC<2:0> */
+
+/*
+* REG_TIA1_C_LSB
+*/
+#define TIA1_RF(x) (((x) & 0x3) << 6) /* TIA1 RF<1:0> */
+#define TIA1_C_LSB(x) (((x) & 0x3F) << 0) /* TIA1 C LSB<5:0> */
+
+/*
+* REG_TIA1_C_MSB
+*/
+#define TIA1_C_MSB(x) (((x) & 0x7F) << 0) /* TIA1 C MSB<6:0> */
+
+/*
+* REG_TIA2_C_LSB
+*/
+#define TIA2_RF(x) (((x) & 0x3) << 6) /* TIA2 RF<1:0> */
+#define TIA2_C_LSB(x) (((x) & 0x3F) << 0) /* TIA2 C LSB<5:0> */
+
+/*
+* REG_TIA2_C_MSB
+*/
+#define TIA2_C_MSB(x) (((x) & 0x7F) << 0) /* TIA2 C MSB<6:0> */
+
+/*
+* REG_RX1_BBF_R1A
+*/
+#define FORCE_RX1_RESISTORS (1 << 7) /* Force Rx1 Resistors */
+#define RX1_BBF_R1A(x) (((x) & 0x3F) << 0) /* Rx1 BBF R1A<5:0> */
+
+/*
+* REG_RX2_BBF_R1A
+*/
+#define FORCE_RX2_RESISTORS (1 << 7) /* Force Rx2 Resistors */
+#define RX2_BBF_R1A(x) (((x) & 0x3F) << 0) /* Rx2 BBF R1A<5:0> */
+
+/*
+* REG_RX1_TUNE_CTRL
+*/
+#define RX1_TUNE_RESAMPLE_PHASE (1 << 2) /* Rx1 Tune Resample Phase */
+#define RX1_TUNE_RESAMPLE (1 << 1) /* Rx1 Tune Resample */
+#define RX1_PD_TUNE (1 << 0) /* Rx1 PD Tune */
+
+/*
+* REG_RX2_TUNE_CTRL
+*/
+#define RX2_TUNE_RESAMPLE_PHASE (1 << 2) /* Rx2 Tune Resam ple Phase */
+#define RX2_TUNE_RESAMPLE (1 << 1) /* Rx2 Tune Resample */
+#define RX2_PD_TUNE (1 << 0) /* Rx2 PD Tune */
+
+/*
+* REG_RX_BBF_R2346
+*/
+#define TUNE_OVERRIDE (1 << 7) /* Tune Override */
+#define RX_BBF_R2346(x) (((x) & 0x7) << 0) /* Rx BBF R2346<2:0> */
+
+/*
+* REG_RX_BBF_C1_MSB
+*/
+#define RX_BBF_C1_MSB(x) (((x) & 0x3F) << 0) /* Rx BBF C1 MSB<5:0> */
+
+/*
+* REG_RX_BBF_C1_LSB
+*/
+#define RX_BBF_C1_LSB(x) (((x) & 0x7F) << 0) /* Rx BBF C1 LSB<6:0> */
+
+/*
+* REG_RX_BBF_C2_MSB
+*/
+#define RX_BBF_C2_MSB(x) (((x) & 0x3F) << 0) /* Rx BBF C2 MSB<5:0> */
+
+/*
+* REG_RX_BBF_C2_LSB
+*/
+#define RX_BBF_C2_LSB(x) (((x) & 0x7F) << 0) /* Rx BBF C2 LSB<6:0> */
+
+/*
+* REG_RX_BBF_C3_MSB
+*/
+#define RX_BBF_C3_MSB(x) (((x) & 0x3F) << 0) /* Rx BBF C3 MSB<5:0> */
+
+/*
+* REG_RX_BBF_C3_LSB
+*/
+#define RX_BBF_C3_LSB(x) (((x) & 0x7F) << 0) /* Rx BBF C3 LSB<6:0> */
+
+/*
+* REG_RX_BBF_CC1_CTR
+*/
+#define RX_BBF_CC1_CTR(x) (((x) & 0x7F) << 0) /* Rx BBF CC1 Ctr<6:0> */
+
+/*
+* REG_RX_BBF_POW_RZ_BYTE0
+*/
+#define MUST_BE_ZERO (1 << 7) /* Must be zero */
+#define RX1_BBF_POW_CTR(x) (((x) & 0x3) << 5) /* Rx1 BBF Pow Ctr<1:0> */
+#define RX_BBF_RZ1_CTR(x) (((x) & 0x3) << 3) /* Rx BBF Rz1 Ctr<1:0> */
+
+/*
+* REG_RX_BBF_CC2_CTR
+*/
+#define RX_BBF_CC2_CTR(x) (((x) & 0x7F) << 0) /* Rx BBF CC2 Ctr<6:0> */
+
+/*
+* REG_RX_BBF_POW_RZ_BYTE1
+*/
+#define RX_BBF_POW3_CTR(x) (((x) & 0x3) << 6) /* Rx BBF Pow3 Ctr<1:0> */
+#define RX_BBF_RZ3_CTR(x) (((x) & 0x3) << 4) /* Rx BBF RZ3 Ctr<1:0> */
+#define RX_BBF_POW2_CTR(x) (((x) & 0x3) << 2) /* Rx BBF Pow2 Ctr<1:0> */
+#define RX_BBF_RZ2_CTR(x) (((x) & 0x3) << 0) /* Rx BBF Rz2 Ctr<1:0> */
+
+/*
+* REG_RX_BBF_CC3_CTR
+*/
+#define RX_BBF_CC3_CTR(x) (((x) & 0x7F) << 0) /* Rx BBF CC3 Ctr<6:0> */
+
+/*
+* REG_RX_BBF_TUNE
+*/
+#define RXBBF_BYPASS_BIAS_R (1 << 7) /* RxBBF Bypass Bias R */
+#define RX_BBF_R5_TUNE (1 << 4) /* Rx BBF R5 Tune */
+#define RX1_BBF_TUNE_COMP_I (1 << 3) /* Rx1 BBF Tune Comp I */
+#define RX1_BBF_TUNE_COMP_Q (1 << 2) /* Rx1 BBF Tune Comp Q */
+#define RX2_BBF_TUNE_COMP_I (1 << 1) /* Rx2 BBF Tune Comp I */
+#define RX2_BBF_TUNE_COMP_Q (1 << 0) /* Rx2 BBF Tune Comp Q */
+#define RX_BBF_TUNE_CTR(x) (((x) & 0x3) << 5) /* Rx BBF Tune Ctr<1:0> */
+
+/*
+* REG_RX1_BBF_MAN_GAIN
+*/
+#define RX1_BBF_FORCE_GAIN (1 << 5) /* Rx1 BBF Force Gain */
+#define RX1_BBF_BQ_GAIN(x) (((x) & 0x3) << 3) /* Rx1 BBF BQ Gain<1:0> */
+#define RX1_BBF_POLE_GAIN(x) (((x) & 0x7) << 0) /* Rx1 BBF Pole Gain<2:0> */
+
+/*
+* REG_RX2_BBF_MAN_GAIN
+*/
+#define RX2_BBF_FORCE_GAIN (1 << 5) /* Rx2 BBF Force Gain */
+#define RX2_BBF_BQ_GAIN(x) (((x) & 0x3) << 3) /* Rx2 BBF BQ Gain<1:0> */
+#define RX2_BBF_POLE_GAIN(x) (((x) & 0x7) << 0) /* Rx2 BBF Pole Gain<2:0> */
+
+/*
+* REG_RX_BBF_TUNE_CONFIG
+*/
+#define RX_TUNE_EVALTIME (1 << 4) /* Rx Tune Evaltime */
+#define RX_BBF_TUNE_DIVIDE (1 << 0) /* RX BBF Tune Divide<8> */
+#define TUNE_COMP_MASK(x) (((x) & 0x3) << 5) /* Tune Comp Mask <1:0> */
+#define RX_TUNE_MODE(x) (((x) & 0x7) << 1) /* Rx Tune Mode<2:0> */
+
+/*
+* REG_POLE_GAIN
+*/
+#define POLE_GAIN_TUNE(x) (((x) & 0x3) << 0) /* Pole Gain Tune<1:0> */
+
+/*
+* REG_RX_BBBW_MHZ
+*/
+#define RX_TUNE_BBBW_MHZ(x) (((x) & 0x1F) << 0) /* Rx Tune BBBW MHz<4::0> */
+
+/*
+* REG_RX_BBBW_KHZ
+*/
+#define RX_TUNE_BBBW_KHZ(x) (((x) & 0x7F) << 0) /* Rx Tune BBBW kHz<6:0> */
+
+/*
+* REG_RX_PFD_CONFIG
+*/
+#define BYPASS_LD_SYNTH (1 << 0) /* Bypass Ld Synth */
+
+/*
+* REG_RX_INTEGER_BYTE_1
+*/
+#define SYNTH_INTEGER_WORD(x) (((x) & 0x7) << 0) /* Synthesizer Integer Word<10:8> */
+
+/*
+* REG_RX_FRACT_BYTE_2
+*/
+#define SYNTH_FRACT_WORD(x) (((x) & 0x7F) << 0) /* Synthesizer Fractional Word <22:16> */
+
+/*
+* REG_RX_FORCE_VCO_TUNE_1
+*/
+#define VCO_CAL_OFFSET(x) (((x) & 0xF) << 3) /* VCO Cal Offset<3:0> */
+
+/*
+* REG_RX_ALC_VARACTOR
+*/
+#define INIT_ALC_VALUE(x) (((x) & 0xF) << 4) /* Init ALC Value<3:0> */
+#define VCO_VARACTOR(x) (((x) & 0xF) << 0) /* VCO Varactor<3:0> */
+
+/*
+* REG_RX_VCO_OUTPUT
+*/
+#define PORB_VCO_LOGIC (1 << 6) /* PORb VCO Logic */
+#define VCO_OUTPUT_LEVEL(x) (((x) & 0xF) << 0) /* VCO Output Level<3:0> */
+
+/*
+* REG_RX_CP_CURRENT
+*/
+#define CHARGE_PUMP_CURRENT(x) (((x) & 0x3F) << 0) /* Charge Pump Current<5:0> */
+
+/*
+* REG_RX_CP_OFFSET
+*/
+#define SYNTH_RECAL (1 << 7) /* Synth Re-Cal */
+
+/*
+* REG_RX_CP_CONFIG
+*/
+#define HALF_VCO_CAL_CLK (1 << 7) /* Half Vco Cal Clk */
+#define F_CPCAL (1 << 3) /* F Cpcal */
+#define CP_CAL_ENABLE (1 << 2) /* Cp Cal Enable */
+
+/*
+* REG_RX_LOOP_FILTER_1
+*/
+#define LOOP_FILTER_C2(x) (((x) & 0xF) << 4) /* Loop Filter C2<3:0> */
+#define LOOP_FILTER_C1(x) (((x) & 0xF) << 0) /* Loop Filter C1<3:0> */
+
+/*
+* REG_RX_LOOP_FILTER_2
+*/
+#define LOOP_FILTER_R1(x) (((x) & 0xF) << 4) /* Loop Filter R1<3:0> */
+#define LOOP_FILTER_C3(x) (((x) & 0xF) << 0) /* Loop Filter C3<3:0> */
+
+/*
+* REG_RX_LOOP_FILTER_3
+*/
+#define LOOP_FILTER_BYPASS_R3 (1 << 7) /* Loop Filter Bypass R3 */
+#define LOOP_FILTER_BYPASS_R1 (1 << 6) /* Loop Filter Bypass R1 */
+#define LOOP_FILTER_BYPASS_C2 (1 << 5) /* Loop Filter Bypass C2 */
+#define LOOP_FILTER_BYPASS_C1 (1 << 4) /* Loop Filter Bypass C1 */
+#define LOOP_FILTER_R3(x) (((x) & 0xF) << 0) /* Loop Filter R3<3:0> */
+
+/*
+* REG_RX_DITHERCP_CAL
+*/
+#define FORCED_CP_CAL_WORD(x) (((x) & 0xF) << 0) /* Forced CP Cal Word<3:0> */
+
+/*
+* REG_RX_VCO_BIAS_1
+*/
+#define VCO_BIAS_TCF(x) (((x) & 0x3) << 3) /* VCO Bias Tcf<1:0> */
+#define VCO_BIAS_REF(x) (((x) & 0x7) << 0) /* VCO Bias Ref<2:0> */
+
+/*
+* REG_RX_CAL_STATUS
+*/
+#define CP_CAL_VALID (1 << 7) /* CP Cal Valid */
+#define CP_CAL_DONE (1 << 5) /* CP Cal Done */
+#define VCO_CAL_BUSY (1 << 4) /* VCO Cal Busy */
+#define CP_CAL_WORD(x) (((x) & 0xF) << 0) /* CP Cal Word<3:0> */
+
+/*
+* REG_RX_VCO_CAL_REF
+*/
+#define VCO_CAL_REF_TCF(x) (((x) & 0x7) << 0) /* VCO Cal Ref Tcf<2:0> */
+
+/*
+* REG_RX_VCO_PD_OVERRIDES
+*/
+#define POWER_DOWN_VARACTOR_REF (1 << 3) /* Power Down Varactor Ref */
+#define PWR_DOWN_VARACT_REF_TCF (1 << 2) /* Pwr Down Varact Ref Tcf */
+#define POWER_DOWN_CAL_TCF (1 << 1) /* Power Down Cal Tcf */
+#define POWER_DOWN_VCO_BUFFFER (1 << 0) /* Power Down VCO Bufffer */
+
+/*
+* REG_RX_CP_OVERRANGE_VCO_LOCK
+*/
+#define CP_OVRG_HIGH (1 << 7) /* CP Ovrg High */
+#define CP_OVRG_LOW (1 << 6) /* CP Ovrg Low */
+#define VCO_LOCK (1 << 1) /* Lock */
+
+/*
+* REG_RX_VCO_LDO
+*/
+#define VCO_LDO_BYPASS (1 << 7) /* VCO LDO Bypass */
+#define VCO_LDO_INRUSH(x) (((x) & 0x3) << 5) /* VCO LDO Inrush<1:0> */
+#define VCO_LDO_SEL(x) (((x) & 0x7) << 2) /* VCO LDO Sel<2:0> */
+#define VCO_LDO_VDROP_SEL(x) (((x) & 0x3) << 0) /* VCO LDO Vdrop Sel<1:0> */
+
+/*
+* REG_RX_VCO_CAL
+*/
+#define VCO_CAL_EN (1 << 7) /* VCO Cal En */
+#define VCO_CAL_ALC_WAIT(x) (((x) & 0x7) << 4) /* VCO Cal ALC Wait <2:0> */
+#define VCO_CAL_COUNT(x) (((x) & 0x3) << 2) /* VCO Cal Count <1:0> */
+
+/*
+* REG_RX_LOCK_DETECT_CONFIG
+*/
+#define LOCK_DETECT_COUNT(x) (((x) & 0x3) << 2) /* Lock Detect Count<1:0> */
+#define LOCK_DETECT_MODE(x) (((x) & 0x3) << 0) /* Lock Detect Mode<1:0> */
+
+/*
+* REG_RX_CP_LEVEL_DETECT
+*/
+#define CP_LEVEL_DETECT_POWER_DOWN (1 << 6) /* CP Level Detect Power Down */
+#define CP_LEVEL_THRESH_LOW(x) (((x) & 0x7) << 3) /* CP Level Threshold Low<2:0> */
+#define CP_LEVEL_THRESH_HIGH(x) (((x) & 0x7) << 0) /* CP Level Threshold High<2:0> */
+
+/*
+* REG_RX_DSM_SETUP_0
+*/
+#define DSM_PROG(x) (((x) & 0xF) << 0) /* DSM Prog<3:0> */
+
+/*
+* REG_RX_DSM_SETUP_1
+*/
+#define SIF_CLOCK (1 << 6) /* SIF clock */
+#define SIF_RESET_BAR (1 << 5) /* SIF Reset Bar */
+#define SIF_ADDR(x) (((x) & 0x1F) << 0) /* SIF Addr<4:0> */
+
+/*
+* REG_RX_CORRECTION_WORD0
+*/
+#define UPDATE_FREQ_WORD (1 << 7) /* Update Freq Word */
+#define READ_EFFECTIVE_TUNING_WORD (1 << 5) /* Read Effective Tuning Word */
+#define FREQ_CORRECTION_WORD_MSB(x) (((x) & 0x1F) << 0) /* Frequency Correction Word<11:7> */
+
+/*
+* REG_RX_CORRECTION_WORD1
+*/
+#define UPDATE_FREQ_WORD (1 << 7) /* Update Freq Word */
+#define FREQ_CORRECTION_WORD_LSB(x) (((x) & 0x7F) << 0) /* Frequency Correction Word<6:0> */
+
+/*
+* REG_RX_VCO_VARACTOR_CTRL_0
+*/
+#define VCO_VARACTOR_REFERENCE_TCF(x) (((x) & 0x7) << 4) /* VCO Varactor Reference Tcf<2:0> */
+#define VCO_VARACTOR_OFFSET(x) (((x) & 0xF) << 0) /* VCO Varactor Offset<3:0> */
+
+/*
+* REG_RX_VCO_VARACTOR_CTRL_1
+*/
+#define VCO_VARACTOR_REFERENCE(x) (((x) & 0xF) << 0) /* VCO Varactor Reference<3:0> */
+
+/*
+* REG_RX_FAST_LOCK_SETUP
+*/
+#define RX_FAST_LOCK_LOAD_SYNTH (1 << 3) /* Rx Fast Lock Load Synth */
+#define RX_FAST_LOCK_PROFILE_INIT (1 << 2) /* Rx Fast Lock Profile Init */
+#define RX_FAST_LOCK_PROFILE_PIN_SELECT (1 << 1) /* Rx Fast Lock Profile Pin Select */
+#define RX_FAST_LOCK_MODE_ENABLE (1 << 0) /* Rx Fast Lock Mode Enable */
+#define RX_FAST_LOCK_PROFILE(x) (((x) & 0x7) << 5) /* Rx Fast Lock Profile<2:0> */
+
+/*
+* REG_RX_FAST_LOCK_PROGRAM_ADDR
+*/
+#define RX_FAST_LOCK_PROFILE_ADDR(x) (((x) & 0x7) << 4) /* Rx Fast Lock Profile<2:0> */
+#define RX_FAST_LOCK_PROFILE_WORD(x) (((x) & 0xF) << 0) /* Configuration Word <3:0> */
+
+
+/*
+* REG_RX_FAST_LOCK_PROGRAM_CTRL
+*/
+#define RX_FAST_LOCK_PROGRAM_WRITE (1 << 1) /* Rx Fast Lock Program Write */
+#define RX_FAST_LOCK_PROGRAM_CLOCK_ENABLE (1 << 0) /* Rx Fast Lock Program Clock Enable */
+
+#define RX_FAST_LOCK_CONFIG_WORD_NUM 16
+
+/*
+* REG_RX_LO_GEN_POWER_MODE
+*/
+#define RX_LO_GEN_POWER_MODE(x) (((x) & 0x3) << 4) /* Power Mode<3:0> */
+
+/*
+* REG_TX_PFD_CONFIG
+*/
+#define DIV_TEST_EN (1 << 5) /* Div Test En */
+#define PFD_CLK_EDGE (1 << 1) /* PFD Clk Edge */
+#define BYPASS_LD_SYNTH (1 << 0) /* Bypass Ld Synth */
+#define PFD_WIDTH(x) (((x) & 0x3) << 2) /* PFD Width <1:0> */
+
+/*
+* REG_TX_INTEGER_BYTE_1
+*/
+#define SDM_BYPASS (1 << 7) /* SDM Bypass */
+#define SDM_POWER_DOWN (1 << 6) /* SDM Power Down */
+#define SYNTH_INTEGER_WORD(x) (((x) & 0x7) << 0) /* Synthesizer Integer Word<10:8> */
+
+/*
+* REG_TX_FRACT_BYTE_2
+*/
+#define SYNTH_FRACT_WORD(x) (((x) & 0x7F) << 0) /* Synthesizer Fractional Word <22:16> */
+
+/*
+* REG_TX_FORCE_ALC
+*/
+#define FORCE_ALC_ENABLE (1 << 7) /* Force ALC Enable */
+#define FORCE_ALC_WORD(x) (((x) & 0x7F) << 0) /* Force ALC Word<6:0> */
+
+/*
+* REG_TX_FORCE_VCO_TUNE_1
+*/
+#define BYPASS_LOAD_DELAY (1 << 7) /* Bypass Load Delay */
+#define FORCE_VCO_TUNE_ENABLE (1 << 1) /* Force VCO Tune Enable */
+#define FORCE_VCO_TUNE (1 << 0) /* Force VCO Tune */
+#define VCO_CAL_OFFSET(x) (((x) & 0xF) << 3) /* VCO Cal Offset<3:0> */
+
+/*
+* REG_TX_ALCVARACT_OR
+*/
+#define INIT_ALC_VALUE(x) (((x) & 0xF) << 4) /* Init ALC Value<3:0> */
+#define VCO_VARACTOR(x) (((x) & 0xF) << 0) /* VCO Varactor<3:0> */
+
+/*
+* REG_TX_VCO_OUTPUT
+*/
+#define PORB_VCO_LOGIC (1 << 6) /* PORb VCO Logic */
+#define VCO_OUTPUT_LEVEL(x) (((x) & 0xF) << 0) /* VCO Output Level<3:0> */
+
+/*
+* REG_TX_CP_CURRENT
+*/
+#define TX_CP_CURRENT_DFLT (1 << 7) /* Set to 1 */
+#define VTUNE_FORCE (1 << 6) /* Vtune Force */
+#define CHARGE_PUMP_CURRENT(x) (((x) & 0x3F) << 0) /* Charge Pump Current<5:0> */
+
+/*
+* REG_TX_CP_OFFSET
+*/
+#define SYNTH_RECAL (1 << 7) /* Synth Re-Cal */
+#define CHARGE_PUMP_OFFSET(x) (((x) & 0x3F) << 0) /* Charge Pump Offset<5:0> */
+
+/*
+* REG_TX_CP_CONFIG
+*/
+#define HALF_VCO_CAL_CLK (1 << 7) /* Half Vco Cal Clk */
+#define DITHER_MODE (1 << 6) /* Dither Mode */
+#define CP_OFFSET_OFF (1 << 4) /* Cp Offset Off */
+#define F_CPCAL (1 << 3) /* F Cpcal */
+#define CP_CAL_ENABLE (1 << 2) /* Cp Cal Enable */
+#define CP_TEST(x) (((x) & 0x3) << 0) /* Cp Test <1:0> */
+
+/*
+* REG_TX_LOOP_FILTER_1
+*/
+#define LOOP_FILTER_C2(x) (((x) & 0xF) << 4) /* Loop Filter C2<3:0> */
+#define LOOP_FILTER_C1(x) (((x) & 0xF) << 0) /* Loop Filter C1<3:0> */
+
+/*
+* REG_TX_LOOP_FILTER_2
+*/
+#define LOOP_FILTER_R1(x) (((x) & 0xF) << 4) /* Loop Filter R1<3:0> */
+#define LOOP_FILTER_C3(x) (((x) & 0xF) << 0) /* Loop Filter C3<3:0> */
+
+/*
+* REG_TX_LOOP_FILTER_3
+*/
+#define LOOP_FILTER_BYPASS_R3 (1 << 7) /* Loop Filter Bypass R3 */
+#define LOOP_FILTER_BYPASS_R1 (1 << 6) /* Loop Filter Bypass R1 */
+#define LOOP_FILTER_BYPASS_C2 (1 << 5) /* Loop Filter Bypass C2 */
+#define LOOP_FILTER_BYPASS_C1 (1 << 4) /* Loop Filter Bypass C1 */
+#define LOOP_FILTER_R3(x) (((x) & 0xF) << 0) /* Loop Filter R3<3:0> */
+
+/*
+* REG_TX_DITHERCP_CAL
+*/
+#define NUMBER_SDM_DITHER_BITS(x) (((x) & 0xF) << 4) /* Number SDM Dither Bits<3:0> */
+#define FORCED_CP_CAL_WORD(x) (((x) & 0xF) << 0) /* Forced CP Cal Word<3:0> */
+
+/*
+* REG_TX_VCO_BIAS_1
+*/
+#define MUST_BE_ZEROS(x) (((x) & 0x3) << 5) /* Must be zeros */
+#define VCO_BIAS_TCF(x) (((x) & 0x3) << 3) /* VCO Bias Tcf<1:0> */
+#define VCO_BIAS_REF(x) (((x) & 0x7) << 0) /* VCO Bias Ref<2:0> */
+
+/*
+* REG_TX_VCO_BIAS_2
+*/
+#define VCO_BYPASS_BIAS_DAC_R (1 << 7) /* VCO Bypass Bias DAC R */
+#define VCO_COMP_BYPASS_BIAS_R (1 << 4) /* VCO Comp Bypass Bias R */
+#define BYPASS_PRESCALE_R (1 << 3) /* Bypass Prescale R */
+#define LAST_ALC_ENABLE (1 << 2) /* Last ALC Enable */
+#define PRESCALE_BIAS(x) (((x) & 0x3) << 0) /* Prescale Bias <1:0> */
+
+/*
+* REG_TX_CAL_STATUS
+*/
+#define CP_CAL_VALID (1 << 7) /* CP Cal Valid */
+#define COMP_OUT (1 << 6) /* Comp Out */
+#define CP_CAL_DONE (1 << 5) /* CP Cal Done */
+#define VCO_CAL_BUSY (1 << 4) /* VCO Cal Busy */
+#define CP_CAL_WORD(x) (((x) & 0xF) << 0) /* CP Cal Word<3:0> */
+
+/*
+* REG_TX_VCO_CAL_REF
+*/
+#define VCO_CAL_REF_MONITOR (1 << 3) /* VCO Cal Ref Monitor */
+#define VCO_CAL_REF_TCF(x) (((x) & 0x7) << 0) /* VCO Cal Ref Tcf<2:0> */
+
+/*
+* REG_TX_VCO_PD_OVERRIDES
+*/
+#define POWER_DOWN_VARACTOR_REF (1 << 3) /* Power Down Varactor Ref */
+#define POWER_DOWN_VARACT_REF_TCF (1 << 2) /* Power Down Varact Ref Tcf */
+#define POWER_DOWN_CAL_TCF (1 << 1) /* Power Down Cal Tcf */
+#define POWER_DOWN_VCO_BUFFFER (1 << 0) /* Power Down VCO Bufffer */
+
+/*
+* REG_TX_CP_OVERRANGE_VCO_LOCK
+*/
+#define CP_OVRG_HIGH (1 << 7) /* CP Ovrg High */
+#define CP_OVRG_LOW (1 << 6) /* CP Ovrg Low */
+#define VCO_LOCK (1 << 1) /* Lock */
+
+/*
+* REG_TX_VCO_LDO
+*/
+#define VCO_LDO_BYPASS (1 << 7) /* VCO LDO Bypass */
+#define VCO_LDO_INRUSH(x) (((x) & 0x3) << 5) /* VCO LDO Inrush<1:0> */
+#define VCO_LDO_VOUT_SEL(x) (((x) & 0x7) << 2) /* VCO LDO Vout Sel<2:0> */
+#define VCO_LDO_VDROP_SEL(x) (((x) & 0x3) << 0) /* VCO LDO Vdrop Sel<1:0> */
+
+/*
+* REG_TX_VCO_CAL
+*/
+#define VCO_CAL_EN (1 << 7) /* VCO Cal En */
+#define VCO_CAL_ALC_WAIT(x) (((x) & 0x7) << 4) /* VCO Cal ALC Wait<2:0) */
+#define VCO_CAL_COUNT(x) (((x) & 0x3) << 2) /* VCO Cal Count<1:0> */
+#define FB_CLOCK_ADV(x) (((x) & 0x3) << 0) /* FB Clock Adv<1:0> */
+
+/*
+* REG_TX_LOCK_DETECT_CONFIG
+*/
+#define LOCK_DETECT_COUNT(x) (((x) & 0x3) << 2) /* Lock Detect Count<1:0> */
+#define LOCK_DETECT_MODE(x) (((x) & 0x3) << 0) /* Lock Detect Mode<1:0> */
+
+/*
+* REG_TX_CP_LEVEL_DETECT
+*/
+#define CP_LEVEL_DETECT_POWER_DOWN (1 << 6) /* CP Level Detect Power Down */
+#define CP_LEVEL_DETECT_THRESH_LOW(x) (((x) & 0x7) << 3) /* CP Level Detect Threshold Low<2:0> */
+#define CP_LEVEL_DETECT_THRESH_HIGH(x) (((x) & 0x7) << 0) /* CP Level Detect Threshold High<2:0> */
+
+/*
+* REG_TX_DSM_SETUP_0
+*/
+#define DSM_PROG(x) (((x) & 0xF) << 0) /* DSM Prog<3:0> */
+
+/*
+* REG_TX_DSM_SETUP_1
+*/
+#define SIF_CLOCK (1 << 6) /* SIF clock */
+#define SIF_RESET_BAR (1 << 5) /* SIF Reset Bar */
+#define SIF_ADDR(x) (((x) & 0x1F) << 0) /* SIF Addr<4:0> */
+
+/*
+* REG_TX_CORRECTION_WORD0
+*/
+#define UPDATE_FREQ_WORD (1 << 7) /* Update Freq Word */
+#define READ_EFFECTIVE_TUNING_WORD (1 << 5) /* Read Effective Tuning Word */
+#define FREQ_CORRECTION_WORD_MSB(x) (((x) & 0x1F) << 0) /* Frequency Correction Word<11:7> */
+
+/*
+* REG_TX_CORRECTION_WORD1
+*/
+#define UPDATE_FREQ_WORD (1 << 7) /* Update Freq Word */
+#define FREQ_CORRECTION_WORD_LSB(x) (((x) & 0x7F) << 0) /* Frequency Correction Word<6:0> */
+
+/*
+* REG_TX_VCO_VARACTOR_CTRL_0
+*/
+#define VCO_VARACTOR_REFERENCE_TCF(x) (((x) & 0x7) << 4) /* VCO Varactor Reference Tcf<2:0> */
+#define VCO_VARACTOR_OFFSET(x) (((x) & 0xF) << 0) /* VCO Varactor Offset<3:0> */
+
+/*
+* REG_TX_VCO_VARACTOR_CTRL_1
+*/
+#define VCO_VARACTOR_REFERENCE(x) (((x) & 0xF) << 0) /* VCO Varactor Reference<3:0> */
+
+/*
+* REG_DCXO_COARSE_TUNE
+*/
+#define DCXO_TUNE_COARSE(x) (((x) & 0x3F) << 0) /* DCXO Tune Coarse<5:0> */
+
+/*
+* REG_DCXO_FINE_TUNE_LOW
+*/
+#define DCXO_TUNE_FINE_LOW(x) (((x) & 0x1F) << 3) /* DCXO Tune Fine<4:0> */
+
+/*
+* REG_DCXO_FINE_TUNE_HIGH
+*/
+#define DCXO_TUNE_FINE_HIGH(x) ((x) >> 5) /* DCXO Tune Fine<12:5> */
+
+/*
+* REG_DCXO_CONFIG
+*/
+#define MUST_BE_ZERO (1 << 7) /* Must be zero */
+#define DCXO_RTAIL(x) (((x) & 0x7) << 4) /* DCXO Rtail<2:0> */
+#define DCXO_RD(x) (((x) & 0x3) << 2) /* DCXO Rd<1:0> */
+
+/*
+* REG_DCXO_TEMPCO_ADDR
+*/
+#define DCXO_TEMPCO_EN (1 << 7) /* DCXO Tempco En */
+#define DCXO_TEMPCO_CLK (1 << 6) /* DCXO Tempco Clk */
+#define DCXO_TEMPERATURE_COEF_ADDRESS(x) (((x) & 0x3F) << 0) /* DCXO Temperature Coefficient Address<5:0> */
+
+/*
+* REG_TX_FAST_LOCK_SETUP
+*/
+#define TX_FAST_LOCK_LOAD_SYNTH (1 << 3) /* Tx Fast Lock Load Synth */
+#define TX_FAST_LOCK_PROFILE_INIT (1 << 2) /* Tx Fast Lock Profile Init */
+#define TX_FAST_LOCK_PROFILE_PIN_SELECT (1 << 1) /* Tx Fast Lock Profile Pin Select */
+#define TX_FAST_LOCK_MODE_ENABLE (1 << 0) /* Tx Fast Lock Mode Enable */
+#define TX_FAST_LOCK_PROFILE(x) (((x) & 0x7) << 5) /* Tx Fast Lock Profile<2:0> */
+
+/*
+* REG_TX_FAST_LOCK_PROGRAM_CTRL
+*/
+#define TX_FAST_LOCK_PROGRAM_WRITE (1 << 1) /* Tx Fast Lock Program Write */
+#define TX_FAST_LOCK_PROGRAM_CLOCK_ENABLE (1 << 0) /* Tx Fast Lock Program Clock Enable */
+
+/*
+* REG_TX_LO_GEN_POWER_MODE
+*/
+#define TX_LO_GEN_POWER_MODE(x) (((x) & 0xF) << 4) /* Power Mode<3:0> */
+
+/*
+* REG_BANDGAP_CONFIG0
+*/
+#define POWER_DOWN_BANDGAP_REF (1 << 7) /* Power Down Bandgap Ref */
+#define MASTER_BIAS_FILTER_BYPASS (1 << 6) /* Master Bias Filter Bypass */
+#define MASTER_BIAS_REF_SEL (1 << 5) /* Master Bias Ref Sel */
+#define MASTER_BIAS_TRIM(x) (((x) & 0x1F) << 0) /* Master Bias Trim<4:0> */
+
+/*
+* REG_BANDGAP_CONFIG1
+*/
+#define VCO_LDO_FILTER_BYPASS (1 << 7) /* VCO LDO Filter Bypass */
+#define VCO_LDO_REF_SEL (1 << 6) /* VCO LDO Ref Sel */
+#define BANDGAP_REF_RESET (1 << 5) /* Bandgap Ref Reset */
+#define BANDGAP_TEMP_TRIM(x) (((x) & 0x1F) << 0) /* Bandgap Temp Trim<4:0> */
+
+/*
+* REG_REF_DIVIDE_CONFIG_1
+*/
+#define REF_DIVIDE_CONFIG_1_DFLT (1 << 2) /* Set to 1 */
+#define RX_REF_RESET_BAR (1 << 1) /* Rx Ref Reset Bar */
+#define RX_REF_DIVIDER_MSB (1 << 0) /* Rx Ref Divider<1> */
+
+/*
+* REG_REF_DIVIDE_CONFIG_2
+*/
+#define RX_REF_DIVIDER_LSB (1 << 7) /* Rx Ref Divider< 0> */
+#define TX_REF_RESET_BAR (1 << 4) /* Tx Ref Reset Bar */
+#define RX_REF_DOUBLER_FB_DELAY(x) (((x) & 0x3) << 5) /* Rx Ref Doubler FB Delay<1:0> */
+#define TX_REF_DIVIDER(x) (((x) & 0x3) << 2) /* Tx Ref Divider<1:0> */
+#define TX_REF_DOUBLER_FB_DELAY(x) (((x) & 0x3) << 0) /* Tx Ref Doubler FB Delay<1:0> */
+
+/*
+* REG_GAIN_RX1,2
+*/
+#define FULL_TABLE_GAIN_INDEX(x) (((x) & 0x7F) << 0) /* Full Table Gain Index Rx1/LMT Gain Rx1<6:0> */
+
+/*
+* REG_LPF_GAIN_RX1,2
+*/
+#define LPF_GAIN_RX(x) (((x) & 0x1F) << 0) /* LPF gain Rx1<4:0> */
+
+/*
+* REG_DIG_GAIN_RX1,2
+*/
+#define DIGITAL_GAIN_RX(x) (((x) & 0x1F) << 0) /* Digital gain Rx1<4:0> */
+
+/*
+* REG_FAST_ATTACK_STATE
+*/
+#define FAST_ATTACK_STATE_RX2(x) (((x) & 0x7) << 4) /* Fast Attack State Rx2<2:0> */
+#define FAST_ATTACK_STATE_RX1(x) (((x) & 0x7) << 0) /* Fast Attack State Rx1<2:0> */
+#define FAST_ATK_MASK 0x7
+#define RX1_FAST_ATK_SHIFT 0
+#define RX2_FAST_ATK_SHIFT 4
+#define FAST_ATK_RESET 0
+#define FAST_ATK_PEAK_DETECT 1
+#define FAST_ATK_PWR_MEASURE 2
+#define FAST_ATK_FINAL_SETTELING 3
+#define FAST_ATK_FINAL_OVER 4
+#define FAST_ATK_GAIN_LOCKED 5
+
+/*
+* REG_SLOW_LOOP_STATE
+*/
+#define SLOW_LOOP_STATE_RX2(x) (((x) & 0x7) << 4) /* Slow Loop State Rx2<2:0> */
+#define SLOW_LOOP_STATE_RX1(x) (((x) & 0x7) << 0) /* Slow Loop State Rx1<2:0> */
+
+
+/*
+* REG_OVRG_SIGS_RX1,2
+*/
+#define GAIN_LOCK_1 (1 << 6) /* Gain Lock 1 */
+#define LOW_POWER_1 (1 << 5) /* Low Power 1 */
+#define LARGE_LMT_OL (1 << 4) /* Large LMT OL */
+#define SMALL_LMT_OL (1 << 3) /* Small LMT OL */
+#define LARGE_ADC_OL (1 << 2) /* Large ADC OL */
+#define SMALL_ADC_OL (1 << 1) /* Small ADC OL */
+#define DIG_SAT (1 << 0) /* Dig Sat */
+/*
+* REG_CTRL
+*/
+#define CTRL_ENABLE (1 << 0) /* Set to 1 */
+
+/*
+* REG_BIST_CONFIG
+*/
+#define TONE_PRBS (1 << 1) /* Tone/ PRBS */
+#define BIST_ENABLE (1 << 0) /* BIST Enable */
+#define TONE_FREQ(x) (((x) & 0x3) << 6) /* Tone Frequency<1:0> */
+#define TONE_LEVEL(x) (((x) & 0x3) << 4) /* Tone Level<1:0> */
+#define BIST_CTRL_POINT(x) (((x) & 0x3) << 2) /* BIST Control Point <1:0> */
+
+/*
+* REG_OBSERVE_CONFIG
+*/
+#define DATA_PORT_SP_HD_LOOP_TEST_OE (1 << 7) /* Data Port SP, HD Loop Test OE */
+#define RX_MASK (1 << 6) /* Rx Mask */
+#define CHANNEL (1 << 5) /* Channel */
+#define DATA_PORT_LOOP_TEST_ENABLE (1 << 0) /* Data Port Loop Test Enable */
+#define OBSERVATION_POINT(x) (((x) & 0xF) << 1) /* Observation Point<2:0> */
+
+/*
+* REG_BIST_AND_DATA_PORT_TEST_CONFIG
+*/
+#define BIST_MASK_CHANNEL_2_Q_DATA (1 << 5) /* BIST Mask Channel 2 Q data */
+#define BIST_MASK_CHANNEL_2_I_DATA (1 << 4) /* BIST Mask Channel 2 I data */
+#define BIST_MASK_CHANNEL_1_Q_DATA (1 << 3) /* BIST Mask Channel 1 Q data */
+#define BIST_MASK_CHANNEL_1_I_DATA (1 << 2) /* BIST Mask Channel 1 I data */
+#define DATA_PORT_HILOW (1 << 1) /* Data Port Hi/Low */
+#define USE_DATA_PORT (1 << 0) /* Use Data Port */
+#define TEMP_SENSE_VBE_TEST(x) (((x) & 0x3) << 6) /* Temp Sense Vbe Test<1:0> */
+
+/*
+* REG_DAC_TEST_2
+*/
+#define DAC_TEST_ENABLE (1 << 7) /* DAC Test Enable */
+#define DAC_TEST_WORD(x) (((x) & 0x7F) << 0) /* DAC test Word <22:16> */
+
+/*
+* SPI Comm Helpers
+*/
+#define AD_READ (0 << 15)
+#define AD_WRITE (1 << 15)
+#define AD_CNT(x) ((((x) - 1) & 0x7) << 12)
+#define AD_ADDR(x) ((x) & 0x3FF)
+
+
+/*
+* AD9361 Limits
+*/
+
+#define RSSI_MULTIPLIER 100
+#define RSSI_RESOLUTION ((int) (0.25 * RSSI_MULTIPLIER))
+#define RSSI_MAX_WEIGHT 255
+
+#define MAX_LMT_INDEX 40
+#define MAX_LPF_GAIN 24
+#define MAX_DIG_GAIN 31
+
+#define MAX_BBPLL_FREF 70000000UL /* 70 MHz */
+#define MIN_BBPLL_FREQ 715000000UL /* 715 MHz */
+#define MAX_BBPLL_FREQ 1430000000UL /* 1430 MHz */
+#define MAX_BBPLL_DIV 64
+#define MIN_BBPLL_DIV 2
+
+/*
+ * The ADC minimum and maximum operating output data rates
+ * are 25MHz and 640MHz respectively.
+ * For more information see here: https://ez.analog.com/docs/DOC-12763
+ */
+
+#define MIN_ADC_CLK 25000000UL /* 25 MHz */
+//#define MIN_ADC_CLK (MIN_BBPLL_FREQ / MAX_BBPLL_DIV) /* 11.17MHz */
+#define MAX_ADC_CLK 640000000UL /* 640 MHz */
+#define MAX_DAC_CLK (MAX_ADC_CLK / 2)
+
+#define MAX_MBYTE_SPI 8
+
+#define RFPLL_MODULUS 8388593UL
+#define BBPLL_MODULUS 2088960UL
+
+#define MAX_SYNTH_FREF 80000000UL /* 80 MHz */
+#define MIN_SYNTH_FREF 10000000UL /* 10 MHz */
+#define MIN_VCO_FREQ_HZ 6000000000ULL
+#define MAX_CARRIER_FREQ_HZ 6000000000ULL
+#define MIN_CARRIER_FREQ_HZ 47000000ULL /* Nuand modification */
+
+#define AD9363A_MAX_CARRIER_FREQ_HZ 3800000000ULL
+#define AD9363A_MIN_CARRIER_FREQ_HZ 325000000ULL
+
+/*
+* Driver
+*/
+
+enum rx_gain_table_type {
+ RXGAIN_FULL_TBL,
+ RXGAIN_SPLIT_TBL,
+};
+
+enum rx_gain_table_name {
+ TBL_200_1300_MHZ,
+ TBL_1300_4000_MHZ,
+ TBL_4000_6000_MHZ,
+ RXGAIN_TBLS_END,
+};
+
+enum fir_dest {
+ FIR_TX1 = 0x01,
+ FIR_TX2 = 0x02,
+ FIR_TX1_TX2 = 0x03,
+ FIR_RX1 = 0x81,
+ FIR_RX2 = 0x82,
+ FIR_RX1_RX2 = 0x83,
+ FIR_IS_RX = 0x80,
+};
+
+struct rf_gain_ctrl {
+ uint32_t ant;
+ uint8_t mode;
+};
+
+enum rf_gain_ctrl_mode {
+ RF_GAIN_MGC,
+ RF_GAIN_FASTATTACK_AGC,
+ RF_GAIN_SLOWATTACK_AGC,
+ RF_GAIN_HYBRID_AGC
+};
+
+enum f_agc_target_gain_index_type {
+ MAX_GAIN,
+ SET_GAIN,
+ OPTIMIZED_GAIN,
+ NO_GAIN_CHANGE,
+};
+
+struct gain_control {
+ enum rf_gain_ctrl_mode rx1_mode;
+ enum rf_gain_ctrl_mode rx2_mode;
+
+ /* Common */
+ uint8_t adc_ovr_sample_size; /* 1..8 Sum x samples, AGC_CONFIG_3 */
+ uint8_t adc_small_overload_thresh; /* 0..255, 0x105 */
+ uint8_t adc_large_overload_thresh; /* 0..255, 0x104 */
+
+ uint16_t lmt_overload_high_thresh; /* 16..800 mV, 0x107 */
+ uint16_t lmt_overload_low_thresh; /* 16..800 mV, 0x108 */
+ uint16_t dec_pow_measuremnt_duration; /* Samples, 0x15C */
+ uint8_t low_power_thresh; /* -64..0 dBFS, 0x114 */
+
+ bool dig_gain_en; /* should be turned off, since ADI GT doesn't use dig gain */
+ uint8_t max_dig_gain; /* 0..31 */
+
+ /* MGC */
+ bool mgc_rx1_ctrl_inp_en; /* Enables Pin control on RX1 default SPI ctrl */
+ bool mgc_rx2_ctrl_inp_en; /* Enables Pin control on RX2 default SPI ctrl */
+
+ uint8_t mgc_inc_gain_step; /* 1..8 */
+ uint8_t mgc_dec_gain_step; /* 1..8 */
+ uint8_t mgc_split_table_ctrl_inp_gain_mode; /* 0=AGC determine this, 1=only in LPF, 2=only in LMT */
+
+ /* AGC */
+ uint8_t agc_attack_delay_extra_margin_us; /* 0..31 us */
+
+ uint8_t agc_outer_thresh_high;
+ uint8_t agc_outer_thresh_high_dec_steps;
+ uint8_t agc_inner_thresh_high;
+ uint8_t agc_inner_thresh_high_dec_steps;
+ uint8_t agc_inner_thresh_low;
+ uint8_t agc_inner_thresh_low_inc_steps;
+ uint8_t agc_outer_thresh_low;
+ uint8_t agc_outer_thresh_low_inc_steps;
+
+ uint8_t adc_small_overload_exceed_counter; /* 0..15, 0x122 */
+ uint8_t adc_large_overload_exceed_counter; /* 0..15, 0x122 */
+ uint8_t adc_large_overload_inc_steps; /* 0..15, 0x106 */
+
+ bool adc_lmt_small_overload_prevent_gain_inc; /* 0x120 */
+
+ uint8_t lmt_overload_large_exceed_counter; /* 0..15, 0x121 */
+ uint8_t lmt_overload_small_exceed_counter; /* 0..15, 0x121 */
+ uint8_t lmt_overload_large_inc_steps; /* 0..7, 0x121 */
+
+ uint8_t dig_saturation_exceed_counter; /* 0..15, 0x128 */
+ uint8_t dig_gain_step_size; /* 1..8, 0x100 */
+ bool sync_for_gain_counter_en; /* 0x128:4 !Hybrid */
+
+ uint32_t gain_update_interval_us; /* in us */
+ bool immed_gain_change_if_large_adc_overload; /* 0x123:3 */
+ bool immed_gain_change_if_large_lmt_overload; /* 0x123:7 */
+
+ /*
+ * Fast AGC
+ */
+ uint32_t f_agc_dec_pow_measuremnt_duration; /* Samples, 0x15C */
+ uint32_t f_agc_state_wait_time_ns; /* 0x117 0..31 RX samples -> time_ns */
+ /* Fast AGC - Low Power */
+ bool f_agc_allow_agc_gain_increase; /* 0x110:1 */
+ uint8_t f_agc_lp_thresh_increment_time; /* 0x11B RX samples */
+ uint8_t f_agc_lp_thresh_increment_steps; /* 0x117 1..8 */
+
+ /* Fast AGC - Lock Level */
+ uint8_t f_agc_lock_level; /* 0x101 0..-127 dBFS */
+ bool f_agc_lock_level_lmt_gain_increase_en; /* 0x111:6 */
+ uint8_t f_agc_lock_level_gain_increase_upper_limit; /* 0x118 0..63 */
+ /* Fast AGC - Peak Detectors and Final Settling */
+ uint8_t f_agc_lpf_final_settling_steps; /* 0x112:6 0..3 (Post Lock Level Step)*/
+ uint8_t f_agc_lmt_final_settling_steps; /* 0x113:6 0..3 (Post Lock Level Step)*/
+ uint8_t f_agc_final_overrange_count; /* 0x116:5 0..7 */
+ /* Fast AGC - Final Power Test */
+ bool f_agc_gain_increase_after_gain_lock_en; /* 0x110:7 */
+ /* Fast AGC - Unlocking the Gain */
+ /* 0 = MAX Gain, 1 = Set Gain, 2 = Optimized Gain */
+ enum f_agc_target_gain_index_type f_agc_gain_index_type_after_exit_rx_mode; /* 0x110:[4,2] */
+ bool f_agc_use_last_lock_level_for_set_gain_en; /* 0x111:7 */
+ uint8_t f_agc_optimized_gain_offset; /*0x116 0..15 steps */
+ bool f_agc_rst_gla_stronger_sig_thresh_exceeded_en; /* 0x110:~6 */
+ uint8_t f_agc_rst_gla_stronger_sig_thresh_above_ll; /*0x113 0..63 dbFS */
+ bool f_agc_rst_gla_engergy_lost_sig_thresh_exceeded_en; /* 0x110:6 */
+ bool f_agc_rst_gla_engergy_lost_goto_optim_gain_en; /* 0x110:6 */
+ uint8_t f_agc_rst_gla_engergy_lost_sig_thresh_below_ll; /* 0x112:6 */
+ uint8_t f_agc_energy_lost_stronger_sig_gain_lock_exit_cnt; /* 0x119 0..63 RX samples */
+ bool f_agc_rst_gla_large_adc_overload_en; /*0x110:~1 and 0x114:~7 */
+ bool f_agc_rst_gla_large_lmt_overload_en; /*0x110:~1 */
+ bool f_agc_rst_gla_en_agc_pulled_high_en;
+ /* 0 = Max Gain, 1 = Set Gain, 2 = Optimized Gain, 3 = No Gain Change */
+
+ enum f_agc_target_gain_index_type f_agc_rst_gla_if_en_agc_pulled_high_mode; /* 0x0FB, 0x111 */
+ uint8_t f_agc_power_measurement_duration_in_state5; /* 0x109, 0x10a RX samples 0..524288*/
+
+};
+
+struct auxdac_control {
+ uint16_t dac1_default_value;
+ uint16_t dac2_default_value;
+
+ bool auxdac_manual_mode_en;
+
+ bool dac1_in_rx_en;
+ bool dac1_in_tx_en;
+ bool dac1_in_alert_en;
+
+ bool dac2_in_rx_en;
+ bool dac2_in_tx_en;
+ bool dac2_in_alert_en;
+
+ uint8_t dac1_rx_delay_us;
+ uint8_t dac1_tx_delay_us;
+ uint8_t dac2_rx_delay_us;
+ uint8_t dac2_tx_delay_us;
+};
+
+enum rssi_restart_mode {
+ AGC_IN_FAST_ATTACK_MODE_LOCKS_THE_GAIN,
+ EN_AGC_PIN_IS_PULLED_HIGH,
+ ENTERS_RX_MODE,
+ GAIN_CHANGE_OCCURS,
+ SPI_WRITE_TO_REGISTER,
+ GAIN_CHANGE_OCCURS_OR_EN_AGC_PIN_PULLED_HIGH,
+};
+
+struct rssi_control {
+ enum rssi_restart_mode restart_mode;
+ bool rssi_unit_is_rx_samples; /* default unit is time */
+ uint32_t rssi_delay;
+ uint32_t rssi_wait;
+ uint32_t rssi_duration;
+};
+
+struct rx_gain_info {
+ enum rx_gain_table_type tbl_type;
+ int32_t starting_gain_db;
+ int32_t max_gain_db;
+ int32_t gain_step_db;
+ int32_t max_idx;
+ int32_t idx_step_offset;
+};
+
+struct port_control {
+ uint8_t pp_conf[3];
+ uint8_t rx_clk_data_delay;
+ uint8_t tx_clk_data_delay;
+ uint8_t digital_io_ctrl;
+ uint8_t lvds_bias_ctrl;
+ uint8_t lvds_invert[2];
+#ifdef NUAND_MODIFICATIONS
+ // add digital interface drive and clock skew
+ uint8_t clk_out_drive;
+ uint8_t dataclk_drive;
+ uint8_t data_port_drive;
+ uint8_t clk_out_slew;
+ uint8_t dataclk_slew;
+ uint8_t data_port_slew;
+#endif // NUAND_MODIFICATIONS
+};
+
+struct ctrl_outs_control {
+ uint8_t index;
+ uint8_t en_mask;
+};
+
+struct elna_control {
+ uint16_t gain_mdB;
+ uint16_t bypass_loss_mdB;
+ uint32_t settling_delay_ns;
+ bool elna_1_control_en; /* GPO0 */
+ bool elna_2_control_en; /* GPO1 */
+ bool elna_in_gaintable_all_index_en;
+};
+
+struct auxadc_control {
+ int8_t offset;
+ uint32_t temp_time_inteval_ms;
+ uint32_t temp_sensor_decimation;
+ bool periodic_temp_measuremnt;
+ uint32_t auxadc_clock_rate;
+ uint32_t auxadc_decimation;
+};
+
+struct gpo_control {
+ bool gpo0_inactive_state_high_en;
+ bool gpo1_inactive_state_high_en;
+ bool gpo2_inactive_state_high_en;
+ bool gpo3_inactive_state_high_en;
+ bool gpo0_slave_rx_en;
+ bool gpo0_slave_tx_en;
+ bool gpo1_slave_rx_en;
+ bool gpo1_slave_tx_en;
+ bool gpo2_slave_rx_en;
+ bool gpo2_slave_tx_en;
+ bool gpo3_slave_rx_en;
+ bool gpo3_slave_tx_en;
+ uint8_t gpo0_rx_delay_us;
+ uint8_t gpo0_tx_delay_us;
+ uint8_t gpo1_rx_delay_us;
+ uint8_t gpo1_tx_delay_us;
+ uint8_t gpo2_rx_delay_us;
+ uint8_t gpo2_tx_delay_us;
+ uint8_t gpo3_rx_delay_us;
+ uint8_t gpo3_tx_delay_us;
+};
+
+struct tx_monitor_control {
+ bool tx_mon_track_en;
+ bool one_shot_mode_en;
+ uint32_t low_high_gain_threshold_mdB;
+ uint8_t low_gain_dB;
+ uint8_t high_gain_dB;
+ uint16_t tx_mon_delay;
+ uint16_t tx_mon_duration;
+ uint8_t tx1_mon_front_end_gain;
+ uint8_t tx2_mon_front_end_gain;
+ uint8_t tx1_mon_lo_cm;
+ uint8_t tx2_mon_lo_cm;
+};
+
+enum ad9361_pdata_rx_freq {
+ BBPLL_FREQ,
+ ADC_FREQ,
+ R2_FREQ,
+ R1_FREQ,
+ CLKRF_FREQ,
+ RX_SAMPL_FREQ,
+ NUM_RX_CLOCKS,
+};
+
+enum ad9361_pdata_tx_freq {
+#ifdef NUAND_MODIFICATIONS
+ // this is a name conflict on some platforms
+ IGNORE_FREQ,
+#else
+ IGNORE,
+#endif // NUAND_MODIFICATIONS
+ DAC_FREQ,
+ T2_FREQ,
+ T1_FREQ,
+ CLKTF_FREQ,
+ TX_SAMPL_FREQ,
+ NUM_TX_CLOCKS,
+};
+
+enum ad9361_clkout {
+ CLKOUT_DISABLE,
+ BUFFERED_XTALN_DCXO,
+ ADC_CLK_DIV_2,
+ ADC_CLK_DIV_3,
+ ADC_CLK_DIV_4,
+ ADC_CLK_DIV_8,
+ ADC_CLK_DIV_16,
+};
+
+struct ad9361_phy_platform_data {
+ bool rx2tx2;
+ bool fdd;
+ bool fdd_independent_mode;
+ bool split_gt;
+ bool use_extclk;
+ bool ensm_pin_pulse_mode;
+ bool ensm_pin_ctrl;
+ bool debug_mode;
+ bool tdd_use_dual_synth;
+ bool tdd_skip_vco_cal;
+ bool use_ext_rx_lo;
+ bool use_ext_tx_lo;
+ bool rx1rx2_phase_inversion_en;
+ bool qec_tracking_slow_mode_en;
+ uint8_t dc_offset_update_events;
+ uint8_t dc_offset_attenuation_high;
+ uint8_t dc_offset_attenuation_low;
+ uint8_t rf_dc_offset_count_high;
+ uint8_t rf_dc_offset_count_low;
+ uint8_t dig_interface_tune_skipmode;
+ uint8_t dig_interface_tune_fir_disable;
+ uint32_t dcxo_coarse;
+ uint32_t dcxo_fine;
+ uint32_t rf_rx_input_sel;
+ uint32_t rf_tx_output_sel;
+ uint32_t rx1tx1_mode_use_rx_num;
+ uint32_t rx1tx1_mode_use_tx_num;
+ uint32_t rx_path_clks[NUM_RX_CLOCKS];
+ uint32_t tx_path_clks[NUM_TX_CLOCKS];
+ uint32_t trx_synth_max_fref;
+ uint64_t rx_synth_freq;
+ uint64_t tx_synth_freq;
+ uint32_t rf_rx_bandwidth_Hz;
+ uint32_t rf_tx_bandwidth_Hz;
+ int32_t tx_atten;
+ bool update_tx_gain_via_alert;
+ uint32_t rx_fastlock_delay_ns;
+ uint32_t tx_fastlock_delay_ns;
+ bool trx_fastlock_pinctrl_en[2];
+
+ enum ad9361_clkout ad9361_clkout_mode;
+
+ struct gain_control gain_ctrl;
+ struct rssi_control rssi_ctrl;
+ struct port_control port_ctrl;
+ struct ctrl_outs_control ctrl_outs_ctrl;
+ struct elna_control elna_ctrl;
+ struct auxadc_control auxadc_ctrl;
+ struct auxdac_control auxdac_ctrl;
+ struct gpo_control gpo_ctrl;
+ struct tx_monitor_control txmon_ctrl;
+
+ int32_t gpio_resetb;
+ /* MCS SYNC */
+ int32_t gpio_sync;
+ int32_t gpio_cal_sw1;
+ int32_t gpio_cal_sw2;
+};
+
+struct rf_rx_gain {
+ uint32_t ant; /* Antenna number to read gain */
+ int32_t gain_db; /* gain value in dB */
+ uint32_t fgt_lmt_index; /* Full Gain Table / LNA-MIXER-TIA gain index */
+ uint32_t lmt_gain; /* LNA-MIXER-TIA gain in dB (Split GT mode only)*/
+ uint32_t lpf_gain; /* Low pass filter gain in dB / index (Split GT mode only)*/
+ uint32_t digital_gain; /* Digital gain in dB / index */
+ /* Debug only */
+ uint32_t lna_index; /* LNA Index (Split GT mode only) */
+ uint32_t tia_index; /* TIA Index (Split GT mode only) */
+ uint32_t mixer_index; /* MIXER Index (Split GT mode only) */
+
+};
+struct rf_rssi {
+ uint32_t ant; /* Antenna number for which RSSI is reported */
+ uint32_t symbol; /* Runtime RSSI */
+ uint32_t preamble; /* Initial RSSI */
+ int32_t multiplier; /* Multiplier to convert reported RSSI */
+ uint8_t duration; /* Duration to be considered for measuring */
+};
+
+struct SynthLUT {
+ uint16_t VCO_MHz;
+ uint8_t VCO_Output_Level;
+ uint8_t VCO_Varactor;
+ uint8_t VCO_Bias_Ref;
+ uint8_t VCO_Bias_Tcf;
+ uint8_t VCO_Cal_Offset;
+ uint8_t VCO_Varactor_Reference;
+ uint8_t Charge_Pump_Current;
+ uint8_t LF_C2;
+ uint8_t LF_C1;
+ uint8_t LF_R1;
+ uint8_t LF_C3;
+ uint8_t LF_R3;
+};
+
+enum {
+ LUT_FTDD_40,
+ LUT_FTDD_60,
+ LUT_FTDD_80,
+ LUT_FTDD_ENT,
+};
+
+enum ad9361_clocks {
+ BB_REFCLK,
+ RX_REFCLK,
+ TX_REFCLK,
+ BBPLL_CLK,
+ ADC_CLK,
+ R2_CLK,
+ R1_CLK,
+ CLKRF_CLK,
+ RX_SAMPL_CLK,
+ DAC_CLK,
+ T2_CLK,
+ T1_CLK,
+ CLKTF_CLK,
+ TX_SAMPL_CLK,
+ RX_RFPLL_INT,
+ TX_RFPLL_INT,
+ RX_RFPLL_DUMMY,
+ TX_RFPLL_DUMMY,
+ RX_RFPLL,
+ TX_RFPLL,
+ NUM_AD9361_CLKS,
+ EXT_REF_CLK,
+};
+
+struct ad9361_debugfs_entry {
+ struct ad9361_rf_phy *phy;
+ const char *propname;
+ void *out_value;
+ uint32_t val;
+ uint8_t size;
+ uint8_t cmd;
+};
+
+struct ad9361_fastlock_entry {
+#define FASTLOOK_INIT 1
+ uint8_t flags;
+ uint8_t alc_orig;
+ uint8_t alc_written;
+};
+
+struct ad9361_fastlock {
+ uint8_t save_profile;
+ uint8_t current_profile[2];
+ struct ad9361_fastlock_entry entry[2][8];
+};
+
+enum dig_tune_flags {
+ BE_VERBOSE = 1,
+ BE_MOREVERBOSE = 2,
+ DO_IDELAY = 4,
+ DO_ODELAY = 8,
+ SKIP_STORE_RESULT = 16,
+ RESTORE_DEFAULT = 32,
+};
+
+enum ad9361_bist_mode {
+ BIST_DISABLE,
+ BIST_INJ_TX,
+ BIST_INJ_RX,
+};
+
+enum dev_id {
+ ID_AD9361,
+ ID_AD9364,
+ ID_AD9363A
+};
+
+struct ad9361_rf_phy {
+ enum dev_id dev_sel;
+ uint8_t id_no;
+ struct spi_device *spi;
+#ifdef NUAND_MODIFICATIONS
+ // add gpio device struct
+ struct gpio_device *gpio;
+#endif // NUAND_MODIFICATIONS
+ struct clk *clk_refin;
+ struct clk *clks[NUM_AD9361_CLKS];
+ struct refclk_scale *ref_clk_scale[NUM_AD9361_CLKS];
+ struct clk_onecell_data clk_data;
+ uint32_t (*ad9361_rfpll_ext_recalc_rate)(struct refclk_scale *clk_priv);
+ int32_t (*ad9361_rfpll_ext_round_rate)(struct refclk_scale *clk_priv, uint32_t rate);
+ int32_t (*ad9361_rfpll_ext_set_rate)(struct refclk_scale *clk_priv, uint32_t rate);
+ struct ad9361_phy_platform_data *pdata;
+ uint8_t prev_ensm_state;
+ uint8_t curr_ensm_state;
+ uint8_t cached_rx_rfpll_div;
+ uint8_t cached_tx_rfpll_div;
+ struct rx_gain_info rx_gain[RXGAIN_TBLS_END];
+ enum rx_gain_table_name current_table;
+ bool ensm_pin_ctl_en;
+
+ bool auto_cal_en;
+ uint64_t last_tx_quad_cal_freq;
+ uint32_t last_tx_quad_cal_phase;
+ uint64_t current_tx_lo_freq;
+ uint64_t current_rx_lo_freq;
+ bool current_tx_use_tdd_table;
+ bool current_rx_use_tdd_table;
+ uint32_t flags;
+ uint32_t cal_threshold_freq;
+ uint32_t current_rx_bw_Hz;
+ uint32_t current_tx_bw_Hz;
+ uint32_t rxbbf_div;
+ uint32_t rate_governor;
+ bool bypass_rx_fir;
+ bool bypass_tx_fir;
+ bool rx_eq_2tx;
+ bool filt_valid;
+ uint32_t filt_rx_path_clks[NUM_RX_CLOCKS];
+ uint32_t filt_tx_path_clks[NUM_TX_CLOCKS];
+ uint32_t filt_rx_bw_Hz;
+ uint32_t filt_tx_bw_Hz;
+ uint8_t tx_fir_int;
+ uint8_t tx_fir_ntaps;
+ uint8_t rx_fir_dec;
+ uint8_t rx_fir_ntaps;
+ uint8_t agc_mode[2];
+ bool rfdc_track_en;
+ bool bbdc_track_en;
+ bool quad_track_en;
+ bool txmon_tdd_en;
+ uint16_t auxdac1_value;
+ uint16_t auxdac2_value;
+ uint32_t tx1_atten_cached;
+ uint32_t tx2_atten_cached;
+ struct ad9361_fastlock fastlock;
+ struct axiadc_converter *adc_conv;
+ struct axiadc_state *adc_state;
+ int32_t bist_loopback_mode;
+ enum ad9361_bist_mode bist_prbs_mode;
+ enum ad9361_bist_mode bist_tone_mode;
+ uint32_t bist_tone_freq_Hz;
+ uint32_t bist_tone_level_dB;
+ uint32_t bist_tone_mask;
+ bool bbpll_initialized;
+};
+
+struct refclk_scale {
+ struct spi_device *spi;
+ struct ad9361_rf_phy *phy;
+ uint32_t mult;
+ uint32_t div;
+ enum ad9361_clocks source;
+ enum ad9361_clocks parent_source;
+};
+
+enum debugfs_cmd {
+ DBGFS_NONE,
+ DBGFS_INIT,
+ DBGFS_LOOPBACK,
+ DBGFS_BIST_PRBS,
+ DBGFS_BIST_TONE,
+ DBGFS_BIST_DT_ANALYSIS,
+ DBGFS_RXGAIN_1,
+ DBGFS_RXGAIN_2,
+};
+
+/******************************************************************************/
+/************************ Functions Declarations ******************************/
+/******************************************************************************/
+int32_t ad9361_spi_readm(struct spi_device *spi, uint32_t reg,
+ uint8_t *rbuf, uint32_t num);
+int32_t ad9361_spi_read(struct spi_device *spi, uint32_t reg);
+int32_t ad9361_spi_write(struct spi_device *spi,
+ uint32_t reg, uint32_t val);
+int32_t ad9361_reset(struct ad9361_rf_phy *phy);
+int32_t register_clocks(struct ad9361_rf_phy *phy);
+int32_t ad9361_init_gain_tables(struct ad9361_rf_phy *phy);
+int32_t ad9361_setup(struct ad9361_rf_phy *phy);
+int32_t ad9361_post_setup(struct ad9361_rf_phy *phy);
+int32_t ad9361_set_ensm_mode(struct ad9361_rf_phy *phy, bool fdd, bool pinctrl);
+int32_t ad9361_ensm_set_state(struct ad9361_rf_phy *phy, uint8_t ensm_state,
+ bool pinctrl);
+int32_t ad9361_set_rx_gain(struct ad9361_rf_phy *phy,
+ uint32_t rx_id, struct rf_rx_gain *rx_gain);
+int32_t ad9361_get_rx_gain(struct ad9361_rf_phy *phy,
+ uint32_t rx_id, struct rf_rx_gain *rx_gain);
+int32_t ad9361_update_rf_bandwidth(struct ad9361_rf_phy *phy,
+ uint32_t rf_rx_bw, uint32_t rf_tx_bw);
+int32_t ad9361_calculate_rf_clock_chain(struct ad9361_rf_phy *phy,
+ uint32_t tx_sample_rate,
+ uint32_t rate_gov,
+ uint32_t *rx_path_clks,
+ uint32_t *tx_path_clks);
+int32_t ad9361_set_trx_clock_chain(struct ad9361_rf_phy *phy,
+ uint32_t *rx_path_clks,
+ uint32_t *tx_path_clks);
+int32_t ad9361_get_trx_clock_chain(struct ad9361_rf_phy *phy, uint32_t *rx_path_clks,
+ uint32_t *tx_path_clks);
+uint32_t ad9361_to_clk(uint64_t freq);
+uint64_t ad9361_from_clk(uint32_t freq);
+int32_t ad9361_read_rssi(struct ad9361_rf_phy *phy, struct rf_rssi *rssi);
+int32_t ad9361_set_gain_ctrl_mode(struct ad9361_rf_phy *phy,
+ struct rf_gain_ctrl *gain_ctrl);
+int32_t ad9361_load_fir_filter_coef(struct ad9361_rf_phy *phy,
+ enum fir_dest dest, int32_t gain_dB,
+ uint32_t ntaps, short *coef);
+int32_t ad9361_validate_enable_fir(struct ad9361_rf_phy *phy);
+int32_t ad9361_set_tx_atten(struct ad9361_rf_phy *phy, uint32_t atten_mdb,
+ bool tx1, bool tx2, bool immed);
+int32_t ad9361_get_tx_atten(struct ad9361_rf_phy *phy, uint32_t tx_num);
+uint32_t ad9361_clk_factor_recalc_rate(struct refclk_scale *clk_priv,
+ uint32_t parent_rate);
+int32_t ad9361_clk_factor_round_rate(struct refclk_scale *clk_priv, uint32_t rate,
+ uint32_t *prate);
+int32_t ad9361_clk_factor_set_rate(struct refclk_scale *clk_priv, uint32_t rate,
+ uint32_t parent_rate);
+uint32_t ad9361_bbpll_recalc_rate(struct refclk_scale *clk_priv,
+ uint32_t parent_rate);
+int32_t ad9361_bbpll_round_rate(struct refclk_scale *clk_priv, uint32_t rate,
+ uint32_t *prate);
+int32_t ad9361_bbpll_set_rate(struct refclk_scale *clk_priv, uint32_t rate,
+ uint32_t parent_rate);
+uint32_t ad9361_rfpll_int_recalc_rate(struct refclk_scale *clk_priv,
+ uint32_t parent_rate);
+int32_t ad9361_rfpll_int_round_rate(struct refclk_scale *clk_priv, uint32_t rate,
+ uint32_t *prate);
+int32_t ad9361_rfpll_int_set_rate(struct refclk_scale *clk_priv, uint32_t rate,
+ uint32_t parent_rate);
+uint32_t ad9361_rfpll_dummy_recalc_rate(struct refclk_scale *clk_priv);
+int32_t ad9361_rfpll_dummy_set_rate(struct refclk_scale *clk_priv, uint32_t rate);
+uint32_t ad9361_rfpll_recalc_rate(struct refclk_scale *clk_priv);
+int32_t ad9361_rfpll_round_rate(struct refclk_scale *clk_priv, uint32_t rate);
+int32_t ad9361_rfpll_set_rate(struct refclk_scale *clk_priv, uint32_t rate);
+int32_t ad9361_clk_mux_set_parent(struct refclk_scale *clk_priv, uint8_t index);
+int32_t ad9361_tracking_control(struct ad9361_rf_phy *phy, bool bbdc_track,
+ bool rfdc_track, bool rxquad_track);
+int32_t ad9361_bist_loopback(struct ad9361_rf_phy *phy, int32_t mode);
+void ad9361_get_bist_loopback(struct ad9361_rf_phy *phy, int32_t *mode);
+int32_t ad9361_bist_prbs(struct ad9361_rf_phy *phy, enum ad9361_bist_mode mode);
+void ad9361_get_bist_prbs(struct ad9361_rf_phy *phy, enum ad9361_bist_mode *mode);
+int32_t ad9361_bist_tone(struct ad9361_rf_phy *phy,
+ enum ad9361_bist_mode mode, uint32_t freq_Hz,
+ uint32_t level_dB, uint32_t mask);
+void ad9361_get_bist_tone(struct ad9361_rf_phy *phy,
+ enum ad9361_bist_mode *mode, uint32_t *freq_Hz,
+ uint32_t *level_dB, uint32_t *mask);
+int32_t ad9361_rf_port_setup(struct ad9361_rf_phy *phy, bool is_out,
+ uint32_t rx_inputs, uint32_t txb);
+int32_t ad9361_mcs(struct ad9361_rf_phy *phy, int32_t step);
+int32_t ad9361_do_calib_run(struct ad9361_rf_phy *phy, uint32_t cal, int32_t arg);
+int32_t ad9361_fastlock_store(struct ad9361_rf_phy *phy, bool tx, uint32_t profile);
+int32_t ad9361_fastlock_recall(struct ad9361_rf_phy *phy, bool tx, uint32_t profile);
+int32_t ad9361_fastlock_load(struct ad9361_rf_phy *phy, bool tx,
+ uint32_t profile, uint8_t *values);
+int32_t ad9361_fastlock_save(struct ad9361_rf_phy *phy, bool tx,
+ uint32_t profile, uint8_t *values);
+void ad9361_ensm_force_state(struct ad9361_rf_phy *phy, uint8_t ensm_state);
+void ad9361_ensm_restore_prev_state(struct ad9361_rf_phy *phy);
+int32_t ad9361_set_trx_clock_chain_freq(struct ad9361_rf_phy *phy,
+ uint32_t freq);
+int32_t ad9361_find_opt(uint8_t *field, uint32_t size, uint32_t *ret_start);
+int32_t ad9361_hdl_loopback(struct ad9361_rf_phy *phy, bool enable);
+int32_t ad9361_dig_interface_timing_analysis(struct ad9361_rf_phy *phy,
+ char *buf, int32_t buflen);
+int32_t ad9361_dig_tune(struct ad9361_rf_phy *phy, uint32_t max_freq,
+ enum dig_tune_flags flags);
+int32_t ad9361_en_dis_tx(struct ad9361_rf_phy *phy, uint32_t tx_if, uint32_t enable);
+int32_t ad9361_en_dis_rx(struct ad9361_rf_phy *phy, uint32_t rx_if, uint32_t enable);
+int32_t ad9361_1rx1tx_channel_map(struct ad9361_rf_phy *phy, bool tx, int32_t channel);
+int32_t ad9361_rssi_gain_step_calib(struct ad9361_rf_phy *phy);
+int32_t ad9361_set_dcxo_tune(struct ad9361_rf_phy *phy,
+ uint32_t coarse, uint32_t fine);
+int32_t ad9361_tx_mute(struct ad9361_rf_phy *phy, uint32_t state);
+uint32_t ad9361_validate_rf_bw(struct ad9361_rf_phy *phy, uint32_t bw);
+#endif
diff --git a/Radio/HW/BladeRF/common/thirdparty/ad936x/ad9361_api.c b/Radio/HW/BladeRF/common/thirdparty/ad936x/ad9361_api.c
new file mode 100644
index 0000000..180315d
--- /dev/null
+++ b/Radio/HW/BladeRF/common/thirdparty/ad936x/ad9361_api.c
@@ -0,0 +1,2126 @@
+/***************************************************************************//**
+ * @file ad9361_api.c
+ * @brief Implementation of AD9361 API Driver.
+ * @author DBogdan (dragos.bogdan@analog.com)
+********************************************************************************
+ * Copyright 2013(c) Analog Devices, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of Analog Devices, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * - The use of this software may or may not infringe the patent rights
+ * of one or more patent holders. This license does not release you
+ * from the requirement that you obtain separate licenses from these
+ * patent holders to use this software.
+ * - Use of the software either in source or binary form, must be run
+ * on or directly connected to an Analog Devices Inc. component.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+/******************************************************************************/
+/***************************** Include Files **********************************/
+/******************************************************************************/
+#include "ad9361.h"
+#include "ad9361_api.h"
+#include "platform.h"
+#include "util.h"
+#include "config.h"
+#include <string.h>
+
+#ifndef AXI_ADC_NOT_PRESENT
+/******************************************************************************/
+/************************ Constants Definitions *******************************/
+/******************************************************************************/
+static struct axiadc_chip_info axiadc_chip_info_tbl[] =
+{
+ {
+ "4_CH_DEV",
+ 4
+ },
+ {
+ "2_CH_DEV",
+ 2
+ },
+};
+#endif
+
+/**
+ * Initialize the AD9361 part.
+ * @param init_param The structure that contains the AD9361 initial parameters.
+ * @return A structure that contains the AD9361 current state in case of
+ * success, negative error code otherwise.
+ *
+ * Note: This function will/may affect the data path.
+ */
+#ifdef NUAND_MODIFICATIONS
+// add *userdata parameter
+int32_t ad9361_init (struct ad9361_rf_phy **ad9361_phy, AD9361_InitParam *init_param, void *userdata)
+#else
+int32_t ad9361_init (struct ad9361_rf_phy **ad9361_phy, AD9361_InitParam *init_param)
+#endif // NUAND_MODIFICATIONS
+{
+ struct ad9361_rf_phy *phy;
+ int32_t ret = 0;
+ int32_t rev = 0;
+ int32_t i = 0;
+
+ phy = (struct ad9361_rf_phy *)zmalloc(sizeof(*phy));
+ if (!phy) {
+ return -ENOMEM;
+ }
+
+ phy->spi = (struct spi_device *)zmalloc(sizeof(*phy->spi));
+ if (!phy->spi) {
+ return -ENOMEM;
+ }
+
+#ifdef NUAND_MODIFICATIONS
+ // allocate gpio struct
+ phy->gpio = (struct gpio_device *)zmalloc(sizeof(*phy->gpio));
+ if (!phy->gpio) {
+ return -ENOMEM;
+ }
+#endif // NUAND_MODIFICATIONS
+
+ phy->clk_refin = (struct clk *)zmalloc(sizeof(*phy->clk_refin));
+ if (!phy->clk_refin) {
+ return -ENOMEM;
+ }
+
+ phy->pdata = (struct ad9361_phy_platform_data *)zmalloc(sizeof(*phy->pdata));
+ if (!phy->pdata) {
+ return -ENOMEM;
+ }
+#ifndef AXI_ADC_NOT_PRESENT
+ phy->adc_conv = (struct axiadc_converter *)zmalloc(sizeof(*phy->adc_conv));
+ if (!phy->adc_conv) {
+ return -ENOMEM;
+ }
+
+ phy->adc_state = (struct axiadc_state *)zmalloc(sizeof(*phy->adc_state));
+ if (!phy->adc_state) {
+ return -ENOMEM;
+ }
+ phy->adc_state->phy = phy;
+#endif
+
+#ifdef NUAND_MODIFICATIONS
+ /* Ensure phy->clks and phy->ref_clk_scale are adequately nulled */
+ for (size_t i = 0; i < NUM_AD9361_CLKS; ++i) {
+ phy->clks[i] = NULL;
+ phy->ref_clk_scale[i] = NULL;
+ }
+ phy->clk_data.clks = NULL;
+#endif // NUAND_MODIFICATIONS
+
+ /* Device selection */
+ phy->dev_sel = init_param->dev_sel;
+
+ /* Identification number */
+ phy->spi->id_no = init_param->id_no;
+ phy->id_no = init_param->id_no;
+
+ /* Reference Clock */
+ phy->clk_refin->rate = init_param->reference_clk_rate;
+
+ /* Base Configuration */
+ phy->pdata->fdd = init_param->frequency_division_duplex_mode_enable;
+ phy->pdata->fdd_independent_mode = init_param->frequency_division_duplex_independent_mode_enable;
+ phy->pdata->rx2tx2 = init_param->two_rx_two_tx_mode_enable;
+ phy->pdata->rx1tx1_mode_use_rx_num = init_param->one_rx_one_tx_mode_use_rx_num;
+ phy->pdata->rx1tx1_mode_use_tx_num = init_param->one_rx_one_tx_mode_use_tx_num;
+ phy->pdata->tdd_use_dual_synth = init_param->tdd_use_dual_synth_mode_enable;
+ phy->pdata->tdd_skip_vco_cal = init_param->tdd_skip_vco_cal_enable;
+ phy->pdata->rx_fastlock_delay_ns = init_param->rx_fastlock_delay_ns;
+ phy->pdata->tx_fastlock_delay_ns = init_param->tx_fastlock_delay_ns;
+ phy->pdata->trx_fastlock_pinctrl_en[0] = init_param->rx_fastlock_pincontrol_enable;
+ phy->pdata->trx_fastlock_pinctrl_en[1] = init_param->tx_fastlock_pincontrol_enable;
+ if (phy->dev_sel == ID_AD9363A) {
+ phy->pdata->use_ext_rx_lo = false;
+ phy->pdata->use_ext_tx_lo = false;
+ } else {
+ phy->pdata->use_ext_rx_lo = init_param->external_rx_lo_enable;
+ phy->pdata->use_ext_tx_lo = init_param->external_tx_lo_enable;
+ }
+ phy->pdata->dc_offset_update_events = init_param->dc_offset_tracking_update_event_mask;
+ phy->pdata->dc_offset_attenuation_high = init_param->dc_offset_attenuation_high_range;
+ phy->pdata->dc_offset_attenuation_low = init_param->dc_offset_attenuation_low_range;
+ phy->pdata->rf_dc_offset_count_high = init_param->dc_offset_count_high_range;
+ phy->pdata->rf_dc_offset_count_low = init_param->dc_offset_count_low_range;
+ phy->pdata->split_gt = init_param->split_gain_table_mode_enable;
+ phy->pdata->trx_synth_max_fref = init_param->trx_synthesizer_target_fref_overwrite_hz;
+ phy->pdata->qec_tracking_slow_mode_en = init_param->qec_tracking_slow_mode_enable;
+
+ /* ENSM Control */
+ phy->pdata->ensm_pin_pulse_mode = init_param->ensm_enable_pin_pulse_mode_enable;
+ phy->pdata->ensm_pin_ctrl = init_param->ensm_enable_txnrx_control_enable;
+
+ /* LO Control */
+ phy->pdata->rx_synth_freq = init_param->rx_synthesizer_frequency_hz;
+ phy->pdata->tx_synth_freq = init_param->tx_synthesizer_frequency_hz;
+
+ /* Rate & BW Control */
+ for(i = 0; i < 6; i++) {
+ phy->pdata->rx_path_clks[i] = init_param->rx_path_clock_frequencies[i];
+ }
+ for(i = 0; i < 6; i++) {
+ phy->pdata->tx_path_clks[i] = init_param->tx_path_clock_frequencies[i];
+ }
+ phy->pdata->rf_rx_bandwidth_Hz = init_param->rf_rx_bandwidth_hz;
+ phy->pdata->rf_tx_bandwidth_Hz = init_param->rf_tx_bandwidth_hz;
+
+ /* RF Port Control */
+ phy->pdata->rf_rx_input_sel = init_param->rx_rf_port_input_select;
+ phy->pdata->rf_tx_output_sel = init_param->tx_rf_port_input_select;
+
+ /* TX Attenuation Control */
+ phy->pdata->tx_atten = init_param->tx_attenuation_mdB;
+ phy->pdata->update_tx_gain_via_alert = init_param->update_tx_gain_in_alert_enable;
+
+ /* Reference Clock Control */
+ switch (phy->dev_sel) {
+ case ID_AD9363A:
+ phy->pdata->use_extclk = true;
+ break;
+ default:
+ phy->pdata->use_extclk = init_param->xo_disable_use_ext_refclk_enable;
+ }
+ phy->pdata->dcxo_coarse = init_param->dcxo_coarse_and_fine_tune[0];
+ phy->pdata->dcxo_fine = init_param->dcxo_coarse_and_fine_tune[1];
+ phy->pdata->ad9361_clkout_mode = (enum ad9361_clkout)init_param->clk_output_mode_select;
+
+ /* Gain Control */
+ phy->pdata->gain_ctrl.rx1_mode = (enum rf_gain_ctrl_mode)init_param->gc_rx1_mode;
+ phy->pdata->gain_ctrl.rx2_mode = (enum rf_gain_ctrl_mode)init_param->gc_rx2_mode;
+ phy->pdata->gain_ctrl.adc_large_overload_thresh = init_param->gc_adc_large_overload_thresh;
+ phy->pdata->gain_ctrl.adc_ovr_sample_size = init_param->gc_adc_ovr_sample_size;
+ phy->pdata->gain_ctrl.adc_small_overload_thresh = init_param->gc_adc_small_overload_thresh;
+ phy->pdata->gain_ctrl.dec_pow_measuremnt_duration = init_param->gc_dec_pow_measurement_duration;
+ phy->pdata->gain_ctrl.dig_gain_en = init_param->gc_dig_gain_enable;
+ phy->pdata->gain_ctrl.lmt_overload_high_thresh = init_param->gc_lmt_overload_high_thresh;
+ phy->pdata->gain_ctrl.lmt_overload_low_thresh = init_param->gc_lmt_overload_low_thresh;
+ phy->pdata->gain_ctrl.low_power_thresh = init_param->gc_low_power_thresh;
+ phy->pdata->gain_ctrl.max_dig_gain = init_param->gc_max_dig_gain;
+
+ /* Gain MGC Control */
+ phy->pdata->gain_ctrl.mgc_dec_gain_step = init_param->mgc_dec_gain_step;
+ phy->pdata->gain_ctrl.mgc_inc_gain_step = init_param->mgc_inc_gain_step;
+ phy->pdata->gain_ctrl.mgc_rx1_ctrl_inp_en = init_param->mgc_rx1_ctrl_inp_enable;
+ phy->pdata->gain_ctrl.mgc_rx2_ctrl_inp_en = init_param->mgc_rx2_ctrl_inp_enable;
+ phy->pdata->gain_ctrl.mgc_split_table_ctrl_inp_gain_mode = init_param->mgc_split_table_ctrl_inp_gain_mode;
+
+ /* Gain AGC Control */
+ phy->pdata->gain_ctrl.adc_large_overload_exceed_counter = init_param->agc_adc_large_overload_exceed_counter;
+ phy->pdata->gain_ctrl.adc_large_overload_inc_steps = init_param->agc_adc_large_overload_inc_steps;
+ phy->pdata->gain_ctrl.adc_lmt_small_overload_prevent_gain_inc = init_param->agc_adc_lmt_small_overload_prevent_gain_inc_enable;
+ phy->pdata->gain_ctrl.adc_small_overload_exceed_counter = init_param->agc_adc_small_overload_exceed_counter;
+ phy->pdata->gain_ctrl.dig_gain_step_size = init_param->agc_dig_gain_step_size;
+ phy->pdata->gain_ctrl.dig_saturation_exceed_counter = init_param->agc_dig_saturation_exceed_counter;
+ phy->pdata->gain_ctrl.gain_update_interval_us = init_param->agc_gain_update_interval_us;
+ phy->pdata->gain_ctrl.immed_gain_change_if_large_adc_overload = init_param->agc_immed_gain_change_if_large_adc_overload_enable;
+ phy->pdata->gain_ctrl.immed_gain_change_if_large_lmt_overload = init_param->agc_immed_gain_change_if_large_lmt_overload_enable;
+ phy->pdata->gain_ctrl.agc_inner_thresh_high = init_param->agc_inner_thresh_high;
+ phy->pdata->gain_ctrl.agc_inner_thresh_high_dec_steps = init_param->agc_inner_thresh_high_dec_steps;
+ phy->pdata->gain_ctrl.agc_inner_thresh_low = init_param->agc_inner_thresh_low;
+ phy->pdata->gain_ctrl.agc_inner_thresh_low_inc_steps = init_param->agc_inner_thresh_low_inc_steps;
+ phy->pdata->gain_ctrl.lmt_overload_large_exceed_counter = init_param->agc_lmt_overload_large_exceed_counter;
+ phy->pdata->gain_ctrl.lmt_overload_large_inc_steps = init_param->agc_lmt_overload_large_inc_steps;
+ phy->pdata->gain_ctrl.lmt_overload_small_exceed_counter = init_param->agc_lmt_overload_small_exceed_counter;
+ phy->pdata->gain_ctrl.agc_outer_thresh_high = init_param->agc_outer_thresh_high;
+ phy->pdata->gain_ctrl.agc_outer_thresh_high_dec_steps = init_param->agc_outer_thresh_high_dec_steps;
+ phy->pdata->gain_ctrl.agc_outer_thresh_low = init_param->agc_outer_thresh_low;
+ phy->pdata->gain_ctrl.agc_outer_thresh_low_inc_steps = init_param->agc_outer_thresh_low_inc_steps;
+ phy->pdata->gain_ctrl.agc_attack_delay_extra_margin_us = init_param->agc_attack_delay_extra_margin_us;
+ phy->pdata->gain_ctrl.sync_for_gain_counter_en = init_param->agc_sync_for_gain_counter_enable;
+
+ /* Fast AGC */
+ phy->pdata->gain_ctrl.f_agc_dec_pow_measuremnt_duration = init_param->fagc_dec_pow_measuremnt_duration;
+ phy->pdata->gain_ctrl.f_agc_state_wait_time_ns = init_param->fagc_state_wait_time_ns;
+ /* Fast AGC - Low Power */
+ phy->pdata->gain_ctrl.f_agc_allow_agc_gain_increase = init_param->fagc_allow_agc_gain_increase;
+ phy->pdata->gain_ctrl.f_agc_lp_thresh_increment_time = init_param->fagc_lp_thresh_increment_time;
+ phy->pdata->gain_ctrl.f_agc_lp_thresh_increment_steps = init_param->fagc_lp_thresh_increment_steps;
+ /* Fast AGC - Lock Level */
+ phy->pdata->gain_ctrl.f_agc_lock_level = init_param->fagc_lock_level;
+ phy->pdata->gain_ctrl.f_agc_lock_level_lmt_gain_increase_en = init_param->fagc_lock_level_lmt_gain_increase_en;
+ phy->pdata->gain_ctrl.f_agc_lock_level_gain_increase_upper_limit = init_param->fagc_lock_level_gain_increase_upper_limit;
+ /* Fast AGC - Peak Detectors and Final Settling */
+ phy->pdata->gain_ctrl.f_agc_lpf_final_settling_steps = init_param->fagc_lpf_final_settling_steps;
+ phy->pdata->gain_ctrl.f_agc_lmt_final_settling_steps = init_param->fagc_lmt_final_settling_steps;
+ phy->pdata->gain_ctrl.f_agc_final_overrange_count = init_param->fagc_final_overrange_count;
+ /* Fast AGC - Final Power Test */
+ phy->pdata->gain_ctrl.f_agc_gain_increase_after_gain_lock_en = init_param->fagc_gain_increase_after_gain_lock_en;
+ /* Fast AGC - Unlocking the Gain */
+ phy->pdata->gain_ctrl.f_agc_gain_index_type_after_exit_rx_mode = (enum f_agc_target_gain_index_type)init_param->fagc_gain_index_type_after_exit_rx_mode;
+ phy->pdata->gain_ctrl.f_agc_use_last_lock_level_for_set_gain_en = init_param->fagc_use_last_lock_level_for_set_gain_en;
+ phy->pdata->gain_ctrl.f_agc_rst_gla_stronger_sig_thresh_exceeded_en = init_param->fagc_rst_gla_stronger_sig_thresh_exceeded_en;
+ phy->pdata->gain_ctrl.f_agc_optimized_gain_offset = init_param->fagc_optimized_gain_offset;
+ phy->pdata->gain_ctrl.f_agc_rst_gla_stronger_sig_thresh_above_ll = init_param->fagc_rst_gla_stronger_sig_thresh_above_ll;
+ phy->pdata->gain_ctrl.f_agc_rst_gla_engergy_lost_sig_thresh_exceeded_en = init_param->fagc_rst_gla_engergy_lost_sig_thresh_exceeded_en;
+ phy->pdata->gain_ctrl.f_agc_rst_gla_engergy_lost_goto_optim_gain_en = init_param->fagc_rst_gla_engergy_lost_goto_optim_gain_en;
+ phy->pdata->gain_ctrl.f_agc_rst_gla_engergy_lost_sig_thresh_below_ll = init_param->fagc_rst_gla_engergy_lost_sig_thresh_below_ll;
+ phy->pdata->gain_ctrl.f_agc_energy_lost_stronger_sig_gain_lock_exit_cnt = init_param->fagc_energy_lost_stronger_sig_gain_lock_exit_cnt;
+ phy->pdata->gain_ctrl.f_agc_rst_gla_large_adc_overload_en = init_param->fagc_rst_gla_large_adc_overload_en;
+ phy->pdata->gain_ctrl.f_agc_rst_gla_large_lmt_overload_en = init_param->fagc_rst_gla_large_lmt_overload_en;
+ phy->pdata->gain_ctrl.f_agc_rst_gla_en_agc_pulled_high_en = init_param->fagc_rst_gla_en_agc_pulled_high_en;
+ phy->pdata->gain_ctrl.f_agc_rst_gla_if_en_agc_pulled_high_mode = (enum f_agc_target_gain_index_type)init_param->fagc_rst_gla_if_en_agc_pulled_high_mode;
+ phy->pdata->gain_ctrl.f_agc_power_measurement_duration_in_state5 = init_param->fagc_power_measurement_duration_in_state5;
+
+ /* RSSI Control */
+ phy->pdata->rssi_ctrl.rssi_delay = init_param->rssi_delay;
+ phy->pdata->rssi_ctrl.rssi_duration = init_param->rssi_duration;
+ phy->pdata->rssi_ctrl.restart_mode = (enum rssi_restart_mode)init_param->rssi_restart_mode;
+ phy->pdata->rssi_ctrl.rssi_unit_is_rx_samples = init_param->rssi_unit_is_rx_samples_enable;
+ phy->pdata->rssi_ctrl.rssi_wait = init_param->rssi_wait;
+
+ /* Aux ADC Control */
+ phy->pdata->auxadc_ctrl.auxadc_decimation = init_param->aux_adc_decimation;
+ phy->pdata->auxadc_ctrl.auxadc_clock_rate = init_param->aux_adc_rate;
+
+ /* AuxDAC Control */
+ phy->pdata->auxdac_ctrl.auxdac_manual_mode_en = init_param->aux_dac_manual_mode_enable;
+ phy->pdata->auxdac_ctrl.dac1_default_value = init_param->aux_dac1_default_value_mV;
+ phy->pdata->auxdac_ctrl.dac1_in_rx_en = init_param->aux_dac1_active_in_rx_enable;
+ phy->pdata->auxdac_ctrl.dac1_in_tx_en = init_param->aux_dac1_active_in_tx_enable;
+ phy->pdata->auxdac_ctrl.dac1_in_alert_en = init_param->aux_dac1_active_in_alert_enable;
+ phy->pdata->auxdac_ctrl.dac1_rx_delay_us = init_param->aux_dac1_rx_delay_us;
+ phy->pdata->auxdac_ctrl.dac1_tx_delay_us = init_param->aux_dac1_tx_delay_us;
+ phy->pdata->auxdac_ctrl.dac2_default_value = init_param->aux_dac2_default_value_mV;
+ phy->pdata->auxdac_ctrl.dac2_in_rx_en = init_param->aux_dac2_active_in_rx_enable;
+ phy->pdata->auxdac_ctrl.dac2_in_tx_en = init_param->aux_dac2_active_in_tx_enable;
+ phy->pdata->auxdac_ctrl.dac2_in_alert_en = init_param->aux_dac2_active_in_alert_enable;
+ phy->pdata->auxdac_ctrl.dac2_rx_delay_us = init_param->aux_dac2_rx_delay_us;
+ phy->pdata->auxdac_ctrl.dac2_tx_delay_us = init_param->aux_dac2_tx_delay_us;
+
+ /* Temperature Sensor Control */
+ phy->pdata->auxadc_ctrl.temp_sensor_decimation = init_param->temp_sense_decimation;
+ phy->pdata->auxadc_ctrl.temp_time_inteval_ms = init_param->temp_sense_measurement_interval_ms;
+ phy->pdata->auxadc_ctrl.offset = init_param->temp_sense_offset_signed;
+ phy->pdata->auxadc_ctrl.periodic_temp_measuremnt = init_param->temp_sense_periodic_measurement_enable;
+
+ /* Control Out Setup */
+ phy->pdata->ctrl_outs_ctrl.en_mask = init_param->ctrl_outs_enable_mask;
+ phy->pdata->ctrl_outs_ctrl.index = init_param->ctrl_outs_index;
+
+ /* External LNA Control */
+ phy->pdata->elna_ctrl.settling_delay_ns = init_param->elna_settling_delay_ns;
+ phy->pdata->elna_ctrl.gain_mdB = init_param->elna_gain_mdB;
+ phy->pdata->elna_ctrl.bypass_loss_mdB = init_param->elna_bypass_loss_mdB;
+ phy->pdata->elna_ctrl.elna_1_control_en = init_param->elna_rx1_gpo0_control_enable;
+ phy->pdata->elna_ctrl.elna_2_control_en = init_param->elna_rx2_gpo1_control_enable;
+ phy->pdata->elna_ctrl.elna_in_gaintable_all_index_en = init_param->elna_gaintable_all_index_enable;
+
+ /* Digital Interface Control */
+ phy->pdata->dig_interface_tune_skipmode = (init_param->digital_interface_tune_skip_mode);
+ phy->pdata->dig_interface_tune_fir_disable = (init_param->digital_interface_tune_fir_disable);
+ phy->pdata->port_ctrl.pp_conf[0] = (init_param->pp_tx_swap_enable << 7);
+ phy->pdata->port_ctrl.pp_conf[0] |= (init_param->pp_rx_swap_enable << 6);
+ phy->pdata->port_ctrl.pp_conf[0] |= (init_param->tx_channel_swap_enable << 5);
+ phy->pdata->port_ctrl.pp_conf[0] |= (init_param->rx_channel_swap_enable << 4);
+ phy->pdata->port_ctrl.pp_conf[0] |= (init_param->rx_frame_pulse_mode_enable << 3);
+ phy->pdata->port_ctrl.pp_conf[0] |= (init_param->two_t_two_r_timing_enable << 2);
+ phy->pdata->port_ctrl.pp_conf[0] |= (init_param->invert_data_bus_enable << 1);
+ phy->pdata->port_ctrl.pp_conf[0] |= (init_param->invert_data_clk_enable << 0);
+ phy->pdata->port_ctrl.pp_conf[1] = (init_param->fdd_alt_word_order_enable << 7);
+ phy->pdata->port_ctrl.pp_conf[1] |= (init_param->invert_rx_frame_enable << 2);
+ phy->pdata->port_ctrl.pp_conf[2] = (init_param->fdd_rx_rate_2tx_enable << 7);
+ phy->pdata->port_ctrl.pp_conf[2] |= (init_param->swap_ports_enable << 6);
+ phy->pdata->port_ctrl.pp_conf[2] |= (init_param->single_data_rate_enable << 5);
+ phy->pdata->port_ctrl.pp_conf[2] |= (init_param->lvds_mode_enable << 4);
+ phy->pdata->port_ctrl.pp_conf[2] |= (init_param->half_duplex_mode_enable << 3);
+ phy->pdata->port_ctrl.pp_conf[2] |= (init_param->single_port_mode_enable << 2);
+ phy->pdata->port_ctrl.pp_conf[2] |= (init_param->full_port_enable << 1);
+ phy->pdata->port_ctrl.pp_conf[2] |= (init_param->full_duplex_swap_bits_enable << 0);
+ phy->pdata->port_ctrl.pp_conf[1] |= (init_param->delay_rx_data & 0x3);
+ phy->pdata->port_ctrl.rx_clk_data_delay = DATA_CLK_DELAY(init_param->rx_data_clock_delay);
+ phy->pdata->port_ctrl.rx_clk_data_delay |= RX_DATA_DELAY(init_param->rx_data_delay);
+ phy->pdata->port_ctrl.tx_clk_data_delay = FB_CLK_DELAY(init_param->tx_fb_clock_delay);
+ phy->pdata->port_ctrl.tx_clk_data_delay |= TX_DATA_DELAY(init_param->tx_data_delay);
+ phy->pdata->port_ctrl.lvds_bias_ctrl = ((init_param->lvds_bias_mV - 75) / 75) & 0x7;
+ phy->pdata->port_ctrl.lvds_bias_ctrl |= (init_param->lvds_rx_onchip_termination_enable << 5);
+ phy->pdata->rx1rx2_phase_inversion_en = init_param->rx1rx2_phase_inversion_en;
+
+#ifdef NUAND_MODIFICATIONS
+ // settings for digital interface drive and slew
+ phy->pdata->port_ctrl.clk_out_drive = init_param->clk_out_drive & 0x1;
+ phy->pdata->port_ctrl.dataclk_drive = init_param->dataclk_drive & 0x1;
+ phy->pdata->port_ctrl.data_port_drive = init_param->data_port_drive & 0x1;
+ phy->pdata->port_ctrl.clk_out_slew = init_param->clk_out_slew & 0x3;
+ phy->pdata->port_ctrl.dataclk_slew = init_param->dataclk_slew & 0x3;
+ phy->pdata->port_ctrl.data_port_slew = init_param->data_port_slew & 0x3;
+#endif // NUAND_MODIFICATIONS
+
+ /* GPO Control */
+ phy->pdata->gpo_ctrl.gpo0_inactive_state_high_en = init_param->gpo0_inactive_state_high_enable;
+ phy->pdata->gpo_ctrl.gpo1_inactive_state_high_en = init_param->gpo1_inactive_state_high_enable;
+ phy->pdata->gpo_ctrl.gpo2_inactive_state_high_en = init_param->gpo2_inactive_state_high_enable;
+ phy->pdata->gpo_ctrl.gpo3_inactive_state_high_en = init_param->gpo3_inactive_state_high_enable;
+
+ phy->pdata->gpo_ctrl.gpo0_slave_rx_en = init_param->gpo0_slave_rx_enable;
+ phy->pdata->gpo_ctrl.gpo0_slave_tx_en = init_param->gpo0_slave_tx_enable;
+ phy->pdata->gpo_ctrl.gpo1_slave_rx_en = init_param->gpo1_slave_rx_enable;
+ phy->pdata->gpo_ctrl.gpo1_slave_tx_en = init_param->gpo1_slave_tx_enable;
+ phy->pdata->gpo_ctrl.gpo2_slave_rx_en = init_param->gpo2_slave_rx_enable;
+ phy->pdata->gpo_ctrl.gpo2_slave_tx_en = init_param->gpo2_slave_tx_enable;
+ phy->pdata->gpo_ctrl.gpo3_slave_rx_en = init_param->gpo3_slave_rx_enable;
+ phy->pdata->gpo_ctrl.gpo3_slave_tx_en = init_param->gpo3_slave_tx_enable;
+
+ phy->pdata->gpo_ctrl.gpo0_rx_delay_us = init_param->gpo0_rx_delay_us;
+ phy->pdata->gpo_ctrl.gpo0_tx_delay_us = init_param->gpo0_tx_delay_us;
+ phy->pdata->gpo_ctrl.gpo1_rx_delay_us = init_param->gpo1_rx_delay_us;
+ phy->pdata->gpo_ctrl.gpo1_tx_delay_us = init_param->gpo1_tx_delay_us;
+ phy->pdata->gpo_ctrl.gpo2_rx_delay_us = init_param->gpo2_rx_delay_us;
+ phy->pdata->gpo_ctrl.gpo2_tx_delay_us = init_param->gpo2_tx_delay_us;
+ phy->pdata->gpo_ctrl.gpo3_rx_delay_us = init_param->gpo3_rx_delay_us;
+ phy->pdata->gpo_ctrl.gpo3_tx_delay_us = init_param->gpo3_tx_delay_us;
+
+ /* Tx Monitor Control */
+ phy->pdata->txmon_ctrl.low_high_gain_threshold_mdB = init_param->low_high_gain_threshold_mdB;
+ phy->pdata->txmon_ctrl.low_gain_dB = init_param->low_gain_dB;
+ phy->pdata->txmon_ctrl.high_gain_dB = init_param->high_gain_dB;
+ phy->pdata->txmon_ctrl.tx_mon_track_en = init_param->tx_mon_track_en;
+ phy->pdata->txmon_ctrl.one_shot_mode_en = init_param->one_shot_mode_en;
+ phy->pdata->txmon_ctrl.tx_mon_delay = init_param->tx_mon_delay;
+ phy->pdata->txmon_ctrl.tx_mon_duration = init_param->tx_mon_duration;
+ phy->pdata->txmon_ctrl.tx1_mon_front_end_gain = init_param->tx1_mon_front_end_gain;
+ phy->pdata->txmon_ctrl.tx2_mon_front_end_gain = init_param->tx2_mon_front_end_gain;
+ phy->pdata->txmon_ctrl.tx1_mon_lo_cm = init_param->tx1_mon_lo_cm;
+ phy->pdata->txmon_ctrl.tx2_mon_lo_cm = init_param->tx2_mon_lo_cm;
+
+ phy->pdata->debug_mode = true;
+ phy->pdata->gpio_resetb = init_param->gpio_resetb;
+ /* Optional: next three GPIOs are used for MCS synchronization */
+ phy->pdata->gpio_sync = init_param->gpio_sync;
+ phy->pdata->gpio_cal_sw1 = init_param->gpio_cal_sw1;
+ phy->pdata->gpio_cal_sw2 = init_param->gpio_cal_sw2;
+
+ phy->pdata->port_ctrl.digital_io_ctrl = 0;
+ phy->pdata->port_ctrl.lvds_invert[0] = init_param->lvds_invert1_control;
+ phy->pdata->port_ctrl.lvds_invert[1] = init_param->lvds_invert2_control;
+
+#ifndef AXI_ADC_NOT_PRESENT
+ phy->adc_conv->chip_info = &axiadc_chip_info_tbl[phy->pdata->rx2tx2 ? ID_AD9361 : ID_AD9364];
+#endif
+
+ phy->rx_eq_2tx = false;
+
+ phy->current_table = RXGAIN_TBLS_END;
+ phy->bypass_tx_fir = true;
+ phy->bypass_rx_fir = true;
+ phy->rate_governor = 1;
+ phy->rfdc_track_en = true;
+ phy->bbdc_track_en = true;
+ phy->quad_track_en = true;
+
+ phy->bist_loopback_mode = 0;
+ phy->bist_prbs_mode = BIST_DISABLE;
+ phy->bist_tone_mode = BIST_DISABLE;
+ phy->bist_tone_freq_Hz = 0;
+ phy->bist_tone_level_dB = 0;
+ phy->bist_tone_mask = 0;
+
+#ifdef NUAND_MODIFICATIONS
+ // initialize SPI and GPIO
+ ret = spi_init(phy, userdata);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = gpio_init(phy, userdata);
+ if (ret < 0) {
+ goto out;
+ }
+#endif // NUAND_MODIFICATIONS
+
+ ad9361_reset(phy);
+
+ ret = ad9361_spi_read(phy->spi, REG_PRODUCT_ID);
+ if ((ret & PRODUCT_ID_MASK) != PRODUCT_ID_9361) {
+ printf("%s : Unsupported PRODUCT_ID 0x%X", __func__, (unsigned int)ret);
+#ifdef NUAND_MODIFICATIONS
+ // this missing newline, so help me god...
+ printf("\n");
+#endif // NUAND_MODIFICATIONS
+ ret = -ENODEV;
+ goto out;
+ }
+ rev = ret & REV_MASK;
+
+ if (AD9364_DEVICE) {
+ phy->pdata->rx2tx2 = false;
+ phy->pdata->rx1tx1_mode_use_rx_num = 1;
+ phy->pdata->rx1tx1_mode_use_tx_num = 1;
+ }
+
+ phy->ad9361_rfpll_ext_recalc_rate = init_param->ad9361_rfpll_ext_recalc_rate;
+ phy->ad9361_rfpll_ext_round_rate = init_param->ad9361_rfpll_ext_round_rate;
+ phy->ad9361_rfpll_ext_set_rate = init_param->ad9361_rfpll_ext_set_rate;
+
+ ret = register_clocks(phy);
+ if (ret < 0)
+ goto out;
+
+#ifndef AXI_ADC_NOT_PRESENT
+#ifdef NUAND_MODIFICATIONS
+ // use alternate axiadc accessors
+ axiadc_init(phy, userdata);
+ ret = axiadc_read(phy->adc_state, ADI_REG_VERSION, &(phy->adc_state->pcore_version));
+ if (ret < 0)
+ goto out;
+#else
+ axiadc_init(phy);
+ phy->adc_state->pcore_version = axiadc_read(phy->adc_state, ADI_REG_VERSION);
+#endif // NUAND_MODIFICATIONS
+#endif
+
+ ad9361_init_gain_tables(phy);
+
+ ret = ad9361_setup(phy);
+ if (ret < 0)
+ goto out;
+
+#ifndef AXI_ADC_NOT_PRESENT
+ /* platform specific wrapper to call ad9361_post_setup() */
+ ret = axiadc_post_setup(phy);
+ if (ret < 0)
+ goto out;
+#endif
+
+#ifndef NUAND_MODIFICATIONS
+ // reduce console noise
+ printf("%s : AD936x Rev %d successfully initialized\n", __func__, (int)rev);
+#endif // !NUAND_MODIFICATIONS
+
+ *ad9361_phy = phy;
+
+ return 0;
+
+out:
+ free(phy->spi);
+#ifndef AXI_ADC_NOT_PRESENT
+ free(phy->adc_conv);
+ free(phy->adc_state);
+#endif
+ free(phy->clk_refin);
+ free(phy->pdata);
+
+#ifdef NUAND_MODIFICATIONS
+ // free gpio struct, and also the clock stuff
+ free(phy->gpio);
+ free(phy->clk_data.clks);
+ for (size_t i = 0; i < NUM_AD9361_CLKS; ++i) {
+ free(phy->clks[i]);
+ free(phy->ref_clk_scale[i]);
+ }
+#endif // NUAND_MODIFICATIONS
+
+ free(phy);
+ printf("%s : AD936x initialization error\n", __func__);
+
+ return -ENODEV;
+}
+
+#ifdef NUAND_MODIFICATIONS
+/**
+ * Deinitialize the AD9361 part.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_deinit (struct ad9361_rf_phy *phy)
+{
+ if (phy) {
+ /* Put AD9361 part into reset */
+ if (gpio_is_valid(phy->gpio, phy->pdata->gpio_resetb)) {
+ gpio_set_value(phy->gpio, phy->pdata->gpio_resetb, 0);
+ }
+ }
+
+ if (phy) {
+ free(phy->spi);
+ free(phy->gpio);
+#ifndef AXI_ADC_NOT_PRESENT
+ free(phy->adc_conv);
+ free(phy->adc_state);
+#endif
+ free(phy->clk_refin);
+ free(phy->clk_data.clks);
+ free(phy->pdata);
+
+ for (size_t i = 0; i < NUM_AD9361_CLKS; ++i) {
+ free(phy->clks[i]);
+ free(phy->ref_clk_scale[i]);
+ }
+
+ free(phy);
+ }
+
+ return 0;
+}
+#endif // NUAND_MODIFICATIONS
+
+/**
+ * Set the Enable State Machine (ENSM) mode.
+ * @param phy The AD9361 current state structure.
+ * @param mode The ENSM mode.
+ * Accepted values:
+ * ENSM_MODE_TX
+ * ENSM_MODE_RX
+ * ENSM_MODE_ALERT
+ * ENSM_MODE_FDD
+ * ENSM_MODE_WAIT
+ * ENSM_MODE_SLEEP
+ * ENSM_MODE_PINCTRL
+ * ENSM_MODE_PINCTRL_FDD_INDEP
+ * @return 0 in case of success, negative error code otherwise.
+ *
+ * Note: This function will/may affect the data path.
+ */
+int32_t ad9361_set_en_state_machine_mode (struct ad9361_rf_phy *phy,
+ uint32_t mode)
+{
+ int32_t ret;
+ uint8_t ensm_state;
+ bool pinctrl = false;
+
+ phy->pdata->fdd_independent_mode = false;
+
+ switch (mode) {
+ case ENSM_MODE_TX:
+ ensm_state = ENSM_STATE_TX;
+ break;
+ case ENSM_MODE_RX:
+ ensm_state = ENSM_STATE_RX;
+ break;
+ case ENSM_MODE_ALERT:
+ ensm_state = ENSM_STATE_ALERT;
+ break;
+ case ENSM_MODE_FDD:
+ ensm_state = ENSM_STATE_FDD;
+ break;
+ case ENSM_MODE_WAIT:
+ ensm_state = ENSM_STATE_SLEEP_WAIT;
+ break;
+ case ENSM_MODE_SLEEP:
+ ensm_state = ENSM_STATE_SLEEP;
+ break;
+ case ENSM_MODE_PINCTRL:
+ ensm_state = ENSM_STATE_SLEEP_WAIT;
+ pinctrl = true;
+ break;
+ case ENSM_MODE_PINCTRL_FDD_INDEP:
+ ensm_state = ENSM_STATE_FDD;
+ phy->pdata->fdd_independent_mode = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ad9361_set_ensm_mode(phy, phy->pdata->fdd, pinctrl);
+ ret = ad9361_ensm_set_state(phy, ensm_state, pinctrl);
+
+ return ret;
+}
+
+/**
+ * Get the Enable State Machine (ENSM) mode.
+ * @param phy The AD9361 current state structure.
+ * @param mode A variable to store the selected ENSM mode.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_en_state_machine_mode (struct ad9361_rf_phy *phy,
+ uint32_t *mode)
+{
+ uint8_t ensm_state;
+ bool pinctrl = false;
+ int32_t ret;
+
+ ensm_state = ad9361_spi_read(phy->spi, REG_STATE);
+ ensm_state &= ENSM_STATE(~0);
+ ret = ad9361_spi_read(phy->spi, REG_ENSM_CONFIG_1);
+ if ((ret & ENABLE_ENSM_PIN_CTRL) == ENABLE_ENSM_PIN_CTRL)
+ pinctrl = true;
+
+ switch (ensm_state) {
+ case ENSM_STATE_TX:
+ *mode = ENSM_MODE_TX;
+ break;
+ case ENSM_STATE_RX:
+ *mode = ENSM_MODE_RX;
+ break;
+ case ENSM_STATE_ALERT:
+ *mode = ENSM_MODE_ALERT;
+ break;
+ case ENSM_STATE_FDD:
+ if (phy->pdata->fdd_independent_mode)
+ *mode = ENSM_MODE_PINCTRL_FDD_INDEP;
+ else
+ *mode = ENSM_MODE_FDD;
+ break;
+ case ENSM_STATE_SLEEP_WAIT:
+ if (pinctrl)
+ *mode = ENSM_MODE_PINCTRL;
+ else
+ *mode = ENSM_MODE_WAIT;
+ break;
+ case ENSM_STATE_SLEEP:
+ *mode = ENSM_MODE_SLEEP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * Set the receive RF gain for the selected channel.
+ * @param phy The AD9361 current state structure.
+ * @param ch The desired channel number (RX1, RX2).
+ * Accepted values in 2x2 mode:
+ * RX1 (0)
+ * RX2 (1)
+ * Accepted values in 1x1 mode:
+ * RX1 (0)
+ * @param gain_db The RF gain (dB).
+ * Example:
+ * 10 (10 dB)
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_set_rx_rf_gain (struct ad9361_rf_phy *phy,
+ uint8_t ch, int32_t gain_db)
+{
+ struct rf_rx_gain rx_gain = {0};
+ int32_t ret = 0;
+
+ if ((phy->pdata->rx2tx2 == 0) && (ch == RX2)) {
+ printf("%s : RX2 is an invalid option in 1x1 mode!\n", __func__);
+ return -1;
+ }
+
+ rx_gain.gain_db = gain_db;
+ ret = ad9361_set_rx_gain(phy,
+ ad9361_1rx1tx_channel_map(phy, false,
+ ch + 1), &rx_gain);
+
+ return ret;
+}
+
+/**
+ * Get current receive RF gain for the selected channel.
+ * @param phy The AD9361 current state structure.
+ * @param ch The desired channel number (RX1, RX2).
+ * Accepted values in 2x2 mode:
+ * RX1 (0)
+ * RX2 (1)
+ * Accepted values in 1x1 mode:
+ * RX1 (0)
+ * @param gain_db A variable to store the RF gain (dB).
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_rx_rf_gain (struct ad9361_rf_phy *phy,
+ uint8_t ch, int32_t *gain_db)
+{
+ struct rf_rx_gain rx_gain = {0};
+ int32_t ret = 0;
+
+ if ((phy->pdata->rx2tx2 == 0) && (ch == RX2)) {
+ printf("%s : RX2 is an invalid option in 1x1 mode!\n", __func__);
+ return -1;
+ }
+
+ ret = ad9361_get_rx_gain(phy, ad9361_1rx1tx_channel_map(phy,
+ false, ch + 1), &rx_gain);
+
+ *gain_db = rx_gain.gain_db;
+
+ return ret;
+}
+
+/**
+ * Set the RX RF bandwidth.
+ * @param phy The AD9361 current state structure.
+ * @param bandwidth_hz The desired bandwidth (Hz).
+ * Example:
+ * 18000000 (18 MHz)
+ * @return 0 in case of success, negative error code otherwise.
+ *
+ * Note: This function will/may affect the data path.
+ */
+int32_t ad9361_set_rx_rf_bandwidth (struct ad9361_rf_phy *phy,
+ uint32_t bandwidth_hz)
+{
+ int32_t ret = 0;
+
+ bandwidth_hz = ad9361_validate_rf_bw(phy, bandwidth_hz);
+
+ if (phy->current_rx_bw_Hz != bandwidth_hz)
+ ret = ad9361_update_rf_bandwidth(phy, bandwidth_hz,
+ phy->current_tx_bw_Hz);
+ else
+ ret = 0;
+
+ return ret;
+}
+
+/**
+ * Get the RX RF bandwidth.
+ * @param phy The AD9361 current state structure.
+ * @param bandwidth_hz A variable to store the bandwidth value (Hz).
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_rx_rf_bandwidth (struct ad9361_rf_phy *phy,
+ uint32_t *bandwidth_hz)
+{
+ *bandwidth_hz = phy->current_rx_bw_Hz;
+
+ return 0;
+}
+
+/**
+ * Set the RX sampling frequency.
+ * @param phy The AD9361 current state structure.
+ * @param sampling_freq_hz The desired frequency (Hz).
+ * Example:
+ * 30720000 (30.72 MHz)
+ * @return 0 in case of success, negative error code otherwise.
+ *
+ * Note: This function will/may affect the data path.
+ */
+int32_t ad9361_set_rx_sampling_freq (struct ad9361_rf_phy *phy,
+ uint32_t sampling_freq_hz)
+{
+ int32_t ret;
+ uint32_t rx[6], tx[6];
+
+ ret = ad9361_calculate_rf_clock_chain(phy, sampling_freq_hz,
+ phy->rate_governor, rx, tx);
+ if (ret < 0)
+ return ret;
+
+ ad9361_set_trx_clock_chain(phy, rx, tx);
+
+ ret = ad9361_update_rf_bandwidth(phy, phy->current_rx_bw_Hz,
+ phy->current_tx_bw_Hz);
+
+ return ret;
+}
+
+/**
+ * Get current RX sampling frequency.
+ * @param phy The AD9361 current state structure.
+ * @param sampling_freq_hz A variable to store the frequency value (Hz).
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_rx_sampling_freq (struct ad9361_rf_phy *phy,
+ uint32_t *sampling_freq_hz)
+{
+ *sampling_freq_hz = (uint32_t)clk_get_rate(phy,
+ phy->ref_clk_scale[RX_SAMPL_CLK]);
+
+ return 0;
+}
+
+/**
+ * Set the RX LO frequency.
+ * @param phy The AD9361 current state structure.
+ * @param lo_freq_hz The desired frequency (Hz).
+ * Example:
+ * 2400000000 (2.4 GHz)
+ * @return 0 in case of success, negative error code otherwise.
+ *
+ * Note: This function will/may affect the data path.
+ */
+int32_t ad9361_set_rx_lo_freq (struct ad9361_rf_phy *phy,
+ uint64_t lo_freq_hz)
+{
+ int32_t ret;
+
+ ret = clk_set_rate(phy, phy->ref_clk_scale[RX_RFPLL],
+ ad9361_to_clk(lo_freq_hz));
+
+ return ret;
+}
+
+/**
+ * Get current RX LO frequency.
+ * @param phy The AD9361 current state structure.
+ * @param lo_freq_hz A variable to store the frequency value (Hz).
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_rx_lo_freq (struct ad9361_rf_phy *phy,
+ uint64_t *lo_freq_hz)
+{
+ *lo_freq_hz = ad9361_from_clk(clk_get_rate(phy,
+ phy->ref_clk_scale[RX_RFPLL]));
+
+ return 0;
+}
+
+/**
+ * Switch between internal and external LO.
+ * @param phy The AD9361 state structure.
+ * @param int_ext The selected lo (INT_LO, EXT_LO).
+ * Accepted values:
+ * INT_LO
+ * EXT_LO
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_set_rx_lo_int_ext(struct ad9361_rf_phy *phy, uint8_t int_ext)
+{
+ if ((phy->dev_sel == ID_AD9363A) && (int_ext = EXT_LO)) {
+ printf("%s : EXT_LO is not supported by AD9363!\n", __func__);
+ return -1;
+ }
+
+ phy->pdata->use_ext_rx_lo = int_ext;
+
+ return ad9361_clk_mux_set_parent(phy->ref_clk_scale[RX_RFPLL], int_ext);
+}
+
+/**
+ * Get the RSSI for the selected channel.
+ * @param phy The AD9361 current state structure.
+ * @param ch The desired channel (RX1, RX2).
+ * Accepted values in 2x2 mode:
+ * RX1 (0)
+ * RX2 (1)
+ * Accepted values in 1x1 mode:
+ * RX1 (0)
+ * @param rssi A variable to store the RSSI.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_rx_rssi (struct ad9361_rf_phy *phy,
+ uint8_t ch, struct rf_rssi *rssi)
+{
+ int32_t ret;
+
+ if ((phy->pdata->rx2tx2 == 0) && (ch == RX2)) {
+ printf("%s : RX2 is an invalid option in 1x1 mode!\n", __func__);
+ return -1;
+ }
+
+ rssi->ant = ad9361_1rx1tx_channel_map(phy, false, ch + 1);
+ rssi->duration = 1;
+ ret = ad9361_read_rssi(phy, rssi);
+
+ return ret;
+}
+
+/**
+ * Set the gain control mode for the selected channel.
+ * @param phy The AD9361 current state structure.
+ * @param ch The desired channel (RX1, RX2).
+ * Accepted values in 2x2 mode:
+ * RX1 (0)
+ * RX2 (1)
+ * Accepted values in 1x1 mode:
+ * RX1 (0)
+ * @param gc_mode The gain control mode (manual, fast_attack, slow_attack,
+ * hybrid).
+ * Accepted values:
+ * RF_GAIN_MGC (manual)
+ * RF_GAIN_FASTATTACK_AGC (fast_attack)
+ * RF_GAIN_SLOWATTACK_AGC (slow_attack)
+ * RF_GAIN_HYBRID_AGC (hybrid)
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_set_rx_gain_control_mode (struct ad9361_rf_phy *phy,
+ uint8_t ch, uint8_t gc_mode)
+{
+ struct rf_gain_ctrl gc = {0};
+
+ if ((phy->pdata->rx2tx2 == 0) && (ch == RX2)) {
+ printf("%s : RX2 is an invalid option in 1x1 mode!\n", __func__);
+ return -1;
+ }
+
+ gc.ant = ad9361_1rx1tx_channel_map(phy, false, ch + 1);
+ gc.mode = phy->agc_mode[ch] = gc_mode;
+
+ ad9361_set_gain_ctrl_mode(phy, &gc);
+
+ return 0;
+}
+
+/**
+ * Get the gain control mode for the selected channel.
+ * @param phy The AD9361 current state structure.
+ * @param ch The desired channel (RX1, RX2).
+ * Accepted values:
+ * RX1 (0)
+ * RX2 (1)
+ * @param gc_mode A variable to store the gain control mode.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_rx_gain_control_mode (struct ad9361_rf_phy *phy,
+ uint8_t ch, uint8_t *gc_mode)
+{
+ *gc_mode = phy->agc_mode[ch];
+
+ return 0;
+}
+
+/**
+ * Set the RX FIR filter configuration.
+ * @param phy The AD9361 current state structure.
+ * @param fir_cfg FIR filter configuration.
+ * @return 0 in case of success, negative error code otherwise.
+ *
+ * Note: This function will/may affect the data path.
+ */
+int32_t ad9361_set_rx_fir_config (struct ad9361_rf_phy *phy,
+ AD9361_RXFIRConfig fir_cfg)
+{
+ int32_t ret;
+
+ phy->rx_fir_dec = fir_cfg.rx_dec;
+ ret = ad9361_load_fir_filter_coef(phy, (enum fir_dest)(fir_cfg.rx | FIR_IS_RX),
+ fir_cfg.rx_gain, fir_cfg.rx_coef_size, fir_cfg.rx_coef);
+
+ return ret;
+}
+
+/**
+ * Get the RX FIR filter configuration.
+ * @param phy The AD9361 current state structure.
+ * @param tx_ch The selected RX channel (RX1, RX2).
+ * Accepted values:
+ * RX1 (0)
+ * RX2 (1)
+ * @param fir_cfg FIR filter configuration output file.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_rx_fir_config(struct ad9361_rf_phy *phy, uint8_t rx_ch, AD9361_RXFIRConfig *fir_cfg)
+{
+ int32_t ret;
+ uint32_t fir_conf;
+ uint8_t index;
+
+ rx_ch += 1;
+
+ ret = ad9361_spi_read(phy->spi, REG_RX_FILTER_CONFIG);
+ if(ret < 0)
+ return ret;
+ fir_conf = ret;
+
+ fir_cfg->rx_coef_size = (((fir_conf & FIR_NUM_TAPS(7)) >> 5) + 1) * 16;
+
+ ret = ad9361_spi_read(phy->spi, REG_RX_FILTER_GAIN);
+ if(ret < 0)
+ return ret;
+ fir_cfg->rx_gain = -6 * (ret & FILTER_GAIN(3)) + 6;
+ fir_cfg->rx = rx_ch;
+
+ fir_conf &= ~FIR_SELECT(3);
+ fir_conf |= FIR_SELECT(rx_ch) | FIR_START_CLK;
+ ad9361_spi_write(phy->spi, REG_RX_FILTER_CONFIG, fir_conf);
+
+ for(index = 0; index < 128; index++)
+ {
+ ad9361_spi_write(phy->spi, REG_RX_FILTER_COEF_ADDR, index);
+ ret = ad9361_spi_read(phy->spi, REG_RX_FILTER_COEF_READ_DATA_1);
+ if(ret < 0)
+ return ret;
+ fir_cfg->rx_coef[index] = ret;
+ ret = ad9361_spi_read(phy->spi, REG_RX_FILTER_COEF_READ_DATA_2);
+ if(ret < 0)
+ return ret;
+ fir_cfg->rx_coef[index] |= (ret << 8);
+ }
+
+ fir_conf &= ~FIR_START_CLK;
+ ad9361_spi_write(phy->spi, REG_RX_FILTER_CONFIG, fir_conf);
+
+ fir_cfg->rx_dec = phy->rx_fir_dec;
+
+ return 0;
+}
+
+/**
+ * Enable/disable the RX FIR filter.
+ * @param phy The AD9361 current state structure.
+ * @param en_dis The option (ENABLE, DISABLE).
+ * Accepted values:
+ * ENABLE (1)
+ * DISABLE (0)
+ * @return 0 in case of success, negative error code otherwise.
+ *
+ * Note: This function will/may affect the data path.
+ */
+int32_t ad9361_set_rx_fir_en_dis (struct ad9361_rf_phy *phy,
+ uint8_t en_dis)
+{
+ int32_t ret = 0;
+
+ if(phy->bypass_rx_fir == !en_dis)
+ return ret;
+
+ phy->bypass_rx_fir = !en_dis;
+ ret = ad9361_validate_enable_fir(phy);
+ if (ret < 0) {
+ phy->bypass_rx_fir = true;
+ }
+
+ return ret;
+}
+
+/**
+ * Get the status of the RX FIR filter.
+ * @param phy The AD9361 current state structure.
+ * @param en_dis The enable/disable status buffer.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_rx_fir_en_dis (struct ad9361_rf_phy *phy,
+ uint8_t *en_dis)
+{
+ *en_dis = !phy->bypass_rx_fir;
+
+ return 0;
+}
+
+/**
+ * Enable/disable the RX RFDC Tracking.
+ * @param phy The AD9361 current state structure.
+ * @param en_dis The option (ENABLE, DISABLE).
+ * Accepted values:
+ * ENABLE (1)
+ * DISABLE (0)
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_set_rx_rfdc_track_en_dis (struct ad9361_rf_phy *phy,
+ uint8_t en_dis)
+{
+ int32_t ret = 0;
+
+ if(phy->rfdc_track_en == en_dis)
+ return ret;
+
+ phy->rfdc_track_en = en_dis;
+ ret = ad9361_tracking_control(phy, phy->bbdc_track_en,
+ phy->rfdc_track_en, phy->quad_track_en);
+
+ return ret;
+}
+
+/**
+ * Get the status of the RX RFDC Tracking.
+ * @param phy The AD9361 current state structure.
+ * @param en_dis The enable/disable status buffer.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_rx_rfdc_track_en_dis (struct ad9361_rf_phy *phy,
+ uint8_t *en_dis)
+{
+ *en_dis = phy->rfdc_track_en;
+
+ return 0;
+}
+
+/**
+ * Enable/disable the RX BasebandDC Tracking.
+ * @param phy The AD9361 current state structure.
+ * @param en_dis The option (ENABLE, DISABLE).
+ * Accepted values:
+ * ENABLE (1)
+ * DISABLE (0)
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_set_rx_bbdc_track_en_dis (struct ad9361_rf_phy *phy,
+ uint8_t en_dis)
+{
+ int32_t ret = 0;
+
+ if(phy->bbdc_track_en == en_dis)
+ return ret;
+
+ phy->bbdc_track_en = en_dis;
+ ret = ad9361_tracking_control(phy, phy->bbdc_track_en,
+ phy->rfdc_track_en, phy->quad_track_en);
+
+ return ret;
+}
+
+/**
+ * Get the status of the RX BasebandDC Tracking.
+ * @param phy The AD9361 current state structure.
+ * @param en_dis The enable/disable status buffer.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_rx_bbdc_track_en_dis (struct ad9361_rf_phy *phy,
+ uint8_t *en_dis)
+{
+ *en_dis = phy->bbdc_track_en;
+
+ return 0;
+}
+
+/**
+ * Enable/disable the RX Quadrature Tracking.
+ * @param phy The AD9361 current state structure.
+ * @param en_dis The option (ENABLE, DISABLE).
+ * Accepted values:
+ * ENABLE (1)
+ * DISABLE (0)
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_set_rx_quad_track_en_dis (struct ad9361_rf_phy *phy,
+ uint8_t en_dis)
+{
+ int32_t ret = 0;
+
+ if(phy->quad_track_en == en_dis)
+ return ret;
+
+ phy->quad_track_en = en_dis;
+ ret = ad9361_tracking_control(phy, phy->bbdc_track_en,
+ phy->rfdc_track_en, phy->quad_track_en);
+
+ return ret;
+}
+
+/**
+ * Get the status of the RX Quadrature Tracking.
+ * @param phy The AD9361 current state structure.
+ * @param en_dis The enable/disable status buffer.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_rx_quad_track_en_dis (struct ad9361_rf_phy *phy,
+ uint8_t *en_dis)
+{
+ *en_dis = phy->quad_track_en;
+
+ return 0;
+}
+
+/**
+ * Set the RX RF input port.
+ * @param phy The AD9361 current state structure.
+ * @param mode The RF port.
+ * Accepted values:
+ * A_BALANCED (0 - (RX1A_N & RX1A_P) and (RX2A_N & RX2A_P) enabled; balanced)
+ * B_BALANCED (1 - (RX1B_N & RX1B_P) and (RX2B_N & RX2B_P) enabled; balanced)
+ * C_BALANCED (2 - (RX1C_N & RX1C_P) and (RX2C_N & RX2C_P) enabled; balanced)
+ * A_N (3 - RX1A_N and RX2A_N enabled; unbalanced)
+ * A_P (4 - RX1A_P and RX2A_P enabled; unbalanced)
+ * B_N (5 - RX1B_N and RX2B_N enabled; unbalanced)
+ * B_P (6 - RX1B_P and RX2B_P enabled; unbalanced)
+ * C_N (7 - RX1C_N and RX2C_N enabled; unbalanced)
+ * C_P (8 - RX1C_P and RX2C_P enabled; unbalanced)
+ * TX_MON1 (9 - TX_MONITOR1)
+ * TX_MON2 (10 - TX_MONITOR2)
+ * TX_MON1_2 (11 - TX_MONITOR1 & TX_MONITOR2)
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_set_rx_rf_port_input (struct ad9361_rf_phy *phy,
+ uint32_t mode)
+{
+ int32_t ret;
+
+ phy->pdata->rf_rx_input_sel = mode;
+
+ ret = ad9361_rf_port_setup(phy, false,
+ phy->pdata->rf_rx_input_sel,
+ phy->pdata->rf_tx_output_sel);
+
+ return ret;
+}
+
+/**
+ * Get the selected RX RF input port.
+ * @param phy The AD9361 current state structure.
+ * @param mode The RF port.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_rx_rf_port_input (struct ad9361_rf_phy *phy,
+ uint32_t *mode)
+{
+ *mode = phy->pdata->rf_rx_input_sel;
+
+ return 0;
+}
+
+/**
+ * Store RX fastlock profile.
+ * To create a profile tune the synthesizer (ad9361_set_rx_lo_freq()) and then
+ * call this function specifying the target profile number.
+ * @param phy The AD9361 state structure.
+ * @param profile The profile number (0 - 7).
+ * Accepted values:
+ * 0 - 7
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_rx_fastlock_store(struct ad9361_rf_phy *phy, uint32_t profile)
+{
+ return ad9361_fastlock_store(phy, 0, profile);
+}
+
+/**
+ * Recall specified RX fastlock profile.
+ * When in fastlock pin select mode (init_param->rx_fastlock_pincontrol_enable),
+ * the function needs to be called before then the pin-control can be used.
+ * @param phy The AD9361 state structure.
+ * @param profile The profile number (0 - 7).
+ * Accepted values:
+ * 0 - 7
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_rx_fastlock_recall(struct ad9361_rf_phy *phy, uint32_t profile)
+{
+ return ad9361_fastlock_recall(phy, 0, profile);
+}
+
+/**
+ * Load RX fastlock profile. A previously saved profile can be loaded in any
+ * of the 8 available slots.
+ * @param phy The AD9361 state structure.
+ * @param profile The profile number (0 - 7).
+ * Accepted values:
+ * 0 - 7
+ * @param values Fastlock profile program data.
+ * Example:
+ * val0,val1,val2,Â…,val15
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_rx_fastlock_load(struct ad9361_rf_phy *phy, uint32_t profile, uint8_t *values)
+{
+ return ad9361_fastlock_load(phy, 0, profile, values);
+}
+
+/**
+ * Save RX fastlock profile. In order to use more than 8 Profiles, an existing
+ * profile can be read back and stored by the user application.
+ * @param phy The AD9361 state structure.
+ * @param profile The profile number (0 - 7).
+ * Accepted values:
+ * 0 - 7
+ * @param values Fastlock profile program data.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_rx_fastlock_save(struct ad9361_rf_phy *phy, uint32_t profile, uint8_t *values)
+{
+ return ad9361_fastlock_save(phy, 0, profile, values);
+}
+
+/**
+ * Set the transmit attenuation for the selected channel.
+ * @param phy The AD9361 current state structure.
+ * @param ch The desired channel number (TX1, TX2).
+ * Accepted values in 2x2 mode:
+ * TX1 (0)
+ * TX2 (1)
+ * Accepted values in 1x1 mode:
+ * TX1 (0)
+ * @param attenuation_mdb The attenuation (mdB).
+ * Example:
+ * 10000 (10 dB)
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_set_tx_attenuation (struct ad9361_rf_phy *phy,
+ uint8_t ch, uint32_t attenuation_mdb)
+{
+ int32_t ret;
+ int32_t channel;
+
+ if ((phy->pdata->rx2tx2 == 0) && (ch == TX2)) {
+ printf("%s : TX2 is an invalid option in 1x1 mode!\n", __func__);
+ return -1;
+ }
+
+ channel = ad9361_1rx1tx_channel_map(phy, true, ch);
+ ret = ad9361_set_tx_atten(phy, attenuation_mdb,
+ channel == 0, channel == 1,
+ !phy->pdata->update_tx_gain_via_alert);
+
+ return ret;
+}
+
+/**
+ * Get current transmit attenuation for the selected channel.
+ * @param phy The AD9361 current state structure.
+ * @param ch The desired channel number (TX1, TX2).
+ * Accepted values in 2x2 mode:
+ * TX1 (0)
+ * TX2 (1)
+ * Accepted values in 1x1 mode:
+ * TX1 (0)
+ * @param attenuation_mdb A variable to store the attenuation value (mdB).
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_tx_attenuation (struct ad9361_rf_phy *phy,
+ uint8_t ch, uint32_t *attenuation_db)
+{
+ int32_t ret;
+
+ if ((phy->pdata->rx2tx2 == 0) && (ch == TX2)) {
+ printf("%s : TX2 is an invalid option in 1x1 mode!\n", __func__);
+ return -1;
+ }
+
+ ret = ad9361_get_tx_atten(phy,
+ ad9361_1rx1tx_channel_map(phy, true,
+ ch + 1));
+
+ if(ret < 0)
+ return ret;
+ *attenuation_db = ret;
+
+ return 0;
+}
+
+/**
+ * Set the TX RF bandwidth.
+ * @param phy The AD9361 current state structure.
+ * @param bandwidth_hz The desired bandwidth (Hz).
+ * Example:
+ * 18000000 (18 MHz)
+ * @return 0 in case of success, negative error code otherwise.
+ *
+ * Note: This function will/may affect the data path.
+ */
+int32_t ad9361_set_tx_rf_bandwidth (struct ad9361_rf_phy *phy,
+ uint32_t bandwidth_hz)
+{
+ int32_t ret = 0;
+
+ bandwidth_hz = ad9361_validate_rf_bw(phy, bandwidth_hz);
+
+ if (phy->current_tx_bw_Hz != bandwidth_hz)
+ ret = ad9361_update_rf_bandwidth(phy,
+ phy->current_rx_bw_Hz, bandwidth_hz);
+ else
+ ret = 0;
+
+ return ret;
+}
+
+/**
+ * Get the TX RF bandwidth.
+ * @param phy The AD9361 current state structure.
+ * @param bandwidth_hz A variable to store the bandwidth value (Hz).
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_tx_rf_bandwidth (struct ad9361_rf_phy *phy,
+ uint32_t *bandwidth_hz)
+{
+ *bandwidth_hz = phy->current_tx_bw_Hz;
+
+ return 0;
+}
+
+/**
+ * Set the TX sampling frequency.
+ * @param phy The AD9361 current state structure.
+ * @param sampling_freq_hz The desired frequency (Hz).
+ * Example:
+ * 30720000 (30.72 MHz)
+ * @return 0 in case of success, negative error code otherwise.
+ *
+ * Note: This function will/may affect the data path.
+ */
+int32_t ad9361_set_tx_sampling_freq (struct ad9361_rf_phy *phy,
+ uint32_t sampling_freq_hz)
+{
+ int32_t ret;
+ uint32_t rx[6], tx[6];
+
+ ret = ad9361_calculate_rf_clock_chain(phy, sampling_freq_hz,
+ phy->rate_governor, rx, tx);
+ if (ret < 0)
+ return ret;
+
+ ad9361_set_trx_clock_chain(phy, rx, tx);
+
+ ret = ad9361_update_rf_bandwidth(phy, phy->current_rx_bw_Hz,
+ phy->current_tx_bw_Hz);
+
+ return ret;
+}
+
+/**
+ * Get current TX sampling frequency.
+ * @param phy The AD9361 current state structure.
+ * @param sampling_freq_hz A variable to store the frequency value (Hz).
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_tx_sampling_freq (struct ad9361_rf_phy *phy,
+ uint32_t *sampling_freq_hz)
+{
+ *sampling_freq_hz = (uint32_t)clk_get_rate(phy,
+ phy->ref_clk_scale[TX_SAMPL_CLK]);
+
+ return 0;
+}
+
+/**
+ * Set the TX LO frequency.
+ * @param phy The AD9361 current state structure.
+ * @param lo_freq_hz The desired frequency (Hz).
+ * Example:
+ * 2400000000 (2.4 GHz)
+ * @return 0 in case of success, negative error code otherwise.
+ *
+ * Note: This function will/may affect the data path.
+ */
+int32_t ad9361_set_tx_lo_freq (struct ad9361_rf_phy *phy,
+ uint64_t lo_freq_hz)
+{
+ int32_t ret;
+
+ ret = clk_set_rate(phy, phy->ref_clk_scale[TX_RFPLL],
+ ad9361_to_clk(lo_freq_hz));
+
+ return ret;
+}
+
+/**
+ * Get current TX LO frequency.
+ * @param phy The AD9361 current state structure.
+ * @param lo_freq_hz A variable to store the frequency value (Hz).
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_tx_lo_freq (struct ad9361_rf_phy *phy,
+ uint64_t *lo_freq_hz)
+{
+ *lo_freq_hz = ad9361_from_clk(clk_get_rate(phy,
+ phy->ref_clk_scale[TX_RFPLL]));
+
+ return 0;
+}
+
+/**
+ * Switch between internal and external LO.
+ * @param phy The AD9361 state structure.
+ * @param int_ext The selected lo (INT_LO, EXT_LO).
+ * Accepted values:
+ * INT_LO
+ * EXT_LO
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_set_tx_lo_int_ext(struct ad9361_rf_phy *phy, uint8_t int_ext)
+{
+ if ((phy->dev_sel == ID_AD9363A) && (int_ext = EXT_LO)) {
+ printf("%s : EXT_LO is not supported by AD9363!\n", __func__);
+ return -1;
+ }
+
+ phy->pdata->use_ext_tx_lo = int_ext;
+
+ return ad9361_clk_mux_set_parent(phy->ref_clk_scale[TX_RFPLL], int_ext);
+}
+
+/**
+ * Set the TX FIR filter configuration.
+ * @param phy The AD9361 current state structure.
+ * @param fir_cfg FIR filter configuration.
+ * @return 0 in case of success, negative error code otherwise.
+ *
+ * Note: This function will/may affect the data path.
+ */
+int32_t ad9361_set_tx_fir_config (struct ad9361_rf_phy *phy,
+ AD9361_TXFIRConfig fir_cfg)
+{
+ int32_t ret;
+
+ phy->tx_fir_int = fir_cfg.tx_int;
+ ret = ad9361_load_fir_filter_coef(phy, (enum fir_dest)fir_cfg.tx,
+ fir_cfg.tx_gain, fir_cfg.tx_coef_size, fir_cfg.tx_coef);
+
+ return ret;
+}
+
+/**
+ * Get the TX FIR filter configuration.
+ * @param phy The AD9361 current state structure.
+ * @param tx_ch The selected TX channel (TX1, TX2).
+ * Accepted values:
+ * TX1 (0)
+ * TX2 (1)
+ * @param fir_cfg FIR filter configuration output file.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_tx_fir_config(struct ad9361_rf_phy *phy, uint8_t tx_ch, AD9361_TXFIRConfig *fir_cfg)
+{
+ int32_t ret;
+ uint32_t fir_conf;
+ uint8_t index;
+
+ tx_ch += 1;
+
+ ret = ad9361_spi_read(phy->spi, REG_TX_FILTER_CONF);
+ if(ret < 0)
+ return ret;
+ fir_conf = ret;
+ fir_cfg->tx_coef_size = (((fir_conf & FIR_NUM_TAPS(7)) >> 5) + 1) * 16;
+ fir_cfg->tx_gain = -6 * (fir_conf & TX_FIR_GAIN_6DB);
+ fir_cfg->tx = tx_ch;
+
+ fir_conf &= ~FIR_SELECT(3);
+ fir_conf |= FIR_SELECT(tx_ch) | FIR_START_CLK;
+ ad9361_spi_write(phy->spi, REG_TX_FILTER_CONF, fir_conf);
+
+ for(index = 0; index < 128; index++)
+ {
+ ad9361_spi_write(phy->spi, REG_TX_FILTER_COEF_ADDR, index);
+ ret = ad9361_spi_read(phy->spi, REG_TX_FILTER_COEF_READ_DATA_1);
+ if(ret < 0)
+ return ret;
+ fir_cfg->tx_coef[index] = ret;
+ ret = ad9361_spi_read(phy->spi, REG_TX_FILTER_COEF_READ_DATA_2);
+ if(ret < 0)
+ return ret;
+ fir_cfg->tx_coef[index] |= (ret << 8);
+ }
+
+ fir_conf &= ~FIR_START_CLK;
+ ad9361_spi_write(phy->spi, REG_TX_FILTER_CONF, fir_conf);
+
+ fir_cfg->tx_int = phy->tx_fir_int;
+
+ return 0;
+}
+
+/**
+ * Enable/disable the TX FIR filter.
+ * @param phy The AD9361 current state structure.
+ * @param en_dis The option (ENABLE, DISABLE).
+ * Accepted values:
+ * ENABLE (1)
+ * DISABLE (0)
+ * @return 0 in case of success, negative error code otherwise.
+ *
+ * Note: This function will/may affect the data path.
+ */
+int32_t ad9361_set_tx_fir_en_dis (struct ad9361_rf_phy *phy,
+ uint8_t en_dis)
+{
+ int32_t ret = 0;
+
+ if(phy->bypass_tx_fir == !en_dis)
+ return ret;
+
+ phy->bypass_tx_fir = !en_dis;
+ ret = ad9361_validate_enable_fir(phy);
+ if (ret < 0) {
+ phy->bypass_tx_fir = true;
+ }
+
+ return ret;
+}
+
+/**
+ * Get the status of the TX FIR filter.
+ * @param phy The AD9361 current state structure.
+ * @param en_dis The enable/disable status buffer.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_tx_fir_en_dis (struct ad9361_rf_phy *phy,
+ uint8_t *en_dis)
+{
+ *en_dis = !phy->bypass_tx_fir;
+
+ return 0;
+}
+
+/**
+ * Get the TX RSSI for the selected channel (TX_MON should be enabled).
+ * @param phy The AD9361 current state structure.
+ * @param ch The desired channel (TX1, TX2).
+ * Accepted values:
+ * TX1 (0)
+ * TX2 (1)
+ * @param rssi_db_x_1000 A variable to store the RSSI.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_tx_rssi (struct ad9361_rf_phy *phy,
+ uint8_t ch,
+ uint32_t *rssi_db_x_1000)
+{
+ uint8_t reg_val_buf[3];
+ uint32_t val;
+ int32_t ret;
+
+ ret = ad9361_spi_readm(phy->spi, REG_TX_RSSI_LSB,
+ reg_val_buf, ARRAY_SIZE(reg_val_buf));
+ if (ret < 0) {
+ return ret;
+ }
+
+ switch (ch) {
+ case 0:
+ val = (reg_val_buf[2] << 1) | (reg_val_buf[0] & TX_RSSI_1);
+ break;
+ case 1:
+ val = (reg_val_buf[1] << 1) | ((reg_val_buf[0] & TX_RSSI_2) >> 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ val *= RSSI_RESOLUTION;
+
+ *rssi_db_x_1000 = ((val / RSSI_MULTIPLIER) * 1000) +
+ (val % RSSI_MULTIPLIER);
+
+ return 0;
+}
+
+/**
+ * Set the TX RF output port.
+ * @param phy The AD9361 current state structure.
+ * @param mode The RF port.
+ * Accepted values:
+ * TXA (0)
+ * TXB (1)
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_set_tx_rf_port_output (struct ad9361_rf_phy *phy,
+ uint32_t mode)
+{
+ int32_t ret;
+
+ phy->pdata->rf_tx_output_sel = mode;
+
+ ret = ad9361_rf_port_setup(phy, true,
+ phy->pdata->rf_rx_input_sel,
+ phy->pdata->rf_tx_output_sel);
+
+ return ret;
+}
+
+/**
+ * Get the selected TX RF output port.
+ * @param phy The AD9361 current state structure.
+ * @param mode The RF port.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_tx_rf_port_output (struct ad9361_rf_phy *phy,
+ uint32_t *mode)
+{
+ *mode = phy->pdata->rf_tx_output_sel;
+
+ return 0;
+}
+
+/**
+ * Enable/disable the auto calibration.
+ * @param phy The AD9361 current state structure.
+ * @param en_dis The option (ENABLE, DISABLE).
+ * Accepted values:
+ * ENABLE (1)
+ * DISABLE (0)
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_set_tx_auto_cal_en_dis (struct ad9361_rf_phy *phy, uint8_t en_dis)
+{
+ if (en_dis == 0)
+ phy->auto_cal_en = 0;
+ else
+ phy->auto_cal_en = 1;
+
+ return 0;
+}
+
+/**
+ * Get the status of the auto calibration flag.
+ * @param phy The AD9361 current state structure.
+ * @param en_dis The enable/disable status buffer.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_tx_auto_cal_en_dis (struct ad9361_rf_phy *phy, uint8_t *en_dis)
+{
+ *en_dis = phy->auto_cal_en;
+
+ return 0;
+}
+
+/**
+ * Store TX fastlock profile.
+ * To create a profile tune the synthesizer (ad9361_set_tx_lo_freq()) and then
+ * call this function specifying the target profile number.
+ * @param phy The AD9361 state structure.
+ * @param profile The profile number (0 - 7).
+ * Accepted values:
+ * 0 - 7
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_tx_fastlock_store(struct ad9361_rf_phy *phy, uint32_t profile)
+{
+ return ad9361_fastlock_store(phy, 1, profile);
+}
+
+/**
+ * Recall specified TX fastlock profile.
+ * When in fastlock pin select mode (init_param->tx_fastlock_pincontrol_enable),
+ * the function needs to be called before then the pin-control can be used.
+ * @param phy The AD9361 state structure.
+ * @param profile The profile number (0 - 7).
+ * Accepted values:
+ * 0 - 7
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_tx_fastlock_recall(struct ad9361_rf_phy *phy, uint32_t profile)
+{
+ return ad9361_fastlock_recall(phy, 1, profile);
+}
+
+/**
+ * Load TX fastlock profile. A previously saved profile can be loaded in any
+ * of the 8 available slots.
+ * @param phy The AD9361 state structure.
+ * @param profile The profile number (0 - 7).
+ * Accepted values:
+ * 0 - 7
+ * @param values Fastlock profile program data.
+ * Example:
+ * val0,val1,val2,Â…,val15
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_tx_fastlock_load(struct ad9361_rf_phy *phy, uint32_t profile, uint8_t *values)
+{
+ return ad9361_fastlock_load(phy, 1, profile, values);
+}
+
+/**
+ * Save TX fastlock profile. In order to use more than 8 Profiles, an existing
+ * profile can be read back and stored by the user application.
+ * @param phy The AD9361 state structure.
+ * @param profile The profile number (0 - 7).
+ * Accepted values:
+ * 0 - 7
+ * @param values Fastlock profile program data.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_tx_fastlock_save(struct ad9361_rf_phy *phy, uint32_t profile, uint8_t *values)
+{
+ return ad9361_fastlock_save(phy, 1, profile, values);
+}
+
+/**
+ * Set the RX and TX path rates.
+ * @param phy The AD9361 state structure.
+ * @param rx_path_clks RX path rates buffer.
+ * @param tx_path_clks TX path rates buffer.
+ * @return 0 in case of success, negative error code otherwise.
+ *
+ * Note: This function will/may affect the data path.
+ */
+int32_t ad9361_set_trx_path_clks(struct ad9361_rf_phy *phy,
+ uint32_t *rx_path_clks,
+ uint32_t *tx_path_clks)
+{
+ int32_t ret;
+
+ ret = ad9361_set_trx_clock_chain(phy, rx_path_clks, tx_path_clks);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9361_update_rf_bandwidth(phy, phy->current_rx_bw_Hz,
+ phy->current_tx_bw_Hz);
+
+ return ret;
+}
+
+/**
+ * Get the RX and TX path rates.
+ * @param phy The AD9361 state structure.
+ * @param rx_path_clks RX path rates buffer.
+ * @param tx_path_clks TX path rates buffer.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_trx_path_clks(struct ad9361_rf_phy *phy,
+ uint32_t *rx_path_clks,
+ uint32_t *tx_path_clks)
+{
+ return ad9361_get_trx_clock_chain(phy, rx_path_clks, tx_path_clks);
+}
+
+/**
+ * Set the number of channels mode.
+ * @param phy The AD9361 state structure.
+ * @param ch_mode Number of channels mode (MODE_1x1, MODE_2x2).
+ * Accepted values:
+ * MODE_1x1 (1)
+ * MODE_2x2 (2)
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_set_no_ch_mode(struct ad9361_rf_phy *phy, uint8_t no_ch_mode)
+{
+ switch (no_ch_mode) {
+ case 1:
+ phy->pdata->rx2tx2 = 0;
+ break;
+ case 2:
+ phy->pdata->rx2tx2 = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+#ifndef AXI_ADC_NOT_PRESENT
+ phy->adc_conv->chip_info = &axiadc_chip_info_tbl[phy->pdata->rx2tx2 ? ID_AD9361 : ID_AD9364];
+#endif
+ ad9361_reset(phy);
+ ad9361_spi_write(phy->spi, REG_SPI_CONF, SOFT_RESET | _SOFT_RESET);
+ ad9361_spi_write(phy->spi, REG_SPI_CONF, 0x0);
+
+ phy->clks[TX_REFCLK]->rate = ad9361_clk_factor_recalc_rate(phy->ref_clk_scale[TX_REFCLK], phy->clk_refin->rate);
+ phy->clks[TX_REFCLK]->rate = ad9361_clk_factor_recalc_rate(phy->ref_clk_scale[TX_REFCLK], phy->clk_refin->rate);
+ phy->clks[RX_REFCLK]->rate = ad9361_clk_factor_recalc_rate(phy->ref_clk_scale[RX_REFCLK], phy->clk_refin->rate);
+ phy->clks[BB_REFCLK]->rate = ad9361_clk_factor_recalc_rate(phy->ref_clk_scale[BB_REFCLK], phy->clk_refin->rate);
+ phy->clks[BBPLL_CLK]->rate = ad9361_bbpll_recalc_rate(phy->ref_clk_scale[BBPLL_CLK], phy->clks[BB_REFCLK]->rate);
+ phy->clks[ADC_CLK]->rate = ad9361_clk_factor_recalc_rate(phy->ref_clk_scale[ADC_CLK], phy->clks[BBPLL_CLK]->rate);
+ phy->clks[R2_CLK]->rate = ad9361_clk_factor_recalc_rate(phy->ref_clk_scale[R2_CLK], phy->clks[ADC_CLK]->rate);
+ phy->clks[R1_CLK]->rate = ad9361_clk_factor_recalc_rate(phy->ref_clk_scale[R1_CLK], phy->clks[R2_CLK]->rate);
+ phy->clks[CLKRF_CLK]->rate = ad9361_clk_factor_recalc_rate(phy->ref_clk_scale[CLKRF_CLK], phy->clks[R1_CLK]->rate);
+ phy->clks[RX_SAMPL_CLK]->rate = ad9361_clk_factor_recalc_rate(phy->ref_clk_scale[RX_SAMPL_CLK], phy->clks[CLKRF_CLK]->rate);
+ phy->clks[DAC_CLK]->rate = ad9361_clk_factor_recalc_rate(phy->ref_clk_scale[DAC_CLK], phy->clks[ADC_CLK]->rate);
+ phy->clks[T2_CLK]->rate = ad9361_clk_factor_recalc_rate(phy->ref_clk_scale[T2_CLK], phy->clks[DAC_CLK]->rate);
+ phy->clks[T1_CLK]->rate = ad9361_clk_factor_recalc_rate(phy->ref_clk_scale[T1_CLK], phy->clks[T2_CLK]->rate);
+ phy->clks[CLKTF_CLK]->rate = ad9361_clk_factor_recalc_rate(phy->ref_clk_scale[CLKTF_CLK], phy->clks[T1_CLK]->rate);
+ phy->clks[TX_SAMPL_CLK]->rate = ad9361_clk_factor_recalc_rate(phy->ref_clk_scale[TX_SAMPL_CLK], phy->clks[CLKTF_CLK]->rate);
+ phy->clks[RX_RFPLL_INT]->rate = ad9361_rfpll_int_recalc_rate(phy->ref_clk_scale[RX_RFPLL_INT], phy->clks[RX_REFCLK]->rate);
+ phy->clks[TX_RFPLL_INT]->rate = ad9361_rfpll_int_recalc_rate(phy->ref_clk_scale[TX_RFPLL_INT], phy->clks[TX_REFCLK]->rate);
+ phy->clks[RX_RFPLL_DUMMY]->rate = ad9361_rfpll_dummy_recalc_rate(phy->ref_clk_scale[RX_RFPLL_DUMMY]);
+ phy->clks[TX_RFPLL_DUMMY]->rate = ad9361_rfpll_dummy_recalc_rate(phy->ref_clk_scale[TX_RFPLL_DUMMY]);
+ phy->clks[RX_RFPLL]->rate = ad9361_rfpll_recalc_rate(phy->ref_clk_scale[RX_RFPLL]);
+ phy->clks[TX_RFPLL]->rate = ad9361_rfpll_recalc_rate(phy->ref_clk_scale[TX_RFPLL]);
+
+#ifndef AXI_ADC_NOT_PRESENT
+#ifdef NUAND_MODIFICATIONS
+ // use alternate axiadc accessors
+ axiadc_init(phy, phy->adc_state->userdata);
+#else
+ axiadc_init(phy);
+#endif // NUAND_MODIFICATIONS
+#endif
+
+ ad9361_setup(phy);
+#ifndef AXI_ADC_NOT_PRESENT
+ /* platform specific wrapper to call ad9361_post_setup() */
+ axiadc_post_setup(phy);
+#endif
+
+ return 0;
+}
+
+/**
+ * Do multi chip synchronization.
+ * @param phy_master The AD9361 Master state structure.
+ * @param phy_slave The AD9361 Slave state structure.
+ * @return 0 in case of success, negative error code otherwise.
+ *
+ * Note: This function will/may affect the data path.
+ */
+int32_t ad9361_do_mcs(struct ad9361_rf_phy *phy_master, struct ad9361_rf_phy *phy_slave)
+{
+ uint32_t ensm_mode;
+ int32_t step;
+ int32_t reg;
+
+ if ((phy_master->dev_sel == ID_AD9363A) ||
+ (phy_slave->dev_sel == ID_AD9363A)) {
+ printf("%s : MCS is not supported by AD9363!\n", __func__);
+ return -1;
+ }
+
+ reg = ad9361_spi_read(phy_master->spi, REG_RX_CLOCK_DATA_DELAY);
+ ad9361_spi_write(phy_slave->spi, REG_RX_CLOCK_DATA_DELAY, reg);
+ reg = ad9361_spi_read(phy_master->spi, REG_TX_CLOCK_DATA_DELAY);
+ ad9361_spi_write(phy_slave->spi, REG_TX_CLOCK_DATA_DELAY, reg);
+
+ ad9361_get_en_state_machine_mode(phy_master, &ensm_mode);
+
+ ad9361_set_en_state_machine_mode(phy_master, ENSM_MODE_ALERT);
+ ad9361_set_en_state_machine_mode(phy_slave, ENSM_MODE_ALERT);
+
+ for (step = 0; step <= 5; step++)
+ {
+ ad9361_mcs(phy_slave, step);
+ ad9361_mcs(phy_master, step);
+ mdelay(100);
+ }
+
+ ad9361_set_en_state_machine_mode(phy_master, ensm_mode);
+ ad9361_set_en_state_machine_mode(phy_slave, ensm_mode);
+
+ return 0;
+}
+
+/**
+ * Enable/disable the TRX FIR filters.
+ * @param phy The AD9361 current state structure.
+ * @param en_dis The option (ENABLE, DISABLE).
+ * Accepted values:
+ * ENABLE (1)
+ * DISABLE (0)
+ * @return 0 in case of success, negative error code otherwise.
+ *
+ * Note: This function will/may affect the data path.
+ */
+int32_t ad9361_set_trx_fir_en_dis (struct ad9361_rf_phy *phy,
+ uint8_t en_dis)
+{
+ int32_t ret = 0;
+
+ if ((phy->bypass_rx_fir == phy->bypass_tx_fir) &&
+ (phy->bypass_rx_fir == !en_dis))
+ return ret;
+
+ phy->bypass_rx_fir = !en_dis;
+ phy->bypass_tx_fir = !en_dis;
+ ret = ad9361_validate_enable_fir(phy);
+ if (ret < 0) {
+ phy->bypass_rx_fir = true;
+ phy->bypass_tx_fir = true;
+ }
+
+ return ret;
+}
+
+/**
+ * Set the OSR rate governor.
+ * @param phy The AD9361 current state structure.
+ * @param rate_gov OSR rate governor (highest, nominal).
+ * Accepted values:
+ * HIGHEST_OSR (0 - highest OSR)
+ * NOMINAL_OSR (1 - nominal)
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_set_trx_rate_gov (struct ad9361_rf_phy *phy, uint32_t rate_gov)
+{
+ if (rate_gov == 0)
+ phy->rate_governor = 0;
+ else
+ phy->rate_governor = 1;
+
+ return 0;
+}
+
+/**
+ * Get the OSR rate governor.
+ * @param phy The AD9361 current state structure.
+ * @param rate_gov Option buffer.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_get_trx_rate_gov (struct ad9361_rf_phy *phy, uint32_t *rate_gov)
+{
+ *rate_gov = phy->rate_governor;
+
+ return 0;
+}
+
+/**
+ * Perform the selected calibration.
+ * @param phy The AD9361 state structure.
+ * @param cal The selected calibration (TX_QUAD_CAL, RFDC_CAL).
+ * Accepted values:
+ * TX_QUAD_CAL
+ * RFDC_CAL
+ * @param arg For TX_QUAD_CAL - the optional RX phase value overwrite (set to zero).
+ * @return 0 in case of success, negative error code otherwise.
+ *
+ * Note: This function will/may affect the data path.
+ */
+int32_t ad9361_do_calib(struct ad9361_rf_phy *phy, uint32_t cal, int32_t arg)
+{
+ return ad9361_do_calib_run(phy, cal, arg);
+}
+
+/**
+ * Load and enable TRX FIR filters configurations.
+ * @param phy The AD9361 current state structure.
+ * @param rx_fir_cfg RX FIR filter configuration.
+ * @param tx_fir_cfg TX FIR filter configuration.
+ * @return 0 in case of success, negative error code otherwise.
+ *
+ * Note: This function will/may affect the data path.
+ */
+int32_t ad9361_trx_load_enable_fir(struct ad9361_rf_phy *phy,
+ AD9361_RXFIRConfig rx_fir_cfg,
+ AD9361_TXFIRConfig tx_fir_cfg)
+{
+ int32_t rtx = -1, rrx = -1;
+
+ phy->filt_rx_bw_Hz = 0;
+ phy->filt_tx_bw_Hz = 0;
+ phy->filt_valid = false;
+
+ if (tx_fir_cfg.tx_path_clks[TX_SAMPL_FREQ]) {
+ memcpy(phy->filt_tx_path_clks, tx_fir_cfg.tx_path_clks,
+ sizeof(phy->filt_tx_path_clks));
+ rtx = 0;
+ }
+
+ if (rx_fir_cfg.rx_path_clks[RX_SAMPL_FREQ]) {
+ memcpy(phy->filt_rx_path_clks, rx_fir_cfg.rx_path_clks,
+ sizeof(phy->filt_rx_path_clks));
+ rrx = 0;
+ }
+
+ if (tx_fir_cfg.tx_bandwidth) {
+ phy->filt_tx_bw_Hz = tx_fir_cfg.tx_bandwidth;
+ }
+
+ if (rx_fir_cfg.rx_bandwidth) {
+ phy->filt_rx_bw_Hz = rx_fir_cfg.rx_bandwidth;
+ }
+
+ ad9361_set_tx_fir_config(phy, tx_fir_cfg);
+ ad9361_set_rx_fir_config(phy, rx_fir_cfg);
+
+ if (!(rrx | rtx))
+ phy->filt_valid = true;
+
+ ad9361_set_trx_fir_en_dis(phy, 1);
+
+ return 0;
+}
+
+/**
+ * Do DCXO coarse tuning.
+ * @param phy The AD9361 current state structure.
+ * @param coarse The DCXO coarse tuning value.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_do_dcxo_tune_coarse(struct ad9361_rf_phy *phy,
+ uint32_t coarse)
+{
+ phy->pdata->dcxo_coarse = coarse;
+
+ return ad9361_set_dcxo_tune(phy, phy->pdata->dcxo_coarse,
+ phy->pdata->dcxo_fine);
+}
+
+/**
+ * Do DCXO fine tuning.
+ * @param phy The AD9361 current state structure.
+ * @param fine The DCXO fine tuning value.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_do_dcxo_tune_fine(struct ad9361_rf_phy *phy,
+ uint32_t fine)
+{
+ phy->pdata->dcxo_fine = fine;
+
+ return ad9361_set_dcxo_tune(phy, phy->pdata->dcxo_coarse,
+ phy->pdata->dcxo_fine);
+}
diff --git a/Radio/HW/BladeRF/common/thirdparty/ad936x/ad9361_api.h b/Radio/HW/BladeRF/common/thirdparty/ad936x/ad9361_api.h
new file mode 100644
index 0000000..ff5d7c5
--- /dev/null
+++ b/Radio/HW/BladeRF/common/thirdparty/ad936x/ad9361_api.h
@@ -0,0 +1,506 @@
+/***************************************************************************//**
+ * @file ad9361_api.h
+ * @brief Header file of AD9361 API Driver.
+ * @author DBogdan (dragos.bogdan@analog.com)
+********************************************************************************
+ * Copyright 2013(c) Analog Devices, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of Analog Devices, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * - The use of this software may or may not infringe the patent rights
+ * of one or more patent holders. This license does not release you
+ * from the requirement that you obtain separate licenses from these
+ * patent holders to use this software.
+ * - Use of the software either in source or binary form, must be run
+ * on or directly connected to an Analog Devices Inc. component.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+#ifndef AD9361_API_H_
+#define AD9361_API_H_
+
+/******************************************************************************/
+/***************************** Include Files **********************************/
+/******************************************************************************/
+#include "util.h"
+
+/******************************************************************************/
+/*************************** Types Declarations *******************************/
+/******************************************************************************/
+typedef struct
+{
+ /* Device selection */
+ enum dev_id dev_sel;
+ /* Identification number */
+ uint8_t id_no;
+ /* Reference Clock */
+ uint32_t reference_clk_rate;
+ /* Base Configuration */
+ uint8_t two_rx_two_tx_mode_enable; /* adi,2rx-2tx-mode-enable */
+ uint8_t one_rx_one_tx_mode_use_rx_num; /* adi,1rx-1tx-mode-use-rx-num */
+ uint8_t one_rx_one_tx_mode_use_tx_num; /* adi,1rx-1tx-mode-use-tx-num */
+ uint8_t frequency_division_duplex_mode_enable; /* adi,frequency-division-duplex-mode-enable */
+ uint8_t frequency_division_duplex_independent_mode_enable; /* adi,frequency-division-duplex-independent-mode-enable */
+ uint8_t tdd_use_dual_synth_mode_enable; /* adi,tdd-use-dual-synth-mode-enable */
+ uint8_t tdd_skip_vco_cal_enable; /* adi,tdd-skip-vco-cal-enable */
+ uint32_t tx_fastlock_delay_ns; /* adi,tx-fastlock-delay-ns */
+ uint32_t rx_fastlock_delay_ns; /* adi,rx-fastlock-delay-ns */
+ uint8_t rx_fastlock_pincontrol_enable; /* adi,rx-fastlock-pincontrol-enable */
+ uint8_t tx_fastlock_pincontrol_enable; /* adi,tx-fastlock-pincontrol-enable */
+ uint8_t external_rx_lo_enable; /* adi,external-rx-lo-enable */
+ uint8_t external_tx_lo_enable; /* adi,external-tx-lo-enable */
+ uint8_t dc_offset_tracking_update_event_mask; /* adi,dc-offset-tracking-update-event-mask */
+ uint8_t dc_offset_attenuation_high_range; /* adi,dc-offset-attenuation-high-range */
+ uint8_t dc_offset_attenuation_low_range; /* adi,dc-offset-attenuation-low-range */
+ uint8_t dc_offset_count_high_range; /* adi,dc-offset-count-high-range */
+ uint8_t dc_offset_count_low_range; /* adi,dc-offset-count-low-range */
+ uint8_t split_gain_table_mode_enable; /* adi,split-gain-table-mode-enable */
+ uint32_t trx_synthesizer_target_fref_overwrite_hz; /* adi,trx-synthesizer-target-fref-overwrite-hz */
+ uint8_t qec_tracking_slow_mode_enable; /* adi,qec-tracking-slow-mode-enable */
+ /* ENSM Control */
+ uint8_t ensm_enable_pin_pulse_mode_enable; /* adi,ensm-enable-pin-pulse-mode-enable */
+ uint8_t ensm_enable_txnrx_control_enable; /* adi,ensm-enable-txnrx-control-enable */
+ /* LO Control */
+ uint64_t rx_synthesizer_frequency_hz; /* adi,rx-synthesizer-frequency-hz */
+ uint64_t tx_synthesizer_frequency_hz; /* adi,tx-synthesizer-frequency-hz */
+ /* Rate & BW Control */
+ uint32_t rx_path_clock_frequencies[6]; /* adi,rx-path-clock-frequencies */
+ uint32_t tx_path_clock_frequencies[6]; /* adi,tx-path-clock-frequencies */
+ uint32_t rf_rx_bandwidth_hz; /* adi,rf-rx-bandwidth-hz */
+ uint32_t rf_tx_bandwidth_hz; /* adi,rf-tx-bandwidth-hz */
+ /* RF Port Control */
+ uint32_t rx_rf_port_input_select; /* adi,rx-rf-port-input-select */
+ uint32_t tx_rf_port_input_select; /* adi,tx-rf-port-input-select */
+ /* TX Attenuation Control */
+ int32_t tx_attenuation_mdB; /* adi,tx-attenuation-mdB */
+ uint8_t update_tx_gain_in_alert_enable; /* adi,update-tx-gain-in-alert-enable */
+ /* Reference Clock Control */
+ uint8_t xo_disable_use_ext_refclk_enable; /* adi,xo-disable-use-ext-refclk-enable */
+ uint32_t dcxo_coarse_and_fine_tune[2]; /* adi,dcxo-coarse-and-fine-tune */
+ uint32_t clk_output_mode_select; /* adi,clk-output-mode-select */
+ /* Gain Control */
+ uint8_t gc_rx1_mode; /* adi,gc-rx1-mode */
+ uint8_t gc_rx2_mode; /* adi,gc-rx2-mode */
+ uint8_t gc_adc_large_overload_thresh; /* adi,gc-adc-large-overload-thresh */
+ uint8_t gc_adc_ovr_sample_size; /* adi,gc-adc-ovr-sample-size */
+ uint8_t gc_adc_small_overload_thresh; /* adi,gc-adc-small-overload-thresh */
+ uint16_t gc_dec_pow_measurement_duration; /* adi,gc-dec-pow-measurement-duration */
+ uint8_t gc_dig_gain_enable; /* adi,gc-dig-gain-enable */
+ uint16_t gc_lmt_overload_high_thresh; /* adi,gc-lmt-overload-high-thresh */
+ uint16_t gc_lmt_overload_low_thresh; /* adi,gc-lmt-overload-low-thresh */
+ uint8_t gc_low_power_thresh; /* adi,gc-low-power-thresh */
+ uint8_t gc_max_dig_gain; /* adi,gc-max-dig-gain */
+ /* Gain MGC Control */
+ uint8_t mgc_dec_gain_step; /* adi,mgc-dec-gain-step */
+ uint8_t mgc_inc_gain_step; /* adi,mgc-inc-gain-step */
+ uint8_t mgc_rx1_ctrl_inp_enable; /* adi,mgc-rx1-ctrl-inp-enable */
+ uint8_t mgc_rx2_ctrl_inp_enable; /* adi,mgc-rx2-ctrl-inp-enable */
+ uint8_t mgc_split_table_ctrl_inp_gain_mode; /* adi,mgc-split-table-ctrl-inp-gain-mode */
+ /* Gain AGC Control */
+ uint8_t agc_adc_large_overload_exceed_counter; /* adi,agc-adc-large-overload-exceed-counter */
+ uint8_t agc_adc_large_overload_inc_steps; /* adi,agc-adc-large-overload-inc-steps */
+ uint8_t agc_adc_lmt_small_overload_prevent_gain_inc_enable; /* adi,agc-adc-lmt-small-overload-prevent-gain-inc-enable */
+ uint8_t agc_adc_small_overload_exceed_counter; /* adi,agc-adc-small-overload-exceed-counter */
+ uint8_t agc_dig_gain_step_size; /* adi,agc-dig-gain-step-size */
+ uint8_t agc_dig_saturation_exceed_counter; /* adi,agc-dig-saturation-exceed-counter */
+ uint32_t agc_gain_update_interval_us; /* adi,agc-gain-update-interval-us */
+ uint8_t agc_immed_gain_change_if_large_adc_overload_enable; /* adi,agc-immed-gain-change-if-large-adc-overload-enable */
+ uint8_t agc_immed_gain_change_if_large_lmt_overload_enable; /* adi,agc-immed-gain-change-if-large-lmt-overload-enable */
+ uint8_t agc_inner_thresh_high; /* adi,agc-inner-thresh-high */
+ uint8_t agc_inner_thresh_high_dec_steps; /* adi,agc-inner-thresh-high-dec-steps */
+ uint8_t agc_inner_thresh_low; /* adi,agc-inner-thresh-low */
+ uint8_t agc_inner_thresh_low_inc_steps; /* adi,agc-inner-thresh-low-inc-steps */
+ uint8_t agc_lmt_overload_large_exceed_counter; /* adi,agc-lmt-overload-large-exceed-counter */
+ uint8_t agc_lmt_overload_large_inc_steps; /* adi,agc-lmt-overload-large-inc-steps */
+ uint8_t agc_lmt_overload_small_exceed_counter; /* adi,agc-lmt-overload-small-exceed-counter */
+ uint8_t agc_outer_thresh_high; /* adi,agc-outer-thresh-high */
+ uint8_t agc_outer_thresh_high_dec_steps; /* adi,agc-outer-thresh-high-dec-steps */
+ uint8_t agc_outer_thresh_low; /* adi,agc-outer-thresh-low */
+ uint8_t agc_outer_thresh_low_inc_steps; /* adi,agc-outer-thresh-low-inc-steps */
+ uint32_t agc_attack_delay_extra_margin_us; /* adi,agc-attack-delay-extra-margin-us */
+ uint8_t agc_sync_for_gain_counter_enable; /* adi,agc-sync-for-gain-counter-enable */
+ /* Fast AGC */
+ uint32_t fagc_dec_pow_measuremnt_duration; /* adi,fagc-dec-pow-measurement-duration */
+ uint32_t fagc_state_wait_time_ns; /* adi,fagc-state-wait-time-ns */
+ /* Fast AGC - Low Power */
+ uint8_t fagc_allow_agc_gain_increase; /* adi,fagc-allow-agc-gain-increase-enable */
+ uint32_t fagc_lp_thresh_increment_time; /* adi,fagc-lp-thresh-increment-time */
+ uint32_t fagc_lp_thresh_increment_steps; /* adi,fagc-lp-thresh-increment-steps */
+ /* Fast AGC - Lock Level */
+ uint32_t fagc_lock_level; /* adi,fagc-lock-level */
+ uint8_t fagc_lock_level_lmt_gain_increase_en; /* adi,fagc-lock-level-lmt-gain-increase-enable */
+ uint32_t fagc_lock_level_gain_increase_upper_limit; /* adi,fagc-lock-level-gain-increase-upper-limit */
+ /* Fast AGC - Peak Detectors and Final Settling */
+ uint32_t fagc_lpf_final_settling_steps; /* adi,fagc-lpf-final-settling-steps */
+ uint32_t fagc_lmt_final_settling_steps; /* adi,fagc-lmt-final-settling-steps */
+ uint32_t fagc_final_overrange_count; /* adi,fagc-final-overrange-count */
+ /* Fast AGC - Final Power Test */
+ uint8_t fagc_gain_increase_after_gain_lock_en; /* adi,fagc-gain-increase-after-gain-lock-enable */
+ /* Fast AGC - Unlocking the Gain */
+ uint32_t fagc_gain_index_type_after_exit_rx_mode; /* adi,fagc-gain-index-type-after-exit-rx-mode */
+ uint8_t fagc_use_last_lock_level_for_set_gain_en; /* adi,fagc-use-last-lock-level-for-set-gain-enable */
+ uint8_t fagc_rst_gla_stronger_sig_thresh_exceeded_en; /* adi,fagc-rst-gla-stronger-sig-thresh-exceeded-enable */
+ uint32_t fagc_optimized_gain_offset; /* adi,fagc-optimized-gain-offset */
+ uint32_t fagc_rst_gla_stronger_sig_thresh_above_ll; /* adi,fagc-rst-gla-stronger-sig-thresh-above-ll */
+ uint8_t fagc_rst_gla_engergy_lost_sig_thresh_exceeded_en; /* adi,fagc-rst-gla-engergy-lost-sig-thresh-exceeded-enable */
+ uint8_t fagc_rst_gla_engergy_lost_goto_optim_gain_en; /* adi,fagc-rst-gla-engergy-lost-goto-optim-gain-enable */
+ uint32_t fagc_rst_gla_engergy_lost_sig_thresh_below_ll; /* adi,fagc-rst-gla-engergy-lost-sig-thresh-below-ll */
+ uint32_t fagc_energy_lost_stronger_sig_gain_lock_exit_cnt; /* adi,fagc-energy-lost-stronger-sig-gain-lock-exit-cnt */
+ uint8_t fagc_rst_gla_large_adc_overload_en; /* adi,fagc-rst-gla-large-adc-overload-enable */
+ uint8_t fagc_rst_gla_large_lmt_overload_en; /* adi,fagc-rst-gla-large-lmt-overload-enable */
+ uint8_t fagc_rst_gla_en_agc_pulled_high_en; /* adi,fagc-rst-gla-en-agc-pulled-high-enable */
+ uint32_t fagc_rst_gla_if_en_agc_pulled_high_mode; /* adi,fagc-rst-gla-if-en-agc-pulled-high-mode */
+ uint32_t fagc_power_measurement_duration_in_state5; /* adi,fagc-power-measurement-duration-in-state5 */
+ /* RSSI Control */
+ uint32_t rssi_delay; /* adi,rssi-delay */
+ uint32_t rssi_duration; /* adi,rssi-duration */
+ uint8_t rssi_restart_mode; /* adi,rssi-restart-mode */
+ uint8_t rssi_unit_is_rx_samples_enable; /* adi,rssi-unit-is-rx-samples-enable */
+ uint32_t rssi_wait; /* adi,rssi-wait */
+ /* Aux ADC Control */
+ uint32_t aux_adc_decimation; /* adi,aux-adc-decimation */
+ uint32_t aux_adc_rate; /* adi,aux-adc-rate */
+ /* AuxDAC Control */
+ uint8_t aux_dac_manual_mode_enable; /* adi,aux-dac-manual-mode-enable */
+ uint32_t aux_dac1_default_value_mV; /* adi,aux-dac1-default-value-mV */
+ uint8_t aux_dac1_active_in_rx_enable; /* adi,aux-dac1-active-in-rx-enable */
+ uint8_t aux_dac1_active_in_tx_enable; /* adi,aux-dac1-active-in-tx-enable */
+ uint8_t aux_dac1_active_in_alert_enable; /* adi,aux-dac1-active-in-alert-enable */
+ uint32_t aux_dac1_rx_delay_us; /* adi,aux-dac1-rx-delay-us */
+ uint32_t aux_dac1_tx_delay_us; /* adi,aux-dac1-tx-delay-us */
+ uint32_t aux_dac2_default_value_mV; /* adi,aux-dac2-default-value-mV */
+ uint8_t aux_dac2_active_in_rx_enable; /* adi,aux-dac2-active-in-rx-enable */
+ uint8_t aux_dac2_active_in_tx_enable; /* adi,aux-dac2-active-in-tx-enable */
+ uint8_t aux_dac2_active_in_alert_enable; /* adi,aux-dac2-active-in-alert-enable */
+ uint32_t aux_dac2_rx_delay_us; /* adi,aux-dac2-rx-delay-us */
+ uint32_t aux_dac2_tx_delay_us; /* adi,aux-dac2-tx-delay-us */
+ /* Temperature Sensor Control */
+ uint32_t temp_sense_decimation; /* adi,temp-sense-decimation */
+ uint16_t temp_sense_measurement_interval_ms; /* adi,temp-sense-measurement-interval-ms */
+ int8_t temp_sense_offset_signed; /* adi,temp-sense-offset-signed */
+ uint8_t temp_sense_periodic_measurement_enable; /* adi,temp-sense-periodic-measurement-enable */
+ /* Control Out Setup */
+ uint8_t ctrl_outs_enable_mask; /* adi,ctrl-outs-enable-mask */
+ uint8_t ctrl_outs_index; /* adi,ctrl-outs-index */
+ /* External LNA Control */
+ uint32_t elna_settling_delay_ns; /* adi,elna-settling-delay-ns */
+ uint32_t elna_gain_mdB; /* adi,elna-gain-mdB */
+ uint32_t elna_bypass_loss_mdB; /* adi,elna-bypass-loss-mdB */
+ uint8_t elna_rx1_gpo0_control_enable; /* adi,elna-rx1-gpo0-control-enable */
+ uint8_t elna_rx2_gpo1_control_enable; /* adi,elna-rx2-gpo1-control-enable */
+ uint8_t elna_gaintable_all_index_enable; /* adi,elna-gaintable-all-index-enable */
+ /* Digital Interface Control */
+ uint8_t digital_interface_tune_skip_mode; /* adi,digital-interface-tune-skip-mode */
+ uint8_t digital_interface_tune_fir_disable; /* adi,digital-interface-tune-fir-disable */
+ uint8_t pp_tx_swap_enable; /* adi,pp-tx-swap-enable */
+ uint8_t pp_rx_swap_enable; /* adi,pp-rx-swap-enable */
+ uint8_t tx_channel_swap_enable; /* adi,tx-channel-swap-enable */
+ uint8_t rx_channel_swap_enable; /* adi,rx-channel-swap-enable */
+ uint8_t rx_frame_pulse_mode_enable; /* adi,rx-frame-pulse-mode-enable */
+ uint8_t two_t_two_r_timing_enable; /* adi,2t2r-timing-enable */
+ uint8_t invert_data_bus_enable; /* adi,invert-data-bus-enable */
+ uint8_t invert_data_clk_enable; /* adi,invert-data-clk-enable */
+ uint8_t fdd_alt_word_order_enable; /* adi,fdd-alt-word-order-enable */
+ uint8_t invert_rx_frame_enable; /* adi,invert-rx-frame-enable */
+ uint8_t fdd_rx_rate_2tx_enable; /* adi,fdd-rx-rate-2tx-enable */
+ uint8_t swap_ports_enable; /* adi,swap-ports-enable */
+ uint8_t single_data_rate_enable; /* adi,single-data-rate-enable */
+ uint8_t lvds_mode_enable; /* adi,lvds-mode-enable */
+ uint8_t half_duplex_mode_enable; /* adi,half-duplex-mode-enable */
+ uint8_t single_port_mode_enable; /* adi,single-port-mode-enable */
+ uint8_t full_port_enable; /* adi,full-port-enable */
+ uint8_t full_duplex_swap_bits_enable; /* adi,full-duplex-swap-bits-enable */
+ uint32_t delay_rx_data; /* adi,delay-rx-data */
+ uint32_t rx_data_clock_delay; /* adi,rx-data-clock-delay */
+ uint32_t rx_data_delay; /* adi,rx-data-delay */
+ uint32_t tx_fb_clock_delay; /* adi,tx-fb-clock-delay */
+ uint32_t tx_data_delay; /* adi,tx-data-delay */
+ uint32_t lvds_bias_mV; /* adi,lvds-bias-mV */
+ uint8_t lvds_rx_onchip_termination_enable; /* adi,lvds-rx-onchip-termination-enable */
+ uint8_t rx1rx2_phase_inversion_en; /* adi,rx1-rx2-phase-inversion-enable */
+ uint8_t lvds_invert1_control; /* adi,lvds-invert1-control */
+ uint8_t lvds_invert2_control; /* adi,lvds-invert2-control */
+#ifdef NUAND_MODIFICATIONS
+ // add digital interface drive and clock slew
+ uint8_t clk_out_drive;
+ uint8_t dataclk_drive;
+ uint8_t data_port_drive;
+ uint8_t clk_out_slew;
+ uint8_t dataclk_slew;
+ uint8_t data_port_slew;
+#endif // NUAND_MODIFICATIONS
+ /* GPO Control */
+ uint8_t gpo0_inactive_state_high_enable; /* adi,gpo0-inactive-state-high-enable */
+ uint8_t gpo1_inactive_state_high_enable; /* adi,gpo1-inactive-state-high-enable */
+ uint8_t gpo2_inactive_state_high_enable; /* adi,gpo2-inactive-state-high-enable */
+ uint8_t gpo3_inactive_state_high_enable; /* adi,gpo3-inactive-state-high-enable */
+ uint8_t gpo0_slave_rx_enable; /* adi,gpo0-slave-rx-enable */
+ uint8_t gpo0_slave_tx_enable; /* adi,gpo0-slave-tx-enable */
+ uint8_t gpo1_slave_rx_enable; /* adi,gpo1-slave-rx-enable */
+ uint8_t gpo1_slave_tx_enable; /* adi,gpo1-slave-tx-enable */
+ uint8_t gpo2_slave_rx_enable; /* adi,gpo2-slave-rx-enable */
+ uint8_t gpo2_slave_tx_enable; /* adi,gpo2-slave-tx-enable */
+ uint8_t gpo3_slave_rx_enable; /* adi,gpo3-slave-rx-enable */
+ uint8_t gpo3_slave_tx_enable; /* adi,gpo3-slave-tx-enable */
+ uint8_t gpo0_rx_delay_us; /* adi,gpo0-rx-delay-us */
+ uint8_t gpo0_tx_delay_us; /* adi,gpo0-tx-delay-us */
+ uint8_t gpo1_rx_delay_us; /* adi,gpo1-rx-delay-us */
+ uint8_t gpo1_tx_delay_us; /* adi,gpo1-tx-delay-us */
+ uint8_t gpo2_rx_delay_us; /* adi,gpo2-rx-delay-us */
+ uint8_t gpo2_tx_delay_us; /* adi,gpo2-tx-delay-us */
+ uint8_t gpo3_rx_delay_us; /* adi,gpo3-rx-delay-us */
+ uint8_t gpo3_tx_delay_us; /* adi,gpo3-tx-delay-us */
+ /* Tx Monitor Control */
+ uint32_t low_high_gain_threshold_mdB; /* adi,txmon-low-high-thresh */
+ uint32_t low_gain_dB; /* adi,txmon-low-gain */
+ uint32_t high_gain_dB; /* adi,txmon-high-gain */
+ uint8_t tx_mon_track_en; /* adi,txmon-dc-tracking-enable */
+ uint8_t one_shot_mode_en; /* adi,txmon-one-shot-mode-enable */
+ uint32_t tx_mon_delay; /* adi,txmon-delay */
+ uint32_t tx_mon_duration; /* adi,txmon-duration */
+ uint32_t tx1_mon_front_end_gain; /* adi,txmon-1-front-end-gain */
+ uint32_t tx2_mon_front_end_gain; /* adi,txmon-2-front-end-gain */
+ uint32_t tx1_mon_lo_cm; /* adi,txmon-1-lo-cm */
+ uint32_t tx2_mon_lo_cm; /* adi,txmon-2-lo-cm */
+ /* GPIO definitions */
+ int32_t gpio_resetb; /* reset-gpios */
+ /* MCS Sync */
+ int32_t gpio_sync; /* sync-gpios */
+ int32_t gpio_cal_sw1; /* cal-sw1-gpios */
+ int32_t gpio_cal_sw2; /* cal-sw2-gpios */
+ /* External LO clocks */
+ uint32_t (*ad9361_rfpll_ext_recalc_rate)(struct refclk_scale *clk_priv);
+ int32_t (*ad9361_rfpll_ext_round_rate)(struct refclk_scale *clk_priv, uint32_t rate);
+ int32_t (*ad9361_rfpll_ext_set_rate)(struct refclk_scale *clk_priv, uint32_t rate);
+}AD9361_InitParam;
+
+typedef struct
+{
+ uint32_t rx; /* 1, 2, 3(both) */
+ int32_t rx_gain; /* -12, -6, 0, 6 */
+ uint32_t rx_dec; /* 1, 2, 4 */
+ int16_t rx_coef[128];
+ uint8_t rx_coef_size;
+ uint32_t rx_path_clks[6];
+ uint32_t rx_bandwidth;
+}AD9361_RXFIRConfig;
+
+typedef struct
+{
+ uint32_t tx; /* 1, 2, 3(both) */
+ int32_t tx_gain; /* -6, 0 */
+ uint32_t tx_int; /* 1, 2, 4 */
+ int16_t tx_coef[128];
+ uint8_t tx_coef_size;
+ uint32_t tx_path_clks[6];
+ uint32_t tx_bandwidth;
+}AD9361_TXFIRConfig;
+
+enum ad9361_ensm_mode {
+ ENSM_MODE_TX,
+ ENSM_MODE_RX,
+ ENSM_MODE_ALERT,
+ ENSM_MODE_FDD,
+ ENSM_MODE_WAIT,
+ ENSM_MODE_SLEEP,
+ ENSM_MODE_PINCTRL,
+ ENSM_MODE_PINCTRL_FDD_INDEP,
+};
+
+#define ENABLE 1
+#define DISABLE 0
+
+#define RX1 0
+#define RX2 1
+
+#define TX1 0
+#define TX2 1
+
+#define A_BALANCED 0
+#define B_BALANCED 1
+#define C_BALANCED 2
+#define A_N 3
+#define A_P 4
+#define B_N 5
+#define B_P 6
+#define C_N 7
+#define C_P 8
+#define TX_MON1 9
+#define TX_MON2 10
+#define TX_MON1_2 11
+
+#define TXA 0
+#define TXB 1
+
+#define MODE_1x1 1
+#define MODE_2x2 2
+
+#define HIGHEST_OSR 0
+#define NOMINAL_OSR 1
+
+#define INT_LO 0
+#define EXT_LO 1
+
+/******************************************************************************/
+/************************ Functions Declarations ******************************/
+/******************************************************************************/
+#ifdef NUAND_MODIFICATIONS
+/* Initialize the AD9361 part. */
+int32_t ad9361_init (struct ad9361_rf_phy **ad9361_phy, AD9361_InitParam *init_param, void *userdata);
+/* Deinitialize the AD9361 part. */
+int32_t ad9361_deinit (struct ad9361_rf_phy *phy);
+#else
+/* Initialize the AD9361 part. */
+int32_t ad9361_init (struct ad9361_rf_phy **ad9361_phy, AD9361_InitParam *init_param);
+#endif // NUAND_MODIFICATIONS
+/* Set the Enable State Machine (ENSM) mode. */
+int32_t ad9361_set_en_state_machine_mode (struct ad9361_rf_phy *phy, uint32_t mode);
+/* Get the Enable State Machine (ENSM) mode. */
+int32_t ad9361_get_en_state_machine_mode (struct ad9361_rf_phy *phy, uint32_t *mode);
+/* Set the receive RF gain for the selected channel. */
+int32_t ad9361_set_rx_rf_gain (struct ad9361_rf_phy *phy, uint8_t ch, int32_t gain_db);
+/* Get current receive RF gain for the selected channel. */
+int32_t ad9361_get_rx_rf_gain (struct ad9361_rf_phy *phy, uint8_t ch, int32_t *gain_db);
+/* Set the RX RF bandwidth. */
+int32_t ad9361_set_rx_rf_bandwidth (struct ad9361_rf_phy *phy, uint32_t bandwidth_hz);
+/* Get the RX RF bandwidth. */
+int32_t ad9361_get_rx_rf_bandwidth (struct ad9361_rf_phy *phy, uint32_t *bandwidth_hz);
+/* Set the RX sampling frequency. */
+int32_t ad9361_set_rx_sampling_freq (struct ad9361_rf_phy *phy, uint32_t sampling_freq_hz);
+/* Get current RX sampling frequency. */
+int32_t ad9361_get_rx_sampling_freq (struct ad9361_rf_phy *phy, uint32_t *sampling_freq_hz);
+/* Set the RX LO frequency. */
+int32_t ad9361_set_rx_lo_freq (struct ad9361_rf_phy *phy, uint64_t lo_freq_hz);
+/* Get current RX LO frequency. */
+int32_t ad9361_get_rx_lo_freq (struct ad9361_rf_phy *phy, uint64_t *lo_freq_hz);
+/* Switch between internal and external LO. */
+int32_t ad9361_set_rx_lo_int_ext(struct ad9361_rf_phy *phy, uint8_t int_ext);
+/* Get the RSSI for the selected channel. */
+int32_t ad9361_get_rx_rssi (struct ad9361_rf_phy *phy, uint8_t ch, struct rf_rssi *rssi);
+/* Set the gain control mode for the selected channel. */
+int32_t ad9361_set_rx_gain_control_mode (struct ad9361_rf_phy *phy, uint8_t ch, uint8_t gc_mode);
+/* Get the gain control mode for the selected channel. */
+int32_t ad9361_get_rx_gain_control_mode (struct ad9361_rf_phy *phy, uint8_t ch, uint8_t *gc_mode);
+/* Set the RX FIR filter configuration. */
+int32_t ad9361_set_rx_fir_config (struct ad9361_rf_phy *phy, AD9361_RXFIRConfig fir_cfg);
+/* Get the RX FIR filter configuration. */
+int32_t ad9361_get_rx_fir_config(struct ad9361_rf_phy *phy, uint8_t rx_ch, AD9361_RXFIRConfig *fir_cfg);
+/* Enable/disable the RX FIR filter. */
+int32_t ad9361_set_rx_fir_en_dis (struct ad9361_rf_phy *phy, uint8_t en_dis);
+/* Get the status of the RX FIR filter. */
+int32_t ad9361_get_rx_fir_en_dis (struct ad9361_rf_phy *phy, uint8_t *en_dis);
+/* Enable/disable the RX RFDC Tracking. */
+int32_t ad9361_set_rx_rfdc_track_en_dis (struct ad9361_rf_phy *phy, uint8_t en_dis);
+/* Get the status of the RX RFDC Tracking. */
+int32_t ad9361_get_rx_rfdc_track_en_dis (struct ad9361_rf_phy *phy, uint8_t *en_dis);
+/* Enable/disable the RX BasebandDC Tracking. */
+int32_t ad9361_set_rx_bbdc_track_en_dis (struct ad9361_rf_phy *phy, uint8_t en_dis);
+/* Get the status of the RX BasebandDC Tracking. */
+int32_t ad9361_get_rx_bbdc_track_en_dis (struct ad9361_rf_phy *phy, uint8_t *en_dis);
+/* Enable/disable the RX Quadrature Tracking. */
+int32_t ad9361_set_rx_quad_track_en_dis (struct ad9361_rf_phy *phy, uint8_t en_dis);
+/* Get the status of the RX Quadrature Tracking. */
+int32_t ad9361_get_rx_quad_track_en_dis (struct ad9361_rf_phy *phy, uint8_t *en_dis);
+/* Set the RX RF input port. */
+int32_t ad9361_set_rx_rf_port_input (struct ad9361_rf_phy *phy, uint32_t mode);
+/* Get the selected RX RF input port. */
+int32_t ad9361_get_rx_rf_port_input (struct ad9361_rf_phy *phy, uint32_t *mode);
+/* Store RX fastlock profile. */
+int32_t ad9361_rx_fastlock_store(struct ad9361_rf_phy *phy, uint32_t profile);
+/* Recall RX fastlock profile. */
+int32_t ad9361_rx_fastlock_recall(struct ad9361_rf_phy *phy, uint32_t profile);
+/* Load RX fastlock profile. */
+int32_t ad9361_rx_fastlock_load(struct ad9361_rf_phy *phy, uint32_t profile, uint8_t *values);
+/* Save RX fastlock profile. */
+int32_t ad9361_rx_fastlock_save(struct ad9361_rf_phy *phy, uint32_t profile, uint8_t *values);
+/* Set the transmit attenuation for the selected channel. */
+int32_t ad9361_set_tx_attenuation (struct ad9361_rf_phy *phy, uint8_t ch, uint32_t attenuation_mdb);
+/* Get current transmit attenuation for the selected channel. */
+int32_t ad9361_get_tx_attenuation (struct ad9361_rf_phy *phy, uint8_t ch, uint32_t *attenuation_mdb);
+/* Set the TX RF bandwidth. */
+int32_t ad9361_set_tx_rf_bandwidth (struct ad9361_rf_phy *phy, uint32_t bandwidth_hz);
+/* Get the TX RF bandwidth. */
+int32_t ad9361_get_tx_rf_bandwidth (struct ad9361_rf_phy *phy, uint32_t *bandwidth_hz);
+/* Set the TX sampling frequency. */
+int32_t ad9361_set_tx_sampling_freq (struct ad9361_rf_phy *phy, uint32_t sampling_freq_hz);
+/* Get current TX sampling frequency. */
+int32_t ad9361_get_tx_sampling_freq (struct ad9361_rf_phy *phy, uint32_t *sampling_freq_hz);
+/* Set the TX LO frequency. */
+int32_t ad9361_set_tx_lo_freq (struct ad9361_rf_phy *phy, uint64_t lo_freq_hz);
+/* Get current TX LO frequency. */
+int32_t ad9361_get_tx_lo_freq (struct ad9361_rf_phy *phy, uint64_t *lo_freq_hz);
+/* Switch between internal and external LO. */
+int32_t ad9361_set_tx_lo_int_ext(struct ad9361_rf_phy *phy, uint8_t int_ext);
+/* Set the TX FIR filter configuration. */
+int32_t ad9361_set_tx_fir_config (struct ad9361_rf_phy *phy, AD9361_TXFIRConfig fir_cfg);
+/* Get the TX FIR filter configuration. */
+int32_t ad9361_get_tx_fir_config(struct ad9361_rf_phy *phy, uint8_t tx_ch, AD9361_TXFIRConfig *fir_cfg);
+/* Enable/disable the TX FIR filter. */
+int32_t ad9361_set_tx_fir_en_dis (struct ad9361_rf_phy *phy, uint8_t en_dis);
+/* Get the status of the TX FIR filter. */
+int32_t ad9361_get_tx_fir_en_dis (struct ad9361_rf_phy *phy, uint8_t *en_dis);
+/* Get the TX RSSI for the selected channel. */
+int32_t ad9361_get_tx_rssi (struct ad9361_rf_phy *phy, uint8_t ch, uint32_t *rssi_db_x_1000);
+/* Set the TX RF output port. */
+int32_t ad9361_set_tx_rf_port_output (struct ad9361_rf_phy *phy, uint32_t mode);
+/* Get the selected TX RF output port. */
+int32_t ad9361_get_tx_rf_port_output (struct ad9361_rf_phy *phy, uint32_t *mode);
+/* Enable/disable the auto calibration. */
+int32_t ad9361_set_tx_auto_cal_en_dis (struct ad9361_rf_phy *phy, uint8_t en_dis);
+/* Get the status of the auto calibration flag. */
+int32_t ad9361_get_tx_auto_cal_en_dis (struct ad9361_rf_phy *phy, uint8_t *en_dis);
+/* Store TX fastlock profile. */
+int32_t ad9361_tx_fastlock_store(struct ad9361_rf_phy *phy, uint32_t profile);
+/* Recall TX fastlock profile. */
+int32_t ad9361_tx_fastlock_recall(struct ad9361_rf_phy *phy, uint32_t profile);
+/* Load TX fastlock profile. */
+int32_t ad9361_tx_fastlock_load(struct ad9361_rf_phy *phy, uint32_t profile, uint8_t *values);
+/* Save TX fastlock profile. */
+int32_t ad9361_tx_fastlock_save(struct ad9361_rf_phy *phy, uint32_t profile, uint8_t *values);
+/* Set the RX and TX path rates. */
+int32_t ad9361_set_trx_path_clks(struct ad9361_rf_phy *phy, uint32_t *rx_path_clks, uint32_t *tx_path_clks);
+/* Get the RX and TX path rates. */
+int32_t ad9361_get_trx_path_clks(struct ad9361_rf_phy *phy, uint32_t *rx_path_clks, uint32_t *tx_path_clks);
+/* Set the number of channels mode. */
+int32_t ad9361_set_no_ch_mode(struct ad9361_rf_phy *phy, uint8_t no_ch_mode);
+/* Do multi chip synchronization. */
+int32_t ad9361_do_mcs(struct ad9361_rf_phy *phy_master, struct ad9361_rf_phy *phy_slave);
+/* Enable/disable the TRX FIR filters. */
+int32_t ad9361_set_trx_fir_en_dis (struct ad9361_rf_phy *phy, uint8_t en_dis);
+/* Set the OSR rate governor. */
+int32_t ad9361_set_trx_rate_gov (struct ad9361_rf_phy *phy, uint32_t rate_gov);
+/* Get the OSR rate governor. */
+int32_t ad9361_get_trx_rate_gov (struct ad9361_rf_phy *phy, uint32_t *rate_gov);
+/* Perform the selected calibration. */
+int32_t ad9361_do_calib(struct ad9361_rf_phy *phy, uint32_t cal, int32_t arg);
+/* Load and enable TRX FIR filters configurations. */
+int32_t ad9361_trx_load_enable_fir(struct ad9361_rf_phy *phy,
+ AD9361_RXFIRConfig rx_fir_cfg,
+ AD9361_TXFIRConfig tx_fir_cfg);
+/* Do DCXO coarse tuning. */
+int32_t ad9361_do_dcxo_tune_coarse(struct ad9361_rf_phy *phy,
+ uint32_t coarse);
+/* Do DCXO fine tuning. */
+int32_t ad9361_do_dcxo_tune_fine(struct ad9361_rf_phy *phy,
+ uint32_t fine);
+#endif
diff --git a/Radio/HW/BladeRF/common/thirdparty/ad936x/ad9361_conv.c b/Radio/HW/BladeRF/common/thirdparty/ad936x/ad9361_conv.c
new file mode 100644
index 0000000..0491f91
--- /dev/null
+++ b/Radio/HW/BladeRF/common/thirdparty/ad936x/ad9361_conv.c
@@ -0,0 +1,751 @@
+
+/***************************************************************************//**
+ * @file ad9361_conv.c
+ * @brief Implementation of AD9361 Conv Driver.
+********************************************************************************
+ * Copyright 2014-2015(c) Analog Devices, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of Analog Devices, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * - The use of this software may or may not infringe the patent rights
+ * of one or more patent holders. This license does not release you
+ * from the requirement that you obtain separate licenses from these
+ * patent holders to use this software.
+ * - Use of the software either in source or binary form, must be run
+ * on or directly connected to an Analog Devices Inc. component.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+/******************************************************************************/
+/***************************** Include Files **********************************/
+/******************************************************************************/
+#include <inttypes.h>
+#include <string.h>
+#include "ad9361.h"
+#include "platform.h"
+#include "config.h"
+
+#ifndef AXI_ADC_NOT_PRESENT
+/**
+ * HDL loopback enable/disable.
+ * @param phy The AD9361 state structure.
+ * @param enable Enable/disable option.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_hdl_loopback(struct ad9361_rf_phy *phy, bool enable)
+{
+ struct axiadc_converter *conv = phy->adc_conv;
+ struct axiadc_state *st = phy->adc_state;
+ int32_t reg, addr, chan;
+
+#ifdef NUAND_MODIFICATIONS
+ int ret;
+ uint32_t readval;
+
+ ret = axiadc_read(st, 0x4000, &readval);
+ if (ret < 0)
+ return ret;
+
+ uint32_t version = readval;
+#else
+ uint32_t version = axiadc_read(st, 0x4000);
+#endif // NUAND_MODIFICATIONS
+
+ /* Still there but implemented a bit different */
+ if (PCORE_VERSION_MAJOR(version) > 7)
+ addr = 0x4418;
+ else
+ addr = 0x4414;
+
+ for (chan = 0; chan < conv->chip_info->num_channels; chan++) {
+#ifdef NUAND_MODIFICATIONS
+ ret = axiadc_read(st, addr + (chan) * 0x40, &readval);
+ if (ret < 0)
+ return ret;
+
+ reg = (int32_t)readval;
+#else
+ reg = axiadc_read(st, addr + (chan) * 0x40);
+#endif // NUAND_MODIFICATIONS
+
+ if (PCORE_VERSION_MAJOR(version) > 7) {
+ if (enable && reg != 0x8) {
+ conv->scratch_reg[chan] = reg;
+ reg = 0x8;
+ } else if (reg == 0x8) {
+ reg = conv->scratch_reg[chan];
+ }
+ } else {
+ /* DAC_LB_ENB If set enables loopback of receive data */
+ if (enable)
+ reg |= BIT(1);
+ else
+ reg &= ~BIT(1);
+ }
+ axiadc_write(st, addr + (chan) * 0x40, reg);
+ }
+
+ return 0;
+}
+
+/**
+ * Set IO delay.
+ * @param st The AXI ADC state structure.
+ * @param lane Lane number.
+ * @param val Value.
+ * @param tx The Synthesizer TX = 1, RX = 0.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_iodelay_set(struct axiadc_state *st, unsigned lane,
+ unsigned val, bool tx)
+{
+ if (tx) {
+ if (PCORE_VERSION_MAJOR(st->pcore_version) > 8)
+ axiadc_write(st, 0x4000 + ADI_REG_DELAY(lane), val);
+ else
+ return -ENODEV;
+ } else {
+ axiadc_idelay_set(st, lane, val);
+ }
+
+ return 0;
+}
+
+/**
+ * Set midscale IO delay.
+ * @param phy The AD9361 state structure.
+ * @param tx The Synthesizer TX = 1, RX = 0.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_midscale_iodelay(struct ad9361_rf_phy *phy, bool tx)
+{
+ struct axiadc_state *st = phy->adc_state;
+ int32_t ret = 0, i;
+
+ for (i = 0; i < 7; i++)
+ ret |= ad9361_iodelay_set(st, i, 15, tx);
+
+ return 0;
+}
+
+/**
+ * Digital tune IO delay.
+ * @param phy The AD9361 state structure.
+ * @param tx The Synthesizer TX = 1, RX = 0.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static int32_t ad9361_dig_tune_iodelay(struct ad9361_rf_phy *phy, bool tx)
+{
+ struct axiadc_converter *conv = phy->adc_conv;
+ struct axiadc_state *st = phy->adc_state;
+ int32_t ret, i, j, chan, num_chan;
+ uint32_t s0, c0;
+ uint8_t field[32];
+
+ num_chan = (conv->chip_info->num_channels > 4) ? 4 : conv->chip_info->num_channels;
+
+ for (i = 0; i < 7; i++) {
+ for (j = 0; j < 32; j++) {
+ ad9361_iodelay_set(st, i, j, tx);
+ mdelay(1);
+
+ for (chan = 0; chan < num_chan; chan++)
+ axiadc_write(st, ADI_REG_CHAN_STATUS(chan),
+ ADI_PN_ERR | ADI_PN_OOS);
+ mdelay(10);
+
+#ifdef NUAND_MODIFICATIONS
+ uint32_t stat, tmp;
+
+ for (chan = 0, stat = 0; chan < num_chan; chan++) {
+ ret = axiadc_read(st, ADI_REG_CHAN_STATUS(chan), &tmp);
+ if (ret < 0)
+ return ret;
+ stat |= tmp;
+ }
+ field[j] = stat;
+#else
+
+ for (chan = 0, ret = 0; chan < num_chan; chan++)
+ ret |= axiadc_read(st, ADI_REG_CHAN_STATUS(chan));
+
+ field[j] = ret;
+#endif // NUAND_MODIFICATIONS
+ }
+
+ c0 = ad9361_find_opt(&field[0], 32, &s0);
+ ad9361_iodelay_set(st, i, s0 + c0 / 2, tx);
+
+ dev_dbg(&phy->spi->dev,
+ "%s Lane %"PRId32", window cnt %"PRIu32" , start %"PRIu32", IODELAY set to %"PRIu32"\n",
+ tx ? "TX" :"RX", i , c0, s0, s0 + c0 / 2);
+ }
+
+ return 0;
+}
+
+/**
+ * Digital tune verbose print.
+ * @param phy The AD9361 state structure.
+ * @param field Field.
+ * @param tx The Synthesizer TX = 1, RX = 0.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+static void ad9361_dig_tune_verbose_print(struct ad9361_rf_phy *phy,
+ uint8_t field[][16], bool tx)
+{
+ int32_t i, j;
+
+ printk("SAMPL CLK: %"PRIu32" tuning: %s\n",
+ clk_get_rate(phy, phy->ref_clk_scale[RX_SAMPL_CLK]), tx ? "TX" : "RX");
+ printk(" ");
+ for (i = 0; i < 16; i++)
+ printk("%"PRIx32":", i);
+ printk("\n");
+
+ for (i = 0; i < 2; i++) {
+ printk("%"PRIx32":", i);
+ for (j = 0; j < 16; j++) {
+ printk("%c ", (field[i][j] ? '#' : 'o'));
+ }
+ printk("\n");
+ }
+ printk("\n");
+}
+
+/**
+ * Digital interface timing analysis.
+ * @param phy The AD9361 state structure.
+ * @param buf The buffer.
+ * @param buflen The buffer length.
+ * @return The size in case of success, negative error code otherwise.
+ */
+int32_t ad9361_dig_interface_timing_analysis(struct ad9361_rf_phy *phy,
+ char *buf, int32_t buflen)
+{
+ struct axiadc_state *st = phy->adc_state;
+ int32_t ret, i, j, chan, len = 0;
+ uint8_t field[16][16];
+ uint8_t rx;
+
+ dev_dbg(&phy->spi->dev, "%s:\n", __func__);
+
+ rx = ad9361_spi_read(phy->spi, REG_RX_CLOCK_DATA_DELAY);
+
+ ad9361_bist_prbs(phy, BIST_INJ_RX);
+
+ for (i = 0; i < 16; i++) {
+ for (j = 0; j < 16; j++) {
+ ad9361_spi_write(phy->spi, REG_RX_CLOCK_DATA_DELAY,
+ DATA_CLK_DELAY(j) | RX_DATA_DELAY(i));
+ for (chan = 0; chan < 4; chan++)
+ axiadc_write(st, ADI_REG_CHAN_STATUS(chan),
+ ADI_PN_ERR | ADI_PN_OOS);
+
+ mdelay(1);
+
+#ifdef NUAND_MODIFICATIONS
+ uint32_t tmp, stat;
+ ret = axiadc_read(st, ADI_REG_STATUS, &stat);
+ if (ret < 0)
+ return ret;
+
+ if (stat & ADI_STATUS) {
+ for (chan = 0, stat = 0; chan < 4; chan++) {
+ ret = axiadc_read(st, ADI_REG_CHAN_STATUS(chan), &tmp);
+ if (ret < 0)
+ return ret;
+ stat |= tmp;
+ }
+ } else {
+ stat = 1;
+ }
+#else
+ if (axiadc_read(st, ADI_REG_STATUS) & ADI_STATUS) {
+ for (chan = 0, ret = 0; chan < 4; chan++)
+ ret |= axiadc_read(st, ADI_REG_CHAN_STATUS(chan));
+ }
+ else {
+ ret = 1;
+ }
+#endif // NUAND_MODIFICATIONS
+
+ field[i][j] = ret;
+ }
+ }
+
+ ad9361_spi_write(phy->spi, REG_RX_CLOCK_DATA_DELAY, rx);
+
+ ad9361_bist_prbs(phy, BIST_DISABLE);
+
+ len += snprintf(buf + len, buflen, "CLK: %"PRIu32" Hz 'o' = PASS\n",
+ clk_get_rate(phy, phy->ref_clk_scale[RX_SAMPL_CLK]));
+ len += snprintf(buf + len, buflen, "DC");
+ for (i = 0; i < 16; i++)
+ len += snprintf(buf + len, buflen, "%"PRIx32":", i);
+ len += snprintf(buf + len, buflen, "\n");
+
+ for (i = 0; i < 16; i++) {
+ len += snprintf(buf + len, buflen, "%"PRIx32":", i);
+ for (j = 0; j < 16; j++) {
+ len += snprintf(buf + len, buflen, "%c ",
+ (field[i][j] ? '.' : 'o'));
+ }
+ len += snprintf(buf + len, buflen, "\n");
+ }
+ len += snprintf(buf + len, buflen, "\n");
+
+ return len;
+}
+
+/**
+ * Digital tune.
+ * @param phy The AD9361 state structure.
+ * @param max_freq Maximum frequency.
+ * @param flags Flags: BE_VERBOSE, BE_MOREVERBOSE, DO_IDELAY, DO_ODELAY.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_dig_tune(struct ad9361_rf_phy *phy, uint32_t max_freq,
+ enum dig_tune_flags flags)
+{
+ struct axiadc_converter *conv = phy->adc_conv;
+ struct axiadc_state *st = phy->adc_state;
+ int32_t ret, i, j, k, chan, t, num_chan, err = 0;
+ uint32_t s0, s1, c0, c1, tmp, saved = 0;
+ uint8_t field[2][16];
+ uint32_t saved_dsel[4], saved_chan_ctrl6[4], saved_chan_ctrl0[4];
+ uint32_t rates[3] = {25000000U, 40000000U, 61440000U};
+ uint32_t hdl_dac_version;
+
+ dev_dbg(&phy->spi->dev, "%s: freq %"PRIu32" flags 0x%X\n", __func__,
+ max_freq, flags);
+
+#ifdef NUAND_MODIFICATIONS
+ ret = axiadc_read(st, 0x4000, &hdl_dac_version);
+ if (ret < 0)
+ return ret;
+#else
+ hdl_dac_version = axiadc_read(st, 0x4000);
+#endif // NUAND_MODIFICATIONS
+
+ if ((phy->pdata->dig_interface_tune_skipmode == 2) ||
+ (flags & RESTORE_DEFAULT)) {
+ /* skip completely and use defaults */
+ ad9361_spi_write(phy->spi, REG_RX_CLOCK_DATA_DELAY,
+ phy->pdata->port_ctrl.rx_clk_data_delay);
+
+ ad9361_spi_write(phy->spi, REG_TX_CLOCK_DATA_DELAY,
+ phy->pdata->port_ctrl.tx_clk_data_delay);
+
+ return 0;
+ }
+
+ /* Mute TX, we don't want to transmit the PRBS */
+ ad9361_tx_mute(phy, 1);
+
+ if (flags & DO_IDELAY)
+ ad9361_midscale_iodelay(phy, 0);
+
+ if (flags & DO_ODELAY)
+ ad9361_midscale_iodelay(phy, 1);
+
+ if (!phy->pdata->fdd) {
+ ad9361_set_ensm_mode(phy, true, false);
+ ad9361_ensm_force_state(phy, ENSM_STATE_FDD);
+ } else {
+ ad9361_ensm_force_state(phy, ENSM_STATE_ALERT);
+ ad9361_ensm_restore_prev_state(phy);
+ }
+
+ num_chan = (conv->chip_info->num_channels > 4) ? 4 :
+ conv->chip_info->num_channels;
+
+ ad9361_bist_prbs(phy, BIST_INJ_RX);
+
+ for (t = 0; t < 2; t++) {
+ memset(field, 0, 32);
+ for (k = 0; (uint32_t)k < (max_freq ? ARRAY_SIZE(rates) : 1); k++) {
+ if (max_freq)
+ ad9361_set_trx_clock_chain_freq(phy,
+ ((phy->pdata->port_ctrl.pp_conf[2] & LVDS_MODE) || !phy->pdata->rx2tx2) ?
+ rates[k] : rates[k] / 2);
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < 16; j++) {
+ ad9361_spi_write(phy->spi,
+ REG_RX_CLOCK_DATA_DELAY + t,
+ RX_DATA_DELAY(i == 0 ? j : 0) |
+ DATA_CLK_DELAY(i ? j : 0));
+ for (chan = 0; chan < num_chan; chan++)
+ axiadc_write(st, ADI_REG_CHAN_STATUS(chan),
+ ADI_PN_ERR | ADI_PN_OOS);
+ mdelay(4);
+
+#ifdef NUAND_MODIFICATIONS
+ uint32_t stat;
+ ret = axiadc_read(st, ADI_REG_STATUS, &stat);
+ if (ret < 0)
+ return ret;
+
+ if ((t == 1) || (stat & ADI_STATUS)) {
+ for (chan = 0, stat = 0; chan < num_chan; chan++) {
+ ret = axiadc_read(st, ADI_REG_CHAN_STATUS(chan), &tmp);
+ if (ret < 0)
+ return ret;
+ stat |= tmp;
+ }
+ } else {
+ stat = 1;
+ }
+
+ field[i][j] |= stat;
+#else
+ if ((t == 1) || (axiadc_read(st, ADI_REG_STATUS) & ADI_STATUS)) {
+ for (chan = 0, ret = 0; chan < num_chan; chan++) {
+ ret |= axiadc_read(st, ADI_REG_CHAN_STATUS(chan));
+ }
+ }
+ else {
+ ret = 1;
+ }
+
+ field[i][j] |= ret;
+#endif // NUAND_MODIFICATIONS
+ }
+ }
+ if ((flags & BE_MOREVERBOSE) && max_freq) {
+ ad9361_dig_tune_verbose_print(phy, field, t);
+ }
+ }
+
+ c0 = ad9361_find_opt(&field[0][0], 16, &s0);
+ c1 = ad9361_find_opt(&field[1][0], 16, &s1);
+
+ if (!c0 && !c1) {
+ ad9361_dig_tune_verbose_print(phy, field, t);
+ dev_err(&phy->spi->dev, "%s: Tuning %s FAILED!", __func__,
+ t ? "TX" : "RX");
+ err |= -EIO;
+ } else if (flags & BE_VERBOSE) {
+ ad9361_dig_tune_verbose_print(phy, field, t);
+ }
+
+ if (c1 > c0)
+ ad9361_spi_write(phy->spi, REG_RX_CLOCK_DATA_DELAY + t,
+ DATA_CLK_DELAY(s1 + c1 / 2) |
+ RX_DATA_DELAY(0));
+ else
+ ad9361_spi_write(phy->spi, REG_RX_CLOCK_DATA_DELAY + t,
+ DATA_CLK_DELAY(0) |
+ RX_DATA_DELAY(s0 + c0 / 2));
+
+ if (t == 0) {
+ if (flags & DO_IDELAY)
+ ad9361_dig_tune_iodelay(phy, 0);
+
+ /* Now do the loopback and tune the digital out */
+ ad9361_bist_prbs(phy, BIST_DISABLE);
+
+ axiadc_write(st, ADI_REG_RSTN, ADI_MMCM_RSTN);
+ axiadc_write(st, ADI_REG_RSTN, ADI_RSTN | ADI_MMCM_RSTN);
+
+ if (phy->pdata->dig_interface_tune_skipmode == 1) {
+ /* skip TX */
+ if (!(flags & SKIP_STORE_RESULT))
+ phy->pdata->port_ctrl.rx_clk_data_delay =
+ ad9361_spi_read(phy->spi, REG_RX_CLOCK_DATA_DELAY);
+
+ if (!phy->pdata->fdd) {
+ ad9361_set_ensm_mode(phy, phy->pdata->fdd,
+ phy->pdata->ensm_pin_ctrl);
+ ad9361_ensm_restore_prev_state(phy);
+ }
+
+ ad9361_tx_mute(phy, 0);
+
+ return 0;
+ }
+
+ ad9361_bist_loopback(phy, 1);
+ axiadc_write(st, 0x4000 + ADI_REG_RSTN, ADI_RSTN | ADI_MMCM_RSTN);
+
+ for (chan = 0; chan < num_chan; chan++) {
+#ifdef NUAND_MODIFICATIONS
+ ret = axiadc_read(st, ADI_REG_CHAN_CNTRL(chan), &saved_chan_ctrl0[chan]);
+ if (ret < 0)
+ return ret;
+
+ ret = axiadc_write(st, ADI_REG_CHAN_CNTRL(chan),
+ ADI_FORMAT_SIGNEXT | ADI_FORMAT_ENABLE |
+ ADI_ENABLE | ADI_IQCOR_ENB);
+ if (ret < 0)
+ return ret;
+
+ ret = axiadc_set_pnsel(st, chan, ADC_PN_CUSTOM);
+ if (ret < 0)
+ return ret;
+
+ ret = axiadc_read(st, 0x4414 + (chan) * 0x40, &saved_chan_ctrl6[chan]);
+ if (ret < 0)
+ return ret;
+
+ if (PCORE_VERSION_MAJOR(hdl_dac_version) > 7)
+ {
+ ret = axiadc_read(st, 0x4418 + (chan) * 0x40, &saved_dsel[chan]);
+ if (ret < 0)
+ return ret;
+
+ ret = axiadc_write(st, 0x4418 + (chan) * 0x40, 9);
+ if (ret < 0)
+ return ret;
+
+ ret = axiadc_write(st, 0x4414 + (chan) * 0x40, 0); /* !IQCOR_ENB */
+ if (ret < 0)
+ return ret;
+
+ ret = axiadc_write(st, 0x4044, 0x1);
+ if (ret < 0)
+ return ret;
+ } else {
+ ret = axiadc_write(st, 0x4414 + (chan) * 0x40, 1); /* DAC_PN_ENB */
+ if (ret < 0)
+ return ret;
+ }
+#else
+ saved_chan_ctrl0[chan] = axiadc_read(st, ADI_REG_CHAN_CNTRL(chan));
+ axiadc_write(st, ADI_REG_CHAN_CNTRL(chan),
+ ADI_FORMAT_SIGNEXT | ADI_FORMAT_ENABLE |
+ ADI_ENABLE | ADI_IQCOR_ENB);
+ axiadc_set_pnsel(st, chan, ADC_PN_CUSTOM);
+ saved_chan_ctrl6[chan] = axiadc_read(st, 0x4414 + (chan) * 0x40);
+ if (PCORE_VERSION_MAJOR(hdl_dac_version) > 7)
+ {
+ saved_dsel[chan] = axiadc_read(st, 0x4418 + (chan) * 0x40);
+ axiadc_write(st, 0x4418 + (chan) * 0x40, 9);
+ axiadc_write(st, 0x4414 + (chan) * 0x40, 0); /* !IQCOR_ENB */
+ axiadc_write(st, 0x4044, 0x1);
+ }
+ else
+ axiadc_write(st, 0x4414 + (chan) * 0x40, 1); /* DAC_PN_ENB */
+#endif // NUAND_MODIFICATIONS
+ }
+ if (PCORE_VERSION_MAJOR(hdl_dac_version) < 8) {
+#ifdef NUAND_MODIFICATIONS
+ ret = axiadc_read(st, 0x4048, &tmp);
+ if (ret < 0)
+ return ret;
+
+ saved = tmp;
+#else
+ saved = tmp = axiadc_read(st, 0x4048);
+#endif // NUAND_MODIFICATIONS
+ tmp &= ~0xF;
+ tmp |= 1;
+ axiadc_write(st, 0x4048, tmp);
+
+ }
+ } else {
+ if (flags & DO_ODELAY)
+ ad9361_dig_tune_iodelay(phy, 1);
+
+ ad9361_bist_loopback(phy, 0);
+
+ if (PCORE_VERSION_MAJOR(hdl_dac_version) < 8)
+ axiadc_write(st, 0x4048, saved);
+
+ for (chan = 0; chan < num_chan; chan++) {
+ axiadc_write(st, ADI_REG_CHAN_CNTRL(chan),
+ saved_chan_ctrl0[chan]);
+ axiadc_set_pnsel(st, chan, ADC_PN9);
+ if (PCORE_VERSION_MAJOR(hdl_dac_version) > 7)
+ {
+ axiadc_write(st, 0x4418 + (chan) * 0x40, saved_dsel[chan]);
+ axiadc_write(st, 0x4044, 0x1);
+ }
+
+ axiadc_write(st, 0x4414 + (chan) * 0x40, saved_chan_ctrl6[chan]);
+
+ }
+
+ if (err == -EIO) {
+ ad9361_spi_write(phy->spi, REG_RX_CLOCK_DATA_DELAY,
+ phy->pdata->port_ctrl.rx_clk_data_delay);
+
+ ad9361_spi_write(phy->spi, REG_TX_CLOCK_DATA_DELAY,
+ phy->pdata->port_ctrl.tx_clk_data_delay);
+ if (!max_freq)
+ err = 0;
+ } else if (!(flags & SKIP_STORE_RESULT)) {
+ phy->pdata->port_ctrl.rx_clk_data_delay =
+ ad9361_spi_read(phy->spi, REG_RX_CLOCK_DATA_DELAY);
+ phy->pdata->port_ctrl.tx_clk_data_delay =
+ ad9361_spi_read(phy->spi, REG_TX_CLOCK_DATA_DELAY);
+ }
+
+ if (!phy->pdata->fdd) {
+ ad9361_set_ensm_mode(phy, phy->pdata->fdd, phy->pdata->ensm_pin_ctrl);
+ ad9361_ensm_restore_prev_state(phy);
+ }
+
+ axiadc_write(st, ADI_REG_RSTN, ADI_MMCM_RSTN);
+ axiadc_write(st, ADI_REG_RSTN, ADI_RSTN | ADI_MMCM_RSTN);
+
+ ad9361_tx_mute(phy, 0);
+
+ return err;
+ }
+ }
+
+ return -EINVAL;
+}
+
+/**
+* Setup the AD9361 device.
+* @param phy The AD9361 state structure.
+* @return 0 in case of success, negative error code otherwise.
+*/
+int32_t ad9361_post_setup(struct ad9361_rf_phy *phy)
+{
+ struct axiadc_converter *conv = phy->adc_conv;
+ struct axiadc_state *st = phy->adc_state;
+ int32_t rx2tx2 = phy->pdata->rx2tx2;
+ int32_t tmp, num_chan, flags;
+ int32_t i, ret;
+
+ num_chan = (conv->chip_info->num_channels > 4) ? 4 : conv->chip_info->num_channels;
+
+#ifdef NUAND_MODIFICATIONS
+ ret = axiadc_write(st, ADI_REG_CNTRL, rx2tx2 ? 0 : ADI_R1_MODE);
+ if (ret < 0)
+ return ret;
+
+ uint32_t u32tmp;
+ ret = axiadc_read(st, 0x4048, &u32tmp);
+ if (ret < 0)
+ return ret;
+
+ tmp = (int32_t)u32tmp;
+#else
+ axiadc_write(st, ADI_REG_CNTRL, rx2tx2 ? 0 : ADI_R1_MODE);
+ tmp = axiadc_read(st, 0x4048);
+#endif // NUAND_MODIFICATIONS
+
+ if (!rx2tx2) {
+ axiadc_write(st, 0x4048, tmp | BIT(5)); /* R1_MODE */
+ axiadc_write(st, 0x404c,
+ (phy->pdata->port_ctrl.pp_conf[2] & LVDS_MODE) ? 1 : 0); /* RATE */
+ }
+ else {
+ tmp &= ~BIT(5);
+ axiadc_write(st, 0x4048, tmp);
+ axiadc_write(st, 0x404c,
+ (phy->pdata->port_ctrl.pp_conf[2] & LVDS_MODE) ? 3 : 1); /* RATE */
+ }
+
+#ifdef ALTERA_PLATFORM
+ axiadc_write(st, 0x404c, 1);
+#endif
+
+ for (i = 0; i < num_chan; i++) {
+ axiadc_write(st, ADI_REG_CHAN_CNTRL_1(i),
+ ADI_DCFILT_OFFSET(0));
+ axiadc_write(st, ADI_REG_CHAN_CNTRL_2(i),
+ (i & 1) ? 0x00004000 : 0x40000000);
+ axiadc_write(st, ADI_REG_CHAN_CNTRL(i),
+ ADI_FORMAT_SIGNEXT | ADI_FORMAT_ENABLE |
+ ADI_ENABLE | ADI_IQCOR_ENB);
+ }
+
+ flags = 0x0;
+
+#ifdef NUAND_MODIFICATIONS
+ ret = axiadc_read(st, 0x0004, &u32tmp);
+ if (ret < 0)
+ return ret;
+ ret = ad9361_dig_tune(phy, ((conv->chip_info->num_channels > 4) ||
+ u32tmp) ? 0 : 61440000, flags);
+#else
+ ret = ad9361_dig_tune(phy, ((conv->chip_info->num_channels > 4) ||
+ axiadc_read(st, 0x0004)) ? 0 : 61440000, flags);
+#endif // NUAND_MODIFICATIONS
+ if (ret < 0)
+ return ret;
+
+ if (flags & (DO_IDELAY | DO_ODELAY)) {
+#ifdef NUAND_MODIFICATIONS
+ ret = axiadc_read(st, ADI_REG_ID, &u32tmp);
+ if (ret < 0)
+ return ret;
+ ret = ad9361_dig_tune(phy, u32tmp ? 0 : 61440000, flags & BE_VERBOSE);
+#else
+ ret = ad9361_dig_tune(phy, (axiadc_read(st, ADI_REG_ID)) ?
+ 0 : 61440000, flags & BE_VERBOSE);
+#endif // NUAND_MODIFICATIONS
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = ad9361_set_trx_clock_chain(phy,
+ phy->pdata->rx_path_clks,
+ phy->pdata->tx_path_clks);
+
+ ad9361_ensm_force_state(phy, ENSM_STATE_ALERT);
+ ad9361_ensm_restore_prev_state(phy);
+
+ return ret;
+}
+#else
+/**
+ * HDL loopback enable/disable.
+ * @param phy The AD9361 state structure.
+ * @param enable Enable/disable option.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_hdl_loopback(struct ad9361_rf_phy *phy, bool enable)
+{
+ return -ENODEV;
+}
+
+/**
+ * Digital tune.
+ * @param phy The AD9361 state structure.
+ * @param max_freq Maximum frequency.
+ * @param flags Flags: BE_VERBOSE, BE_MOREVERBOSE, DO_IDELAY, DO_ODELAY.
+ * @return 0 in case of success, negative error code otherwise.
+ */
+int32_t ad9361_dig_tune(struct ad9361_rf_phy *phy, uint32_t max_freq,
+ enum dig_tune_flags flags)
+{
+ return 0;
+}
+
+/**
+* Setup the AD9361 device.
+* @param phy The AD9361 state structure.
+* @return 0 in case of success, negative error code otherwise.
+*/
+int32_t ad9361_post_setup(struct ad9361_rf_phy *phy)
+{
+ return 0;
+}
+#endif
diff --git a/Radio/HW/BladeRF/common/thirdparty/ad936x/common.h b/Radio/HW/BladeRF/common/thirdparty/ad936x/common.h
new file mode 100644
index 0000000..b140494
--- /dev/null
+++ b/Radio/HW/BladeRF/common/thirdparty/ad936x/common.h
@@ -0,0 +1,100 @@
+/***************************************************************************//**
+ * @file common.h
+ * @brief Header file of Common Driver.
+ * @author DBogdan (dragos.bogdan@analog.com)
+********************************************************************************
+ * Copyright 2013(c) Analog Devices, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of Analog Devices, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * - The use of this software may or may not infringe the patent rights
+ * of one or more patent holders. This license does not release you
+ * from the requirement that you obtain separate licenses from these
+ * patent holders to use this software.
+ * - Use of the software either in source or binary form, must be run
+ * on or directly connected to an Analog Devices Inc. component.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+#ifndef COMMON_H_
+#define COMMON_H_
+
+/******************************************************************************/
+/***************************** Include Files **********************************/
+/******************************************************************************/
+#include <stdint.h>
+
+/******************************************************************************/
+/********************** Macros and Constants Definitions **********************/
+/******************************************************************************/
+#ifdef NUAND_MODIFICATIONS
+// just use errno
+#include <errno.h>
+#else
+#define EIO 5 /* I/O error */
+#define EAGAIN 11 /* Try again */
+#define ENOMEM 12 /* Out of memory */
+#define EFAULT 14 /* Bad address */
+#define ENODEV 19 /* No such device */
+#define EINVAL 22 /* Invalid argument */
+#define ETIMEDOUT 110 /* Connection timed out */
+#endif // NUAND_MODIFICATIONS
+
+/******************************************************************************/
+/*************************** Types Declarations *******************************/
+/******************************************************************************/
+
+#ifdef NUAND_MODIFICATIONS
+// just use stdbool
+#include <stdbool.h>
+#else
+#if defined (__STDC__) && (__STDC_VERSION__ >= 199901L)
+#include <stdbool.h>
+#else
+typedef enum { false, true } bool;
+#endif
+#endif // NUAND_MODIFICATIONS
+
+struct clk {
+ const char *name;
+ uint32_t rate;
+};
+
+struct clk_hw {
+ struct clk *clk;
+};
+
+struct clk_init_data {
+ const char *name;
+ const struct clk_ops *ops;
+ const char **parent_names;
+ uint8_t num_parents;
+ uint32_t flags;
+};
+
+struct clk_onecell_data {
+ struct clk **clks;
+ uint32_t clk_num;
+};
+
+#endif
diff --git a/Radio/HW/BladeRF/common/thirdparty/ad936x/util.c b/Radio/HW/BladeRF/common/thirdparty/ad936x/util.c
new file mode 100644
index 0000000..8965553
--- /dev/null
+++ b/Radio/HW/BladeRF/common/thirdparty/ad936x/util.c
@@ -0,0 +1,347 @@
+/***************************************************************************//**
+ * @file util.c
+ * @brief Implementation of Util Driver.
+ * @author DBogdan (dragos.bogdan@analog.com)
+********************************************************************************
+ * Copyright 2013(c) Analog Devices, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of Analog Devices, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * - The use of this software may or may not infringe the patent rights
+ * of one or more patent holders. This license does not release you
+ * from the requirement that you obtain separate licenses from these
+ * patent holders to use this software.
+ * - Use of the software either in source or binary form, must be run
+ * on or directly connected to an Analog Devices Inc. component.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+/******************************************************************************/
+/***************************** Include Files **********************************/
+/******************************************************************************/
+#include "util.h"
+#include "string.h"
+#include "platform.h"
+
+/******************************************************************************/
+/*************************** Macros Definitions *******************************/
+/******************************************************************************/
+#define BITS_PER_LONG 32
+
+/***************************************************************************//**
+ * @brief clk_prepare_enable
+*******************************************************************************/
+int32_t clk_prepare_enable(struct clk *clk)
+{
+ if (clk) {
+ // Unused variable - fix compiler warning
+ }
+
+ return 0;
+}
+
+/***************************************************************************//**
+ * @brief clk_get_rate
+*******************************************************************************/
+uint32_t clk_get_rate(struct ad9361_rf_phy *phy,
+ struct refclk_scale *clk_priv)
+{
+ uint32_t rate = 0;
+ uint32_t source;
+
+ source = clk_priv->source;
+
+ switch (source) {
+ case TX_REFCLK:
+ case RX_REFCLK:
+ case BB_REFCLK:
+ rate = ad9361_clk_factor_recalc_rate(clk_priv,
+ phy->clk_refin->rate);
+ break;
+ case TX_RFPLL_INT:
+ case RX_RFPLL_INT:
+ rate = ad9361_rfpll_int_recalc_rate(clk_priv,
+ phy->clks[clk_priv->parent_source]->rate);
+ case RX_RFPLL_DUMMY:
+ case TX_RFPLL_DUMMY:
+ rate = ad9361_rfpll_dummy_recalc_rate(clk_priv);
+ break;
+ case TX_RFPLL:
+ case RX_RFPLL:
+ rate = ad9361_rfpll_recalc_rate(clk_priv);
+ break;
+ case BBPLL_CLK:
+ rate = ad9361_bbpll_recalc_rate(clk_priv,
+ phy->clks[clk_priv->parent_source]->rate);
+ break;
+ case ADC_CLK:
+ case R2_CLK:
+ case R1_CLK:
+ case CLKRF_CLK:
+ case RX_SAMPL_CLK:
+ case DAC_CLK:
+ case T2_CLK:
+ case T1_CLK:
+ case CLKTF_CLK:
+ case TX_SAMPL_CLK:
+ rate = ad9361_clk_factor_recalc_rate(clk_priv,
+ phy->clks[clk_priv->parent_source]->rate);
+ break;
+ default:
+ break;
+ }
+
+ return rate;
+}
+
+/***************************************************************************//**
+ * @brief clk_set_rate
+*******************************************************************************/
+int32_t clk_set_rate(struct ad9361_rf_phy *phy,
+ struct refclk_scale *clk_priv,
+ uint32_t rate)
+{
+ uint32_t source;
+ int32_t i;
+ uint32_t round_rate;
+
+ source = clk_priv->source;
+ if(phy->clks[source]->rate != rate)
+ {
+ switch (source) {
+ case TX_REFCLK:
+ case RX_REFCLK:
+ case BB_REFCLK:
+ round_rate = ad9361_clk_factor_round_rate(clk_priv, rate,
+ &phy->clk_refin->rate);
+ ad9361_clk_factor_set_rate(clk_priv, round_rate,
+ phy->clk_refin->rate);
+ phy->clks[source]->rate = ad9361_clk_factor_recalc_rate(clk_priv,
+ phy->clk_refin->rate);
+ break;
+ case TX_RFPLL_INT:
+ case RX_RFPLL_INT:
+ round_rate = ad9361_rfpll_int_round_rate(clk_priv, rate,
+ &phy->clks[clk_priv->parent_source]->rate);
+ ad9361_rfpll_int_set_rate(clk_priv, round_rate,
+ phy->clks[clk_priv->parent_source]->rate);
+ phy->clks[source]->rate = ad9361_rfpll_int_recalc_rate(clk_priv,
+ phy->clks[clk_priv->parent_source]->rate);
+ break;
+ case RX_RFPLL_DUMMY:
+ case TX_RFPLL_DUMMY:
+ ad9361_rfpll_dummy_set_rate(clk_priv, rate);
+ case TX_RFPLL:
+ case RX_RFPLL:
+ round_rate = ad9361_rfpll_round_rate(clk_priv, rate);
+ ad9361_rfpll_set_rate(clk_priv, round_rate);
+ phy->clks[source]->rate = ad9361_rfpll_recalc_rate(clk_priv);
+ break;
+ case BBPLL_CLK:
+ round_rate = ad9361_bbpll_round_rate(clk_priv, rate,
+ &phy->clks[clk_priv->parent_source]->rate);
+ ad9361_bbpll_set_rate(clk_priv, round_rate,
+ phy->clks[clk_priv->parent_source]->rate);
+ phy->clks[source]->rate = ad9361_bbpll_recalc_rate(clk_priv,
+ phy->clks[clk_priv->parent_source]->rate);
+ phy->bbpll_initialized = true;
+ break;
+ case ADC_CLK:
+ case R2_CLK:
+ case R1_CLK:
+ case CLKRF_CLK:
+ case RX_SAMPL_CLK:
+ case DAC_CLK:
+ case T2_CLK:
+ case T1_CLK:
+ case CLKTF_CLK:
+ case TX_SAMPL_CLK:
+ round_rate = ad9361_clk_factor_round_rate(clk_priv, rate,
+ &phy->clks[clk_priv->parent_source]->rate);
+ ad9361_clk_factor_set_rate(clk_priv, round_rate,
+ phy->clks[clk_priv->parent_source]->rate);
+ phy->clks[source]->rate = ad9361_clk_factor_recalc_rate(clk_priv,
+ phy->clks[clk_priv->parent_source]->rate);
+ break;
+ default:
+ break;
+ }
+ for(i = BB_REFCLK; i < BBPLL_CLK; i++)
+ {
+ phy->clks[i]->rate = ad9361_clk_factor_recalc_rate(phy->ref_clk_scale[i],
+ phy->clk_refin->rate);
+ }
+ phy->clks[BBPLL_CLK]->rate = ad9361_bbpll_recalc_rate(phy->ref_clk_scale[BBPLL_CLK],
+ phy->clks[phy->ref_clk_scale[BBPLL_CLK]->parent_source]->rate);
+ for(i = ADC_CLK; i < RX_RFPLL_INT; i++)
+ {
+ phy->clks[i]->rate = ad9361_clk_factor_recalc_rate(phy->ref_clk_scale[i],
+ phy->clks[phy->ref_clk_scale[i]->parent_source]->rate);
+ }
+ for(i = RX_RFPLL_INT; i < RX_RFPLL_DUMMY; i++)
+ {
+ phy->clks[i]->rate = ad9361_rfpll_int_recalc_rate(phy->ref_clk_scale[i],
+ phy->clks[phy->ref_clk_scale[i]->parent_source]->rate);
+ }
+ for(i = RX_RFPLL_DUMMY; i < RX_RFPLL; i++)
+ {
+ phy->clks[i]->rate = ad9361_rfpll_dummy_recalc_rate(phy->ref_clk_scale[i]);
+ }
+ for(i = RX_RFPLL; i < NUM_AD9361_CLKS; i++)
+ {
+ phy->clks[i]->rate = ad9361_rfpll_recalc_rate(phy->ref_clk_scale[i]);
+ }
+ } else {
+ if ((source == BBPLL_CLK) && !phy->bbpll_initialized) {
+ round_rate = ad9361_bbpll_round_rate(clk_priv, rate,
+ &phy->clks[clk_priv->parent_source]->rate);
+ ad9361_bbpll_set_rate(clk_priv, round_rate,
+ phy->clks[clk_priv->parent_source]->rate);
+ phy->clks[source]->rate = ad9361_bbpll_recalc_rate(clk_priv,
+ phy->clks[clk_priv->parent_source]->rate);
+ phy->bbpll_initialized = true;
+ }
+ }
+
+ return 0;
+}
+
+/***************************************************************************//**
+ * @brief int_sqrt
+*******************************************************************************/
+uint32_t int_sqrt(uint32_t x)
+{
+ uint32_t b, m, y = 0;
+
+ if (x <= 1)
+ return x;
+
+ m = 1UL << (BITS_PER_LONG - 2);
+ while (m != 0) {
+ b = y + m;
+ y >>= 1;
+
+ if (x >= b) {
+ x -= b;
+ y += m;
+ }
+ m >>= 2;
+ }
+
+ return y;
+}
+
+/***************************************************************************//**
+ * @brief ilog2
+*******************************************************************************/
+int32_t ilog2(int32_t x)
+{
+ int32_t A = !(!(x >> 16));
+ int32_t count = 0;
+ int32_t x_copy = x;
+
+ count = count + (A << 4);
+
+ x_copy = (((~A + 1) & (x >> 16)) + (~(~A + 1) & x));
+
+ A = !(!(x_copy >> 8));
+ count = count + (A << 3);
+ x_copy = (((~A + 1) & (x_copy >> 8)) + (~(~A + 1) & x_copy));
+
+ A = !(!(x_copy >> 4));
+ count = count + (A << 2);
+ x_copy = (((~A + 1) & (x_copy >> 4)) + (~(~A + 1) & x_copy));
+
+ A = !(!(x_copy >> 2));
+ count = count + (A << 1);
+ x_copy = (((~A + 1) & (x_copy >> 2)) + (~(~A + 1) & x_copy));
+
+ A = !(!(x_copy >> 1));
+ count = count + A;
+
+ return count;
+}
+
+/***************************************************************************//**
+ * @brief do_div
+*******************************************************************************/
+uint64_t do_div(uint64_t* n, uint64_t base)
+{
+ uint64_t mod = 0;
+
+ mod = *n % base;
+ *n = *n / base;
+
+ return mod;
+}
+
+/***************************************************************************//**
+ * @brief find_first_bit
+*******************************************************************************/
+uint32_t find_first_bit(uint32_t word)
+{
+ int32_t num = 0;
+
+ if ((word & 0xffff) == 0) {
+ num += 16;
+ word >>= 16;
+ }
+ if ((word & 0xff) == 0) {
+ num += 8;
+ word >>= 8;
+ }
+ if ((word & 0xf) == 0) {
+ num += 4;
+ word >>= 4;
+ }
+ if ((word & 0x3) == 0) {
+ num += 2;
+ word >>= 2;
+ }
+ if ((word & 0x1) == 0)
+ num += 1;
+ return num;
+}
+
+/***************************************************************************//**
+ * @brief ERR_PTR
+*******************************************************************************/
+void * ERR_PTR(long error)
+{
+ uintptr_t val = error;
+ return (void *) val;
+}
+
+/***************************************************************************//**
+ * @brief zmalloc
+*******************************************************************************/
+void *zmalloc(size_t size)
+{
+ void *ptr = malloc(size);
+ if (ptr)
+ memset(ptr, 0, size);
+ mdelay(1);
+
+ return ptr;
+}
diff --git a/Radio/HW/BladeRF/common/thirdparty/ad936x/util.h b/Radio/HW/BladeRF/common/thirdparty/ad936x/util.h
new file mode 100644
index 0000000..2b3f25e
--- /dev/null
+++ b/Radio/HW/BladeRF/common/thirdparty/ad936x/util.h
@@ -0,0 +1,186 @@
+/***************************************************************************//**
+ * @file util.h
+ * @brief Header file of Util driver.
+ * @author DBogdan (dragos.bogdan@analog.com)
+********************************************************************************
+ * Copyright 2013(c) Analog Devices, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of Analog Devices, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * - The use of this software may or may not infringe the patent rights
+ * of one or more patent holders. This license does not release you
+ * from the requirement that you obtain separate licenses from these
+ * patent holders to use this software.
+ * - Use of the software either in source or binary form, must be run
+ * on or directly connected to an Analog Devices Inc. component.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+#ifndef __NO_OS_PORT_H__
+#define __NO_OS_PORT_H__
+
+/******************************************************************************/
+/***************************** Include Files **********************************/
+/******************************************************************************/
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "ad9361.h"
+#include "common.h"
+#include "config.h"
+
+#ifdef NUAND_MODIFICATIONS
+// include adc/dac core headers
+#include "adc_core.h"
+#include "dac_core.h"
+#endif // NUAND_MODIFICATIONS
+
+/******************************************************************************/
+/********************** Macros and Constants Definitions **********************/
+/******************************************************************************/
+#define SUCCESS 0
+#ifdef NUAND_MODIFICATIONS
+// guard on ARRAY_SIZE (already defined in libbladeRF)
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#endif
+#else
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#endif // NUAND_MODIFICATIONS
+#define min(x, y) (((x) < (y)) ? (x) : (y))
+#define min_t(type, x, y) (type)min((type)(x), (type)(y))
+#define max(x, y) (((x) > (y)) ? (x) : (y))
+#define max_t(type, x, y) (type)max((type)(x), (type)(y))
+#define clamp(val, min_val, max_val) (max(min((val), (max_val)), (min_val)))
+#define clamp_t(type, val, min_val, max_val) (type)clamp((type)(val), (type)(min_val), (type)(max_val))
+#define DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y))
+#define DIV_ROUND_CLOSEST(x, divisor) (((x) + (divisor) / 2) / (divisor))
+#define BIT(x) (1 << (x))
+#define CLK_IGNORE_UNUSED BIT(3)
+#define CLK_GET_RATE_NOCACHE BIT(6)
+
+#ifdef NUAND_MODIFICATIONS
+// Fix a whole slew of MSVC compiler errors...
+#if defined(HAVE_VERBOSE_MESSAGES)
+#define dev_err(dev, format, ...) {printf(format, ## __VA_ARGS__);printf("\n"); }
+#define dev_warn(dev, format, ...) {printf(format, ## __VA_ARGS__);printf("\n"); }
+#if defined(HAVE_DEBUG_MESSAGES)
+#define dev_dbg(dev, format, ...) {printf(format, ## __VA_ARGS__);printf("\n"); }
+#else
+#define dev_dbg(dev, format, ...) { if (0) printf(format, ## __VA_ARGS__); }
+#endif
+#define printk(format, ...) printf(format, ## __VA_ARGS__)
+#else
+#define dev_err(dev, format, ...) { if (0) printf(format, ## __VA_ARGS__); }
+#define dev_warn(dev, format, ...) { if (0) printf(format, ## __VA_ARGS__); }
+#define dev_dbg(dev, format, ...) { if (0) printf(format, ## __VA_ARGS__); }
+#define printk(format, ...) { if (0) printf(format, ## __VA_ARGS__); }
+#endif
+#else
+#if defined(HAVE_VERBOSE_MESSAGES)
+#define dev_err(dev, format, ...) ({printf(format, ## __VA_ARGS__);printf("\n"); })
+#define dev_warn(dev, format, ...) ({printf(format, ## __VA_ARGS__);printf("\n"); })
+#if defined(HAVE_DEBUG_MESSAGES)
+#define dev_dbg(dev, format, ...) ({printf(format, ## __VA_ARGS__);printf("\n"); })
+#else
+#define dev_dbg(dev, format, ...) ({ if (0) printf(format, ## __VA_ARGS__); })
+#endif
+#define printk(format, ...) printf(format, ## __VA_ARGS__)
+#else
+#define dev_err(dev, format, ...) ({ if (0) printf(format, ## __VA_ARGS__); })
+#define dev_warn(dev, format, ...) ({ if (0) printf(format, ## __VA_ARGS__); })
+#define dev_dbg(dev, format, ...) ({ if (0) printf(format, ## __VA_ARGS__); })
+#define printk(format, ...) ({ if (0) printf(format, ## __VA_ARGS__); })
+#endif
+#endif // NUAND_MODIFICATIONS
+
+struct device {
+#ifdef NUAND_MODIFICATIONS
+ // fix MSVC code C2016
+ void *noop;
+#endif // NUAND_MODIFICATIONS
+};
+
+struct spi_device {
+ struct device dev;
+ uint8_t id_no;
+#ifdef NUAND_MODIFICATIONS
+ // add userdata field
+ void *userdata;
+#endif // NUAND_MODIFICATIONS
+};
+
+#ifdef NUAND_MODIFICATIONS
+// gpio_device struct
+struct gpio_device {
+ void *userdata;
+};
+#endif // NUAND_MODIFICATIONS
+
+struct axiadc_state {
+ struct ad9361_rf_phy *phy;
+ uint32_t pcore_version;
+#ifdef NUAND_MODIFICATIONS
+ // add DAC DDS state, userdata
+ struct dds_state dac_dds_state;
+ void *userdata;
+#endif // NUAND_MODIFICATIONS
+};
+
+struct axiadc_chip_info {
+ char *name;
+ int32_t num_channels;
+};
+
+struct axiadc_converter {
+ struct axiadc_chip_info *chip_info;
+ uint32_t scratch_reg[16];
+};
+
+#ifdef WIN32
+#include "basetsd.h"
+typedef SSIZE_T ssize_t;
+#define strsep(s, ct) 0
+#define snprintf(s, n, format, ...) 0
+#define __func__ __FUNCTION__
+#endif
+
+/******************************************************************************/
+/************************ Functions Declarations ******************************/
+/******************************************************************************/
+int32_t clk_prepare_enable(struct clk *clk);
+uint32_t clk_get_rate(struct ad9361_rf_phy *phy,
+ struct refclk_scale *clk_priv);
+int32_t clk_set_rate(struct ad9361_rf_phy *phy,
+ struct refclk_scale *clk_priv,
+ uint32_t rate);
+uint32_t int_sqrt(uint32_t x);
+int32_t ilog2(int32_t x);
+uint64_t do_div(uint64_t* n,
+ uint64_t base);
+uint32_t find_first_bit(uint32_t word);
+void * ERR_PTR(long error);
+void *zmalloc(size_t size);
+
+#endif