예제 #1
0
static ssize_t axiadc_debugfs_pncheck_write(struct file *file,
		     const char __user *userbuf, size_t count, loff_t *ppos)
{
	struct iio_dev *indio_dev = file->private_data;
	struct axiadc_state *st = iio_priv(indio_dev);
	struct axiadc_converter *conv = to_converter(st->dev_spi);
	unsigned i, mode = TESTMODE_OFF;
	char buf[80], *p = buf;

	count = min_t(size_t, count, (sizeof(buf)-1));
	if (copy_from_user(p, userbuf, count))
		return -EFAULT;

	p[count] = 0;

	if (sysfs_streq(p, "PN9"))
		mode = TESTMODE_PN9_SEQ;
	else if (sysfs_streq(p, "PN23"))
		mode = TESTMODE_PN23_SEQ;
	else
		mode = TESTMODE_OFF;

	mutex_lock(&indio_dev->mlock);

	for (i = 0; i < conv->chip_info->num_channels; i++) {
		if (conv->testmode_set)
			conv->testmode_set(indio_dev, i, mode);

		axiadc_set_pnsel(st, i, (mode == TESTMODE_PN9_SEQ) ?
				ADC_PN9 : ADC_PN23A);
		axiadc_write(st, ADI_REG_CHAN_STATUS(i), ~0);
	}

	mdelay(1); /* FIXME */
	mutex_unlock(&indio_dev->mlock);

	return count;
}
예제 #2
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;
}