#include <stdio.h>
#include "ad9208.h"
#include "spi.h"

struct reg_t ad9208_configuration[] = {
		/* Control bits 0 and 1 */
		{AD_OUT_MODE_CTRL_1_REG			, 0x10},
		/* Control bit 2 */
		{AD_OUT_MODE_CTRL_2_REG			, 0x01},
		/* F = 1 */
		{AD_OCT_PER_FRAME_REG			, 0x00},
		/* K = 32 */
		{AD_FRAMES_PER_MULTFRAME_REG	, 0x1F},
		/* M = 2 */
		{AD_NUM_OF_CONVERTERS_REG		, 0x01},
		/* CS = 2 & N = 14 */
		{AD_CTRL_BITS_RES_REG			, 0x8D},
		/* SUBCLASS = 0 & N' = 16 */
		{AD_CLASS_SAMPE_BITS_REG		, 0x0F},
		/* Disable scrambling & L = 8 */
		{AD_SCR_LANE_NUM_REG			, 0x07},
		/* Disable frame alignment character insertion */
		{AD_LINK_CTRL_1_REG				, 0x06},
		/* Full scale and real + complex */
		{0x0200							, 0x00},
		/* Don't use two's complement */
		{0x0561							, 0x00},
		/* DC offset calibration */
		{0x0701							, 0x06},
		/* Lane rate 0x00 under 13.5 Gbps / 0x30 over 13.5 Gbps */
		{AD_PLL_CTRL_REG				, 0x30},
};


struct reg_t ad9208_test_pattern[] = {
		{AD_USER_PATTERN_1_LSB_REG		, 0x00},
		{AD_USER_PATTERN_1_MSB_REG		, 0x01},
		{AD_USER_PATTERN_2_LSB_REG		, 0x00},
		{AD_USER_PATTERN_2_MSB_REG		, 0x02},
		{AD_USER_PATTERN_3_LSB_REG		, 0x00},
		{AD_USER_PATTERN_3_MSB_REG		, 0x04},
		{AD_USER_PATTERN_4_LSB_REG		, 0x00},
		{AD_USER_PATTERN_4_MSB_REG		, 0x08},
};

int adc_after_reset_init(XSpi *spi)
{
	/* Reset JESD204B start-up circuit */
	if(spi_write_reg(spi, AD_PLL_STARTUP_REG, 0x4F)){
		xil_printf("%s unable write to register %04x\n\r", __func__, AD_PLL_STARTUP_REG);
		return 1;
	}

	/* JESD204B start-up circuit normal operation */
	if(spi_write_reg(spi, AD_PLL_STARTUP_REG, 0x0F)){
		xil_printf("%s unable write to register %04x\n\r", __func__, AD_PLL_STARTUP_REG);
		return 1;
	}

	/* PLL force normal operation */
	if(spi_write_reg(spi, AD_PLL_CALIB_REG, 0x00)){
		xil_printf("%s unable write to register %04x\n\r", __func__, AD_PLL_CALIB_REG);
		return 1;
	}

	/* Reset PLL calibration */
	if(spi_write_reg(spi, AD_PLL_CALIB_REG, 0x04)){
		xil_printf("%s unable write to register %04x\n\r", __func__, AD_PLL_CALIB_REG);
		return 1;
	}

	/* JESD204B PLL normal operation */
	if(spi_write_reg(spi, AD_PLL_CALIB_REG, 0x00)){
		xil_printf("%s unable write to register %04x\n\r", __func__, AD_PLL_CALIB_REG);
		return 1;
	}

	/* Clear loss of lock */
	if(spi_write_reg(spi, AD_PLL_LOSS_CTRL_REG, 0x08)){
		xil_printf("%s unable write to register %04x\n\r", __func__, AD_PLL_LOSS_CTRL_REG);
		return 1;
	}

	/* Loss of lock normal operation */
	if(spi_write_reg(spi, AD_PLL_LOSS_CTRL_REG, 0x00)){
		xil_printf("%s unable write to register %04x\n\r", __func__, AD_PLL_LOSS_CTRL_REG);
		return 1;
	}

	return 0;
}

int adc_write_conf(XSpi *spi)
{
	if(spi_write_conf(spi, ad9208_configuration, sizeof(ad9208_configuration)/sizeof(*ad9208_configuration)))
		return 1;

	if(spi_compare_conf(spi, ad9208_configuration, sizeof(ad9208_configuration)/sizeof(*ad9208_configuration)))
		return 1;

	return 0;
}

int adc_get_chip_vendor_id(XSpi *spi, uint16_t *chip_id, uint16_t *vendor_id)
{
	uint8_t val;

	*chip_id = 0;
	*vendor_id = 0;

	/* Get Chip ID */
	if(spi_rw_reg(spi, AD_SPI_CHIP_ID_LSB_REG, &val, 0)){
		xil_printf("ADC SPI read failed\n\r");
		return 1;
	}

	*chip_id = (uint16_t)val;

	if(spi_rw_reg(spi, AD_SPI_CHIP_ID_MSB_REG, &val, 0)){
		xil_printf("ADC SPI read failed\n\r");
		return 1;
	}

	*chip_id |= (uint16_t)(val << 8);

	/* Get Vendor ID */
	if(spi_rw_reg(spi, AD_SPI_VENDOR_ID_LSB_REG, &val, 0)){
		xil_printf("ADC SPI read failed\n\r");
		return 1;
	}

	*vendor_id = (uint16_t)val;

	if(spi_rw_reg(spi, AD_SPI_VENDOR_ID_MSB_REG, &val, 0)){
		xil_printf("ADC SPI read failed\n\r");
		return 1;
	}

	*vendor_id |= (uint16_t)(val << 8);

	return 0;
}


int adc_write_user_test_pattern(XSpi *spi)
{
	if(spi_write_conf(spi, ad9208_test_pattern, sizeof(ad9208_test_pattern)/sizeof(*ad9208_test_pattern)))
		return 1;

	if(spi_compare_conf(spi, ad9208_test_pattern, sizeof(ad9208_test_pattern)/sizeof(*ad9208_test_pattern)))
		return 1;

	return 0;
}
