/**
* 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,<