summaryrefslogblamecommitdiffstats
path: root/drivers/staging/agnx/rf.c
blob: 42e457a1844f84772d52e45e7bd3e8d79ccc8cb7 (plain) (tree)














































































































                                                                               



                                             
 
                                         












































































































































                                                                                     
                                                          

















                                                                   

                                                                          




































































































































































































































































































































































                                                                                  
                                                                                     















                                                        
                                          















                                                        
                     





























































































































































































































                                                                       
/**
 * Airgo MIMO wireless driver
 *
 * Copyright (c) 2007 Li YanBo <dreamfly281@gmail.com>

 * Thanks for Jeff Williams <angelbane@gmail.com> do reverse engineer
 * works and published the SPECS at http://airgo.wdwconsulting.net/mymoin

 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation;
 */

#include <linux/pci.h>
#include <linux/delay.h>
#include "agnx.h"
#include "debug.h"
#include "phy.h"
#include "table.h"

/* FIXME! */
static inline void spi_write(void __iomem *region, u32 chip_ids, u32 sw,
		      u16 size, u32 control)
{
	u32 reg;
	u32 lsw = sw & 0xffff;		/* lower 16 bits of sw*/
	u32 msw = sw >> 16;		/* high 16 bits of sw */

	/* FIXME Write Most Significant Word of the 32bit data to MSW */
	/* FIXME And Least Significant Word to LSW */
	iowrite32((lsw), region + AGNX_SPI_WLSW);
	iowrite32((msw), region + AGNX_SPI_WMSW);
	reg = chip_ids | size | control;
	/* Write chip id(s), write size and busy control to Control Register */
	iowrite32((reg), region + AGNX_SPI_CTL);
	/* Wait for Busy control to clear */
	spi_delay();
}

/*
 * Write to SPI Synth register
 */
static inline void spi_sy_write(void __iomem *region, u32 chip_ids, u32 sw)
{
	/* FIXME the size 0x15 is a magic value*/
	spi_write(region, chip_ids, sw, 0x15, SPI_BUSY_CTL);
}

/*
 * Write to SPI RF register
 */
static inline void spi_rf_write(void __iomem *region, u32 chip_ids, u32 sw)
{
	/* FIXME the size 0xd is a magic value*/
	spi_write(region, chip_ids, sw, 0xd, SPI_BUSY_CTL);
} /* spi_rf_write */

/*
 * Write to SPI with Read Control bit set
 */
inline void spi_rc_write(void __iomem *region, u32 chip_ids, u32 sw)
{
	/* FIXME the size 0xe5 is a magic value */
	spi_write(region, chip_ids, sw, 0xe5, SPI_BUSY_CTL|SPI_READ_CTL);
}

/* Get the active chains's count */
static int get_active_chains(struct agnx_priv *priv)
{
	void __iomem *ctl = priv->ctl;
	int num = 0;
	u32 reg;
	AGNX_TRACE;

	spi_rc_write(ctl, RF_CHIP0, 0x21);
	reg = agnx_read32(ctl, AGNX_SPI_RLSW);
	if (reg == 1)
		num++;

	spi_rc_write(ctl, RF_CHIP1, 0x21);
	reg = agnx_read32(ctl, AGNX_SPI_RLSW);
	if (reg == 1)
		num++;

	spi_rc_write(ctl, RF_CHIP2, 0x21);
	reg = agnx_read32(ctl, AGNX_SPI_RLSW);
	if (reg == 1)
		num++;

	spi_rc_write(ctl, RF_CHIP0, 0x26);
	reg = agnx_read32(ctl, AGNX_SPI_RLSW);
	if (0x33 != reg)
		printk(KERN_WARNING PFX "Unmatched rf chips result\n");

	return num;
} /* get_active_chains */

void rf_chips_init(struct agnx_priv *priv)
{
	void __iomem *ctl = priv->ctl;
	u32 reg;
	int num;
	AGNX_TRACE;

	if (priv->revid == 1) {
		reg = agnx_read32(ctl, AGNX_SYSITF_GPIOUT);
		reg |= 0x8;
		agnx_write32(ctl, AGNX_SYSITF_GPIOUT, reg);
	}

	/* Set SPI clock speed to 200NS */
	reg = agnx_read32(ctl, AGNX_SPI_CFG);
	reg &= ~0xF;
	reg |= 0x3;
	agnx_write32(ctl, AGNX_SPI_CFG, reg);

	/* Set SPI clock speed to 50NS */
	reg = agnx_read32(ctl, AGNX_SPI_CFG);
	reg &= ~0xF;
	reg |= 0x1;
	agnx_write32(ctl, AGNX_SPI_CFG, reg);

	spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1101);

	num = get_active_chains(priv);
	printk(KERN_INFO PFX "Active chains are %d\n", num);

	reg = agnx_read32(ctl, AGNX_SPI_CFG);
	reg &= ~0xF;
	agnx_write32(ctl, AGNX_SPI_CFG, reg);

	spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1908);
} /* rf_chips_init */


static u32 channel_tbl[15][9] = {
	{0,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
	{1,  0x00, 0x00, 0x624, 0x00, 0x1a4, 0x28, 0x00, 0x1e},
	{2,  0x00, 0x00, 0x615, 0x00, 0x1ae, 0x28, 0x00, 0x1e},
	{3,  0x00, 0x00, 0x61a, 0x00, 0x1ae, 0x28, 0x00, 0x1e},
	{4,  0x00, 0x00, 0x61f, 0x00, 0x1ae, 0x28, 0x00, 0x1e},
	{5,  0x00, 0x00, 0x624, 0x00, 0x1ae, 0x28, 0x00, 0x1e},
	{6,  0x00, 0x00, 0x61f, 0x00, 0x1b3, 0x28, 0x00, 0x1e},
	{7,  0x00, 0x00, 0x624, 0x00, 0x1b3, 0x28, 0x00, 0x1e},
	{8,  0x00, 0x00, 0x629, 0x00, 0x1b3, 0x28, 0x00, 0x1e},
	{9,  0x00, 0x00, 0x624, 0x00, 0x1b8, 0x28, 0x00, 0x1e},
	{10, 0x00, 0x00, 0x629, 0x00, 0x1b8, 0x28, 0x00, 0x1e},
	{11, 0x00, 0x00, 0x62e, 0x00, 0x1b8, 0x28, 0x00, 0x1e},
	{12, 0x00, 0x00, 0x633, 0x00, 0x1b8, 0x28, 0x00, 0x1e},
	{13, 0x00, 0x00, 0x628, 0x00, 0x1b8, 0x28, 0x00, 0x1e},
	{14, 0x00, 0x00, 0x644, 0x00, 0x1b8, 0x28, 0x00, 0x1e},
};


static inline void
channel_tbl_write(struct agnx_priv *priv, unsigned int channel, unsigned int reg_num)
{
	void __iomem *ctl = priv->ctl;
	u32 reg;

	reg = channel_tbl[channel][reg_num];
	reg <<= 4;
	reg |= reg_num;
	spi_sy_write(ctl, SYNTH_CHIP, reg);
}

static void synth_freq_set(struct agnx_priv *priv, unsigned int channel)
{
	void __iomem *ctl = priv->ctl;
	u32 reg;
	AGNX_TRACE;

	spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1201);

	/* Set the Clock bits to 50NS */
	reg = agnx_read32(ctl, AGNX_SPI_CFG);
	reg &= ~0xF;
	reg |= 0x1;
	agnx_write32(ctl, AGNX_SPI_CFG, reg);

	/* Write 0x00c0 to LSW and 0x3 to MSW of Synth Chip */
	spi_sy_write(ctl, SYNTH_CHIP, 0x300c0);

	spi_sy_write(ctl, SYNTH_CHIP, 0x32);

	/* # Write to Register 1 on the Synth Chip */
	channel_tbl_write(priv, channel, 1);
	/* # Write to Register 3 on the Synth Chip */
	channel_tbl_write(priv, channel, 3);
	/* # Write to Register 6 on the Synth Chip */
	channel_tbl_write(priv, channel, 6);
	/* # Write to Register 5 on the Synth Chip */
	channel_tbl_write(priv, channel, 5);
	/* # Write to register 8 on the Synth Chip */
	channel_tbl_write(priv, channel, 8);

	/* FIXME Clear the clock bits */
	reg = agnx_read32(ctl, AGNX_SPI_CFG);
	reg &= ~0xf;
	agnx_write32(ctl, AGNX_SPI_CFG, reg);
} /* synth_chip_init */


static void antenna_init(struct agnx_priv *priv, int num_antenna)
{
	void __iomem *ctl = priv->ctl;

	switch (num_antenna) {
	case 1:
		agnx_write32(ctl, AGNX_GCR_NLISTANT, 1);
		agnx_write32(ctl, AGNX_GCR_NMEASANT, 1);
		agnx_write32(ctl, AGNX_GCR_NACTIANT, 1);
		agnx_write32(ctl, AGNX_GCR_NCAPTANT, 1);

		agnx_write32(ctl, AGNX_GCR_ANTCFG, 7);
		agnx_write32(ctl, AGNX_GCR_BOACT, 34);
		agnx_write32(ctl, AGNX_GCR_BOINACT, 34);
		agnx_write32(ctl, AGNX_GCR_BODYNA, 30);

		agnx_write32(ctl, AGNX_GCR_THD0A, 125);
		agnx_write32(ctl, AGNX_GCR_THD0AL, 100);
		agnx_write32(ctl, AGNX_GCR_THD0B, 90);

		agnx_write32(ctl, AGNX_GCR_THD0BTFEST, 80);
		agnx_write32(ctl, AGNX_GCR_SIGHTH, 100);
		agnx_write32(ctl, AGNX_GCR_SIGLTH, 16);
		break;
	case 2:
		agnx_write32(ctl, AGNX_GCR_NLISTANT, 2);
		agnx_write32(ctl, AGNX_GCR_NMEASANT, 2);
		agnx_write32(ctl, AGNX_GCR_NACTIANT, 2);
		agnx_write32(ctl, AGNX_GCR_NCAPTANT, 2);
		agnx_write32(ctl, AGNX_GCR_ANTCFG, 15);
		agnx_write32(ctl, AGNX_GCR_BOACT, 36);
		agnx_write32(ctl, AGNX_GCR_BOINACT, 36);
		agnx_write32(ctl, AGNX_GCR_BODYNA, 32);
		agnx_write32(ctl, AGNX_GCR_THD0A, 120);
		agnx_write32(ctl, AGNX_GCR_THD0AL, 100);
		agnx_write32(ctl, AGNX_GCR_THD0B, 80);
		agnx_write32(ctl, AGNX_GCR_THD0BTFEST, 70);
		agnx_write32(ctl, AGNX_GCR_SIGHTH, 100);
		agnx_write32(ctl, AGNX_GCR_SIGLTH, 32);
		break;
	case 3:
		agnx_write32(ctl, AGNX_GCR_NLISTANT, 3);
		agnx_write32(ctl, AGNX_GCR_NMEASANT, 3);
		agnx_write32(ctl, AGNX_GCR_NACTIANT, 3);
		agnx_write32(ctl, AGNX_GCR_NCAPTANT, 3);
		agnx_write32(ctl, AGNX_GCR_ANTCFG, 31);
		agnx_write32(ctl, AGNX_GCR_BOACT, 36);
		agnx_write32(ctl, AGNX_GCR_BOINACT, 36);
		agnx_write32(ctl, AGNX_GCR_BODYNA, 32);
		agnx_write32(ctl, AGNX_GCR_THD0A, 100);
		agnx_write32(ctl, AGNX_GCR_THD0AL, 100);
		agnx_write32(ctl, AGNX_GCR_THD0B, 70);
		agnx_write32(ctl, AGNX_GCR_THD0BTFEST, 70);
		agnx_write32(ctl, AGNX_GCR_SIGHTH, 100);
		agnx_write32(ctl, AGNX_GCR_SIGLTH, 48);
/*		agnx_write32(ctl, AGNX_GCR_SIGLTH, 16); */
		break;
	default:
		printk(KERN_WARNING PFX "Unknow antenna number\n");
	}
} /* antenna_init */

static void chain_update(struct agnx_priv *priv, u32 chain)
{
	void __iomem *ctl = priv->ctl;
	u32 reg;
	AGNX_TRACE;

	spi_rc_write(ctl, RF_CHIP0, 0x20);
	reg = agnx_read32(ctl, AGNX_SPI_RLSW);

	if (reg == 0x4)
		spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, reg|0x1000);
	else if (reg != 0x0)
		spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, reg|0x1000);
	else {
		if (chain == 3 || chain == 6) {
			spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, reg|0x1000);
			agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0);
		} else if (chain == 2 || chain == 4) {
			spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, reg|0x1000);
			spi_rf_write(ctl, RF_CHIP2, 0x1005);
			agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x824);
		} else if (chain == 1) {
			spi_rf_write(ctl, RF_CHIP0, reg|0x1000);
			spi_rf_write(ctl, RF_CHIP1|RF_CHIP2, 0x1004);
			agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0xc36);
		}
	}

	spi_rc_write(ctl, RF_CHIP0, 0x22);
	reg = agnx_read32(ctl, AGNX_SPI_RLSW);

	switch (reg) {
	case 0:
		spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1005);
		break;
	case 1:
		spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1201);
		break;
	case 2:
		if (chain == 6 || chain == 4) {
			spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1202);
			spi_rf_write(ctl, RF_CHIP2, 0x1005);
		} else if (chain < 3) {
			spi_rf_write(ctl, RF_CHIP0, 0x1202);
			spi_rf_write(ctl, RF_CHIP1|RF_CHIP2, 0x1005);
		}
		break;
	default:
		if (chain == 3) {
			spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1203);
			spi_rf_write(ctl, RF_CHIP2, 0x1201);
		} else if (chain == 2) {
			spi_rf_write(ctl, RF_CHIP0, 0x1203);
			spi_rf_write(ctl, RF_CHIP2, 0x1200);
			spi_rf_write(ctl, RF_CHIP1, 0x1201);
		} else if (chain == 1) {
			spi_rf_write(ctl, RF_CHIP0, 0x1203);
			spi_rf_write(ctl, RF_CHIP1|RF_CHIP2, 0x1200);
		} else if (chain == 4) {
			spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1203);
			spi_rf_write(ctl, RF_CHIP2, 0x1201);
		} else {
			spi_rf_write(ctl, RF_CHIP0, 0x1203);
			spi_rf_write(ctl, RF_CHIP1|RF_CHIP2, 0x1201);
		}
	}
} /* chain_update */

static void antenna_config(struct agnx_priv *priv)
{
	void __iomem *ctl = priv->ctl;
	u32 reg;
	AGNX_TRACE;

	/* Write 0x0 to the TX Management Control Register Enable bit */
	reg = agnx_read32(ctl, AGNX_TXM_CTL);
	reg &= ~0x1;
	agnx_write32(ctl, AGNX_TXM_CTL, reg);

	/* FIXME */
	/* Set initial value based on number of Antennae */
	antenna_init(priv, 3);

	/* FIXME Update Power Templates for current valid Stations */
	/* sta_power_init(priv, 0);*/

	/* FIXME the number of chains should get from eeprom*/
	chain_update(priv, AGNX_CHAINS_MAX);
} /* antenna_config */

void calibrate_oscillator(struct agnx_priv *priv)
{
	void __iomem *ctl = priv->ctl;
	u32 reg;
	AGNX_TRACE;

	spi_rc_write(ctl, RF_CHIP0|RF_CHIP1, 0x1201);
	reg = agnx_read32(ctl, AGNX_GCR_GAINSET1);
	reg |= 0x10;
	agnx_write32(ctl, AGNX_GCR_GAINSET1, reg);

	agnx_write32(ctl, AGNX_GCR_GAINSETWRITE, 1);
	agnx_write32(ctl, AGNX_GCR_RSTGCTL, 1);

	agnx_write32(ctl, AGNX_ACI_LEN, 0x3ff);

	agnx_write32(ctl, AGNX_ACI_TIMER1, 0x27);
	agnx_write32(ctl, AGNX_ACI_TIMER2, 0x27);
	/* (Residual DC Calibration) to Calibration Mode */
	agnx_write32(ctl, AGNX_ACI_MODE, 0x2);

	spi_rc_write(ctl, RF_CHIP0|RF_CHIP1, 0x1004);
	agnx_write32(ctl, AGNX_ACI_LEN, 0x3ff);
	/* (TX LO Calibration) to Calibration Mode */
	agnx_write32(ctl, AGNX_ACI_MODE, 0x4);

	do {
		u32  reg1, reg2, reg3;
		/* Enable Power Saving Control */
		enable_power_saving(priv);
		/* Save the following registers to restore */
		reg1 = ioread32(ctl + 0x11000);
		reg2 = ioread32(ctl + 0xec50);
		reg3 = ioread32(ctl + 0xec54);
		wmb();

		agnx_write32(ctl, 0x11000, 0xcfdf);
		agnx_write32(ctl, 0xec50, 0x70);
		/* Restore the registers */
		agnx_write32(ctl, 0x11000, reg1);
		agnx_write32(ctl, 0xec50, reg2);
		agnx_write32(ctl, 0xec54, reg3);
		/* Disable Power Saving Control */
		disable_power_saving(priv);
	} while (0);

	agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0);
} /* calibrate_oscillator */


static void radio_channel_set(struct agnx_priv *priv, unsigned int channel)
{
	void __iomem *ctl = priv->ctl;
	unsigned int freq = priv->band.channels[channel - 1].center_freq;
	u32 reg;
	AGNX_TRACE;

	spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1201);
	/* Set SPI Clock to 50 Ns */
	reg = agnx_read32(ctl, AGNX_SPI_CFG);
	reg &= ~0xF;
	reg |= 0x1;
	agnx_write32(ctl, AGNX_SPI_CFG, reg);

	/* Clear the Disable Tx interrupt bit in Interrupt Mask */
/* 	reg = agnx_read32(ctl, AGNX_INT_MASK); */
/* 	reg &= ~IRQ_TX_DISABLE; */
/* 	agnx_write32(ctl, AGNX_INT_MASK, reg); */

	/* Band Selection */
	reg = agnx_read32(ctl, AGNX_SYSITF_GPIOUT);
	reg |= 0x8;
	agnx_write32(ctl, AGNX_SYSITF_GPIOUT, reg);

	/* FIXME Set the SiLabs Chip Frequency */
	synth_freq_set(priv, channel);

	reg = agnx_read32(ctl, AGNX_PM_SOFTRST);
	reg |= 0x80100030;
	agnx_write32(ctl, AGNX_PM_SOFTRST, reg);
	reg = agnx_read32(ctl, AGNX_PM_PLLCTL);
	reg |= 0x20009;
	agnx_write32(ctl, AGNX_PM_PLLCTL, reg);

	agnx_write32(ctl, AGNX_SYSITF_GPIOUT, 0x5);

	spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1100);

	/* Load the MonitorGain Table */
	monitor_gain_table_init(priv);

	/* Load the TX Fir table */
	tx_fir_table_init(priv);

	reg = agnx_read32(ctl, AGNX_PM_PMCTL);
	reg |= 0x8;
	agnx_write32(ctl, AGNX_PM_PMCTL, reg);

	spi_rc_write(ctl, RF_CHIP0|RF_CHIP1, 0x22);
	udelay(80);
	reg = agnx_read32(ctl, AGNX_SPI_RLSW);


	agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0xff);
	agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x3);

	reg = agnx_read32(ctl, 0xec50);
	reg |= 0x4f;
	agnx_write32(ctl, 0xec50, reg);

	spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1201);
	agnx_write32(ctl, 0x11008, 0x1);
	agnx_write32(ctl, 0x1100c, 0x0);
	agnx_write32(ctl, 0x11008, 0x0);
	agnx_write32(ctl, 0xec50, 0xc);

	agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x3);
	agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0);
	agnx_write32(ctl, 0x11010, 0x6e);
	agnx_write32(ctl, 0x11014, 0x6c);

	spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1201);

	/* Calibrate the Antenna */
	/* antenna_calibrate(priv); */
	/* Calibrate the TxLocalOscillator */
	calibrate_oscillator(priv);

	reg = agnx_read32(ctl, AGNX_PM_PMCTL);
	reg &= ~0x8;
	agnx_write32(ctl, AGNX_PM_PMCTL, reg);
	agnx_write32(ctl, AGNX_GCR_GAININIT, 0xa);
	agnx_write32(ctl, AGNX_GCR_THCD, 0x0);

	agnx_write32(ctl, 0x11018, 0xb);
	agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x0);

	/* Write Frequency to Gain Control Channel */
	agnx_write32(ctl, AGNX_GCR_RXCHANEL, freq);
	/* Write 0x140000/Freq to 0x9c08 */
	reg = 0x140000/freq;
	agnx_write32(ctl, 0x9c08, reg);

	reg = agnx_read32(ctl, AGNX_PM_SOFTRST);
	reg &= ~0x80100030;
	agnx_write32(ctl, AGNX_PM_SOFTRST, reg);

	reg = agnx_read32(ctl, AGNX_PM_PLLCTL);
	reg &= ~0x20009;
	reg |= 0x1;
	agnx_write32(ctl, AGNX_PM_PLLCTL, reg);

	agnx_write32(ctl, AGNX_ACI_MODE, 0x0);

/* FIXME According to Number of Chains: */

/* 			   1. 1: */
/*          1. Write 0x1203 to RF Chip 0 */
/*          2. Write 0x1200 to RF Chips 1 +2  */
/* 			   2. 2: */
/*          1. Write 0x1203 to RF Chip 0 */
/*          2. Write 0x1200 to RF Chip 2 */
/*          3. Write 0x1201 to RF Chip 1  */
/* 			   3. 3: */
/*          1. Write 0x1203 to RF Chip 0 */
/*          2. Write 0x1201 to RF Chip 1 + 2  */
/* 			   4. 4: */
/*          1. Write 0x1203 to RF Chip 0 + 1 */
/*          2. Write 0x1200 to RF Chip 2  */

/* 			   5. 6: */
	spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1203);
	spi_rf_write(ctl, RF_CHIP2, 0x1201);

	spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1000);
	agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0);

	/* FIXME Set the Disable Tx interrupt bit in Interrupt Mask
	   (Or 0x20000 to Interrupt Mask) */
/* 	reg = agnx_read32(ctl, AGNX_INT_MASK); */
/* 	reg |= IRQ_TX_DISABLE; */
/* 	agnx_write32(ctl, AGNX_INT_MASK, reg); */

	agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x1);
	agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x0);

	/* Configure the Antenna */
	antenna_config(priv);

	/* Write 0x0 to Discovery Mode Enable detect G, B, A packet? */
	agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0);

	reg = agnx_read32(ctl, AGNX_RXM_REQRATE);
	reg |= 0x80000000;
	agnx_write32(ctl, AGNX_RXM_REQRATE, reg);
	agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x1);
	agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x0);

	/* enable radio on and the power LED */
	reg = agnx_read32(ctl, AGNX_SYSITF_GPIOUT);
	reg &= ~0x1;
	reg |= 0x2;
	agnx_write32(ctl, AGNX_SYSITF_GPIOUT, reg);

	reg = agnx_read32(ctl, AGNX_TXM_CTL);
	reg |= 0x1;
	agnx_write32(ctl, AGNX_TXM_CTL, reg);
} /* radio_channel_set */

static void base_band_filter_calibrate(struct agnx_priv *priv)
{
	void __iomem *ctl = priv->ctl;

	spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1700);
	spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1001);
	agnx_write32(ctl, AGNX_GCR_FORCECTLCLK, 0x0);
	spi_rc_write(ctl, RF_CHIP0, 0x27);
	spi_rc_write(ctl, RF_CHIP1, 0x27);
	spi_rc_write(ctl, RF_CHIP2, 0x27);
	agnx_write32(ctl, AGNX_GCR_FORCECTLCLK, 0x1);
}

static void print_offset(struct agnx_priv *priv, u32 chain)
{
	void __iomem *ctl = priv->ctl;
	u32 offset;

	iowrite32((chain), ctl + AGNX_ACI_SELCHAIN);
	udelay(10);
	offset = (ioread32(ctl + AGNX_ACI_OFFSET));
	printk(PFX "Chain is 0x%x, Offset is 0x%x\n", chain, offset);
}

void print_offsets(struct agnx_priv *priv)
{
	print_offset(priv, 0);
	print_offset(priv, 4);
	print_offset(priv, 1);
	print_offset(priv, 5);
	print_offset(priv, 2);
	print_offset(priv, 6);
}


struct chains {
	u32 cali;		/* calibrate  value*/

#define  NEED_CALIBRATE		0
#define  SUCCESS_CALIBRATE	1
	int status;
};

static void chain_calibrate(struct agnx_priv *priv, struct chains *chains,
			    unsigned int num)
{
	void __iomem *ctl = priv->ctl;
	u32 calibra = chains[num].cali;

	if (num < 3)
		calibra |= 0x1400;
	else
		calibra |= 0x1500;

	switch (num) {
	case 0:
	case 4:
		spi_rf_write(ctl, RF_CHIP0, calibra);
		break;
	case 1:
	case 5:
		spi_rf_write(ctl, RF_CHIP1, calibra);
		break;
	case 2:
	case 6:
		spi_rf_write(ctl, RF_CHIP2, calibra);
		break;
	default:
		BUG();
	}
} /* chain_calibrate */

static inline void get_calibrete_value(struct agnx_priv *priv, struct chains *chains,
				       unsigned int num)
{
	void __iomem *ctl = priv->ctl;
	u32 offset;

	iowrite32((num), ctl + AGNX_ACI_SELCHAIN);
	/* FIXME */
	udelay(10);
	offset = (ioread32(ctl + AGNX_ACI_OFFSET));

	if (offset < 0xf) {
		chains[num].status = SUCCESS_CALIBRATE;
		return;
	}

	if (num == 0 || num == 1 || num == 2) {
		if (0 == chains[num].cali)
			chains[num].cali = 0xff;
		else
			chains[num].cali--;
	} else
		chains[num].cali++;

	chains[num].status = NEED_CALIBRATE;
}

static inline void calibra_delay(struct agnx_priv *priv)
{
	void __iomem *ctl = priv->ctl;
	u32 reg;
	unsigned int i = 100;

	wmb();
	while (--i) {
		reg = (ioread32(ctl + AGNX_ACI_STATUS));
		if (reg == 0x4000)
			break;
		udelay(10);
	}
	if (!i)
		printk(PFX "calibration failed\n");
}

void do_calibration(struct agnx_priv *priv)
{
	void __iomem *ctl = priv->ctl;
	struct chains chains[7];
	unsigned int i, j;
	AGNX_TRACE;

	for (i = 0; i < 7; i++) {
		if (i == 3)
			continue;

		chains[i].cali = 0x7f;
		chains[i].status = NEED_CALIBRATE;
	}

	/* FIXME 0x300 is a magic number */
	for (j = 0; j < 0x300; j++) {
		if (chains[0].status == SUCCESS_CALIBRATE &&
		    chains[1].status == SUCCESS_CALIBRATE &&
		    chains[2].status == SUCCESS_CALIBRATE &&
		    chains[4].status == SUCCESS_CALIBRATE &&
		    chains[5].status == SUCCESS_CALIBRATE &&
		    chains[6].status == SUCCESS_CALIBRATE)
			break;

		/* Attention, there is no chain 3 */
		for (i = 0; i < 7; i++) {
			if (i == 3)
				continue;
			if (chains[i].status == NEED_CALIBRATE)
				chain_calibrate(priv, chains, i);
		}
		/* Write 0x1 to Calibration Measure */
		iowrite32((0x1), ctl + AGNX_ACI_MEASURE);
		calibra_delay(priv);

		for (i = 0; i < 7; i++) {
			if (i == 3)
				continue;

			get_calibrete_value(priv, chains, i);
		}
	}
	printk(PFX "Clibrate times is %d\n", j);
	print_offsets(priv);
} /* do_calibration */

void antenna_calibrate(struct agnx_priv *priv)
{
	void __iomem *ctl = priv->ctl;
	u32 reg;
	AGNX_TRACE;

	agnx_write32(ctl, AGNX_GCR_NLISTANT, 0x3);
	agnx_write32(ctl, AGNX_GCR_NMEASANT, 0x3);
	agnx_write32(ctl, AGNX_GCR_NACTIANT, 0x3);
	agnx_write32(ctl, AGNX_GCR_NCAPTANT, 0x3);

	agnx_write32(ctl, AGNX_GCR_ANTCFG, 0x1f);
	agnx_write32(ctl, AGNX_GCR_BOACT, 0x24);
	agnx_write32(ctl, AGNX_GCR_BOINACT, 0x24);
	agnx_write32(ctl, AGNX_GCR_BODYNA, 0x20);
	agnx_write32(ctl, AGNX_GCR_THD0A, 0x64);
	agnx_write32(ctl, AGNX_GCR_THD0AL, 0x64);
	agnx_write32(ctl, AGNX_GCR_THD0B, 0x46);
	agnx_write32(ctl, AGNX_GCR_THD0BTFEST, 0x3c);
	agnx_write32(ctl, AGNX_GCR_SIGHTH, 0x64);
	agnx_write32(ctl, AGNX_GCR_SIGLTH, 0x30);

	spi_rc_write(ctl, RF_CHIP0, 0x20);
	/* Fixme */
	udelay(80);
	/*    1. Should read 0x0  */
	reg = agnx_read32(ctl, AGNX_SPI_RLSW);
	if (0x0 != reg)
		printk(KERN_WARNING PFX "Unmatched rf chips result\n");
	spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1000);

	agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0);

	spi_rc_write(ctl, RF_CHIP0, 0x22);
	udelay(80);
	reg = agnx_read32(ctl, AGNX_SPI_RLSW);
	if (0x0 != reg)
		printk(KERN_WARNING PFX "Unmatched rf chips result\n");
	spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1005);

	agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x1);
	agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x0);

	reg = agnx_read32(ctl, AGNX_PM_SOFTRST);
	reg |= 0x1c000032;
	agnx_write32(ctl, AGNX_PM_SOFTRST, reg);
	reg = agnx_read32(ctl, AGNX_PM_PLLCTL);
	reg |= 0x0003f07;
	agnx_write32(ctl, AGNX_PM_PLLCTL, reg);

	reg = agnx_read32(ctl, 0xec50);
	reg |= 0x40;
	agnx_write32(ctl, 0xec50, reg);

	agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0xff8);
	agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x3);

	agnx_write32(ctl, AGNX_GCR_CHAINNUM, 0x6);
	agnx_write32(ctl, 0x19874, 0x0);
	spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1700);

	/* Calibrate the BaseBandFilter */
	base_band_filter_calibrate(priv);

	spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1002);

	agnx_write32(ctl, AGNX_GCR_GAINSET0, 0x1d);
	agnx_write32(ctl, AGNX_GCR_GAINSET1, 0x1d);
	agnx_write32(ctl, AGNX_GCR_GAINSET2, 0x1d);
	agnx_write32(ctl, AGNX_GCR_GAINSETWRITE, 0x1);

	agnx_write32(ctl, AGNX_ACI_MODE, 0x1);
	agnx_write32(ctl, AGNX_ACI_LEN, 0x3ff);

	agnx_write32(ctl, AGNX_ACI_TIMER1, 0x27);
	agnx_write32(ctl, AGNX_ACI_TIMER2, 0x27);

	spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1400);
	spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1500);

	/* Measure Calibration */
	agnx_write32(ctl, AGNX_ACI_MEASURE, 0x1);
	calibra_delay(priv);

	/* do calibration */
	do_calibration(priv);

	agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0);
	agnx_write32(ctl, AGNX_ACI_TIMER1, 0x21);
	agnx_write32(ctl, AGNX_ACI_TIMER2, 0x27);
	agnx_write32(ctl, AGNX_ACI_LEN, 0xf);

	reg = agnx_read32(ctl, AGNX_GCR_GAINSET0);
	reg &= 0xf;
	agnx_write32(ctl, AGNX_GCR_GAINSET0, reg);
	reg = agnx_read32(ctl, AGNX_GCR_GAINSET1);
	reg &= 0xf;
	agnx_write32(ctl, AGNX_GCR_GAINSET1, reg);
	reg = agnx_read32(ctl, AGNX_GCR_GAINSET2);
	reg &= 0xf;
	agnx_write32(ctl, AGNX_GCR_GAINSET2, reg);

	agnx_write32(ctl, AGNX_GCR_GAINSETWRITE, 0x0);
	disable_receiver(priv);
} /* antenna_calibrate */

void __antenna_calibrate(struct agnx_priv *priv)
{
	void __iomem *ctl = priv->ctl;
	u32 reg;

	/* Calibrate the BaseBandFilter */
	/* base_band_filter_calibrate(priv); */
	spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1002);


	agnx_write32(ctl, AGNX_GCR_GAINSET0, 0x1d);
	agnx_write32(ctl, AGNX_GCR_GAINSET1, 0x1d);
	agnx_write32(ctl, AGNX_GCR_GAINSET2, 0x1d);

	agnx_write32(ctl, AGNX_GCR_GAINSETWRITE, 0x1);

	agnx_write32(ctl, AGNX_ACI_MODE, 0x1);
	agnx_write32(ctl, AGNX_ACI_LEN, 0x3ff);


	agnx_write32(ctl, AGNX_ACI_TIMER1, 0x27);
	agnx_write32(ctl, AGNX_ACI_TIMER2, 0x27);
	spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1400);
	spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1500);
	/* Measure Calibration */
	agnx_write32(ctl, AGNX_ACI_MEASURE, 0x1);
	calibra_delay(priv);
	do_calibration(priv);
	agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0);

	agnx_write32(ctl, AGNX_ACI_TIMER1, 0x21);
	agnx_write32(ctl, AGNX_ACI_TIMER2, 0x27);

	agnx_write32(ctl, AGNX_ACI_LEN, 0xf);

	reg = agnx_read32(ctl, AGNX_GCR_GAINSET0);
	reg &= 0xf;
	agnx_write32(ctl, AGNX_GCR_GAINSET0, reg);
	reg = agnx_read32(ctl, AGNX_GCR_GAINSET1);
	reg &= 0xf;
	agnx_write32(ctl, AGNX_GCR_GAINSET1, reg);
	reg = agnx_read32(ctl, AGNX_GCR_GAINSET2);
	reg &= 0xf;
	agnx_write32(ctl, AGNX_GCR_GAINSET2, reg);


	agnx_write32(ctl, AGNX_GCR_GAINSETWRITE, 0x0);

	/* Write 0x3 Gain Control Discovery Mode */
	enable_receiver(priv);
}

int agnx_set_channel(struct agnx_priv *priv, unsigned int channel)
{
	AGNX_TRACE;

	printk(KERN_ERR PFX "Channel is %d %s\n", channel, __func__);
	radio_channel_set(priv, channel);
	return 0;
}