📄 rf.c
字号:
/** * Airgo MIMO wireless driver * * Copyright (c) 2007-2008 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); agnx_dbg("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 voidchannel_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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -