Exemple #1
0
/**
 * 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);

			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;
			}

			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;
}
Exemple #2
0
/**
 * 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.
 */
struct ad9361_rf_phy *ad9361_init (AD9361_InitParam *init_param)
{
    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 (struct ad9361_rf_phy *)ERR_PTR(-ENOMEM);
    }

    phy->spi = (struct spi_device *)zmalloc(sizeof(*phy->spi));
    if (!phy->spi) {
        return (struct ad9361_rf_phy *)ERR_PTR(-ENOMEM);
    }

    phy->clk_refin = (struct clk *)zmalloc(sizeof(*phy->clk_refin));
    if (!phy->clk_refin) {
        return (struct ad9361_rf_phy *)ERR_PTR(-ENOMEM);
    }

    phy->pdata = (struct ad9361_phy_platform_data *)zmalloc(sizeof(*phy->pdata));
    if (!phy->pdata) {
        return (struct ad9361_rf_phy *)ERR_PTR(-ENOMEM);
    }

    phy->adc_conv = (struct axiadc_converter *)zmalloc(sizeof(*phy->adc_conv));
    if (!phy->adc_conv) {
        return (struct ad9361_rf_phy *)ERR_PTR(-ENOMEM);
    }

    phy->adc_state = (struct axiadc_state *)zmalloc(sizeof(*phy->adc_state));
    if (!phy->adc_state) {
        return (struct ad9361_rf_phy *)ERR_PTR(-ENOMEM);
    }

    /* 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->rx2tx2 = init_param->two_rx_two_tx_mode_enable;
    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;
    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->tdd_use_fdd_tables = init_param->tdd_use_fdd_vco_tables_enable;
    phy->pdata->split_gt = init_param->split_gain_table_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 */
    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_dec_pow_measuremnt_duration = 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;

    /* Digital Interface Control */
    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) & 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;

    /* 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] = 0xFF;
    phy->pdata->port_ctrl.lvds_invert[1] = 0x0F;

    phy->adc_conv->chip_info = &axiadc_chip_info_tbl[phy->pdata->rx2tx2 ? ID_AD9361 : ID_AD9364];

    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;

    ad9361_reset(phy);
    ad9361_spi_write(NULL, REG_SPI_CONF, SOFT_RESET | _SOFT_RESET);
    ad9361_spi_write(NULL, REG_SPI_CONF, 0x0);

    ret = ad9361_spi_read(NULL, REG_PRODUCT_ID);
    if ((ret & PRODUCT_ID_MASK) != PRODUCT_ID_9361) {
        printf("%s : Unsupported PRODUCT_ID 0x%X", "ad9361_init", (unsigned int)ret);
        ret = -ENODEV;
        goto out;
    }
    rev = ret & REV_MASK;

    ret = register_clocks(phy);
    if (ret < 0)
        goto out;

    axiadc_init(phy);

    ad9361_init_gain_tables(phy);

    ret = ad9361_setup(phy);
    if (ret < 0)
        goto out;

    ret = ad9361_post_setup(phy);
    if (ret < 0)
        goto out;

    printf("%s : AD9361 Rev %d successfully initialized\n", "ad9361_init", (int)rev);

    return phy;

out:
    free(phy->spi);
    free(phy->adc_conv);
    free(phy->adc_state);
    free(phy->clk_refin);
    free(phy->pdata);
    free(phy);
    printf("%s : AD9361 initialization error\n", "ad9361_init");

    return (struct ad9361_rf_phy *)ERR_PTR(ENODEV);
}
Exemple #3
0
/**
 * 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);

	hdl_dac_version = axiadc_read(st, 0x4000);

	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;
	}

	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);

					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;
				}
			}
			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);
				}
				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++) {
				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, 0x4044, 0x1);
				}
				else
					axiadc_write(st, 0x4414 + (chan) * 0x40, 1);

			}
			if (PCORE_VERSION_MAJOR(hdl_dac_version) < 8) {
				saved = tmp = axiadc_read(st, 0x4048);
				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);

			return err;
		}
	}

	return -EINVAL;
}