openwrt-owl/target/linux/amazon/files/drivers/net/ethernet/admmod.c

1494 lines
40 KiB
C

/******************************************************************************
Copyright (c) 2004, Infineon Technologies. All rights reserved.
No Warranty
Because the program is licensed free of charge, there is no warranty for
the program, to the extent permitted by applicable law. Except when
otherwise stated in writing the copyright holders and/or other parties
provide the program "as is" without warranty of any kind, either
expressed or implied, including, but not limited to, the implied
warranties of merchantability and fitness for a particular purpose. The
entire risk as to the quality and performance of the program is with
you. should the program prove defective, you assume the cost of all
necessary servicing, repair or correction.
In no event unless required by applicable law or agreed to in writing
will any copyright holder, or any other party who may modify and/or
redistribute the program as permitted above, be liable to you for
damages, including any general, special, incidental or consequential
damages arising out of the use or inability to use the program
(including but not limited to loss of data or data being rendered
inaccurate or losses sustained by you or third parties or a failure of
the program to operate with any other programs), even if such holder or
other party has been advised of the possibility of such damages.
******************************************************************************
Module : admmod.c
Date : 2004-09-01
Description : JoeLin
Remarks:
Revision:
MarsLin, add to support VLAN
*****************************************************************************/
//000001.joelin 2005/06/02 add"ADM6996_MDC_MDIO_MODE" define,
// if define ADM6996_MDC_MDIO_MODE==> ADM6996LC and ADM6996I will be in MDIO/MDC(SMI)(16 bit) mode,
// amazon should contrl ADM6996 by MDC/MDIO pin
// if undef ADM6996_MDC_MDIO_MODE==> ADM6996 will be in EEProm(32 bit) mode,
// amazon should contrl ADM6996 by GPIO15,16,17,18 pin
/* 507281:linmars 2005/07/28 support MDIO/EEPROM config mode */
/* 509201:linmars remove driver testing codes */
#include <linux/version.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/init.h>
#include <linux/ioctl.h>
#include <asm/atomic.h>
#include <asm-mips/amazon/amazon.h>
#include <asm-mips/amazon/adm6996.h>
//#include <linux/amazon/adm6996.h>
unsigned int ifx_sw_conf[ADM_SW_MAX_PORT_NUM+1] = \
{ADM_SW_PORT0_CONF, ADM_SW_PORT1_CONF, ADM_SW_PORT2_CONF, \
ADM_SW_PORT3_CONF, ADM_SW_PORT4_CONF, ADM_SW_PORT5_CONF};
unsigned int ifx_sw_bits[8] = \
{0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff};
unsigned int ifx_sw_vlan_port[6] = {0, 2, 4, 6, 7, 8};
//050613:fchang
/* 507281:linmars start */
#ifdef CONFIG_SWITCH_ADM6996_MDIO
#define ADM6996_MDC_MDIO_MODE 1 //000001.joelin
#else
#undef ADM6996_MDC_MDIO_MODE
#endif
/* 507281:linmars end */
#define adm6996i 0
#define adm6996lc 1
#define adm6996l 2
unsigned int adm6996_mode=adm6996i;
/*
initialize GPIO pins.
output mode, low
*/
void ifx_gpio_init(void)
{
//GPIO16,17,18 direction:output
//GPIO16,17,18 output 0
AMAZON_SW_REG(AMAZON_GPIO_P1_DIR) |= (GPIO_MDIO|GPIO_MDCS|GPIO_MDC);
AMAZON_SW_REG(AMAZON_GPIO_P1_OUT) =AMAZON_SW_REG(AMAZON_GPIO_P1_IN)& ~(GPIO_MDIO|GPIO_MDCS|GPIO_MDC);
}
/* read one bit from mdio port */
int ifx_sw_mdio_readbit(void)
{
//int val;
//val = (AMAZON_SW_REG(GPIO_conf0_REG) & GPIO0_INPUT_MASK) >> 8;
//return val;
//GPIO16
return AMAZON_SW_REG(AMAZON_GPIO_P1_IN)&1;
}
/*
MDIO mode selection
1 -> output
0 -> input
switch input/output mode of GPIO 0
*/
void ifx_mdio_mode(int mode)
{
// AMAZON_SW_REG(GPIO_conf0_REG) = mode ? GPIO_ENABLEBITS :
// ((GPIO_ENABLEBITS | MDIO_INPUT) & ~MDIO_OUTPUT_EN);
mode?(AMAZON_SW_REG(AMAZON_GPIO_P1_DIR)|=GPIO_MDIO):
(AMAZON_SW_REG(AMAZON_GPIO_P1_DIR)&=~GPIO_MDIO);
/*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_DIR);
mode?(r|=GPIO_MDIO):(r&=~GPIO_MDIO);
AMAZON_SW_REG(AMAZON_GPIO_P1_DIR)=r;*/
}
void ifx_mdc_hi(void)
{
//GPIO_SET_HI(GPIO_MDC);
//AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)|=GPIO_MDC;
/*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT);
r|=GPIO_MDC;
AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/
AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)|GPIO_MDC;
}
void ifx_mdio_hi(void)
{
//GPIO_SET_HI(GPIO_MDIO);
//AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)|=GPIO_MDIO;
/*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT);
r|=GPIO_MDIO;
AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/
AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)|GPIO_MDIO;
}
void ifx_mdcs_hi(void)
{
//GPIO_SET_HI(GPIO_MDCS);
//AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)|=GPIO_MDCS;
/*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT);
r|=GPIO_MDCS;
AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/
AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)|GPIO_MDCS;
}
void ifx_mdc_lo(void)
{
//GPIO_SET_LOW(GPIO_MDC);
//AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)&=~GPIO_MDC;
/*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT);
r&=~GPIO_MDC;
AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/
AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)&(~GPIO_MDC);
}
void ifx_mdio_lo(void)
{
//GPIO_SET_LOW(GPIO_MDIO);
//AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)&=~GPIO_MDIO;
/*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT);
r&=~GPIO_MDIO;
AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/
AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)&(~GPIO_MDIO);
}
void ifx_mdcs_lo(void)
{
//GPIO_SET_LOW(GPIO_MDCS);
//AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)&=~GPIO_MDCS;
/*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT);
r&=~GPIO_MDCS;
AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/
AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)&(~GPIO_MDCS);
}
/*
mdc pulse
0 -> 1 -> 0
*/
static void ifx_sw_mdc_pulse(void)
{
ifx_mdc_lo();
udelay(ADM_SW_MDC_DOWN_DELAY);
ifx_mdc_hi();
udelay(ADM_SW_MDC_UP_DELAY);
ifx_mdc_lo();
}
/*
mdc toggle
1 -> 0
*/
static void ifx_sw_mdc_toggle(void)
{
ifx_mdc_hi();
udelay(ADM_SW_MDC_UP_DELAY);
ifx_mdc_lo();
udelay(ADM_SW_MDC_DOWN_DELAY);
}
/*
enable eeprom write
For ATC 93C66 type EEPROM; accessing ADM6996 internal EEPROM type registers
*/
static void ifx_sw_eeprom_write_enable(void)
{
unsigned int op;
ifx_mdcs_lo();
ifx_mdc_lo();
ifx_mdio_hi();
udelay(ADM_SW_CS_DELAY);
/* enable chip select */
ifx_mdcs_hi();
udelay(ADM_SW_CS_DELAY);
/* start bit */
ifx_mdio_hi();
ifx_sw_mdc_pulse();
/* eeprom write enable */
op = ADM_SW_BIT_MASK_4;
while (op)
{
if (op & ADM_SW_EEPROM_WRITE_ENABLE)
ifx_mdio_hi();
else
ifx_mdio_lo();
ifx_sw_mdc_pulse();
op >>= 1;
}
op = ADM_SW_BIT_MASK_1 << (EEPROM_TYPE - 3);
while (op)
{
ifx_mdio_lo();
ifx_sw_mdc_pulse();
op >>= 1;
}
/* disable chip select */
ifx_mdcs_lo();
udelay(ADM_SW_CS_DELAY);
ifx_sw_mdc_pulse();
}
/*
disable eeprom write
*/
static void ifx_sw_eeprom_write_disable(void)
{
unsigned int op;
ifx_mdcs_lo();
ifx_mdc_lo();
ifx_mdio_hi();
udelay(ADM_SW_CS_DELAY);
/* enable chip select */
ifx_mdcs_hi();
udelay(ADM_SW_CS_DELAY);
/* start bit */
ifx_mdio_hi();
ifx_sw_mdc_pulse();
/* eeprom write disable */
op = ADM_SW_BIT_MASK_4;
while (op)
{
if (op & ADM_SW_EEPROM_WRITE_DISABLE)
ifx_mdio_hi();
else
ifx_mdio_lo();
ifx_sw_mdc_pulse();
op >>= 1;
}
op = ADM_SW_BIT_MASK_1 << (EEPROM_TYPE - 3);
while (op)
{
ifx_mdio_lo();
ifx_sw_mdc_pulse();
op >>= 1;
}
/* disable chip select */
ifx_mdcs_lo();
udelay(ADM_SW_CS_DELAY);
ifx_sw_mdc_pulse();
}
/*
read registers from ADM6996
serial registers start at 0x200 (addr bit 9 = 1b)
EEPROM registers -> 16bits; Serial registers -> 32bits
*/
#ifdef ADM6996_MDC_MDIO_MODE //smi mode//000001.joelin
static int ifx_sw_read_adm6996i_smi(unsigned int addr, unsigned int *dat)
{
addr=(addr<<16)&0x3ff0000;
AMAZON_SW_REG(AMAZON_SW_MDIO_ACC) =(0xC0000000|addr);
while ((AMAZON_SW_REG(AMAZON_SW_MDIO_ACC))&0x80000000){};
*dat=((AMAZON_SW_REG(AMAZON_SW_MDIO_ACC))&0x0FFFF);
return 0;
}
#endif
static int ifx_sw_read_adm6996i(unsigned int addr, unsigned int *dat)
{
unsigned int op;
ifx_gpio_init();
ifx_mdcs_hi();
udelay(ADM_SW_CS_DELAY);
ifx_mdcs_lo();
ifx_mdc_lo();
ifx_mdio_lo();
udelay(ADM_SW_CS_DELAY);
/* preamble, 32 bit 1 */
ifx_mdio_hi();
op = ADM_SW_BIT_MASK_32;
while (op)
{
ifx_sw_mdc_pulse();
op >>= 1;
}
/* command start (01b) */
op = ADM_SW_BIT_MASK_2;
while (op)
{
if (op & ADM_SW_SMI_START)
ifx_mdio_hi();
else
ifx_mdio_lo();
ifx_sw_mdc_pulse();
op >>= 1;
}
/* read command (10b) */
op = ADM_SW_BIT_MASK_2;
while (op)
{
if (op & ADM_SW_SMI_READ)
ifx_mdio_hi();
else
ifx_mdio_lo();
ifx_sw_mdc_pulse();
op >>= 1;
}
/* send address A9 ~ A0 */
op = ADM_SW_BIT_MASK_10;
while (op)
{
if (op & addr)
ifx_mdio_hi();
else
ifx_mdio_lo();
ifx_sw_mdc_pulse();
op >>= 1;
}
/* turnaround bits */
op = ADM_SW_BIT_MASK_2;
ifx_mdio_hi();
while (op)
{
ifx_sw_mdc_pulse();
op >>= 1;
}
udelay(ADM_SW_MDC_DOWN_DELAY);
/* set MDIO pin to input mode */
ifx_mdio_mode(ADM_SW_MDIO_INPUT);
/* start read data */
*dat = 0;
//adm6996i op = ADM_SW_BIT_MASK_32;
op = ADM_SW_BIT_MASK_16;//adm6996i
while (op)
{
*dat <<= 1;
if (ifx_sw_mdio_readbit()) *dat |= 1;
ifx_sw_mdc_toggle();
op >>= 1;
}
/* set MDIO to output mode */
ifx_mdio_mode(ADM_SW_MDIO_OUTPUT);
/* dummy clock */
op = ADM_SW_BIT_MASK_4;
ifx_mdio_lo();
while(op)
{
ifx_sw_mdc_pulse();
op >>= 1;
}
ifx_mdc_lo();
ifx_mdio_lo();
ifx_mdcs_hi();
/* EEPROM registers */
//adm6996i if (!(addr & 0x200))
//adm6996i {
//adm6996i if (addr % 2)
//adm6996i *dat >>= 16;
//adm6996i else
//adm6996i *dat &= 0xffff;
//adm6996i }
return 0;
}
//adm6996
static int ifx_sw_read_adm6996l(unsigned int addr, unsigned int *dat)
{
unsigned int op;
ifx_gpio_init();
ifx_mdcs_hi();
udelay(ADM_SW_CS_DELAY);
ifx_mdcs_lo();
ifx_mdc_lo();
ifx_mdio_lo();
udelay(ADM_SW_CS_DELAY);
/* preamble, 32 bit 1 */
ifx_mdio_hi();
op = ADM_SW_BIT_MASK_32;
while (op)
{
ifx_sw_mdc_pulse();
op >>= 1;
}
/* command start (01b) */
op = ADM_SW_BIT_MASK_2;
while (op)
{
if (op & ADM_SW_SMI_START)
ifx_mdio_hi();
else
ifx_mdio_lo();
ifx_sw_mdc_pulse();
op >>= 1;
}
/* read command (10b) */
op = ADM_SW_BIT_MASK_2;
while (op)
{
if (op & ADM_SW_SMI_READ)
ifx_mdio_hi();
else
ifx_mdio_lo();
ifx_sw_mdc_pulse();
op >>= 1;
}
/* send address A9 ~ A0 */
op = ADM_SW_BIT_MASK_10;
while (op)
{
if (op & addr)
ifx_mdio_hi();
else
ifx_mdio_lo();
ifx_sw_mdc_pulse();
op >>= 1;
}
/* turnaround bits */
op = ADM_SW_BIT_MASK_2;
ifx_mdio_hi();
while (op)
{
ifx_sw_mdc_pulse();
op >>= 1;
}
udelay(ADM_SW_MDC_DOWN_DELAY);
/* set MDIO pin to input mode */
ifx_mdio_mode(ADM_SW_MDIO_INPUT);
/* start read data */
*dat = 0;
op = ADM_SW_BIT_MASK_32;
while (op)
{
*dat <<= 1;
if (ifx_sw_mdio_readbit()) *dat |= 1;
ifx_sw_mdc_toggle();
op >>= 1;
}
/* set MDIO to output mode */
ifx_mdio_mode(ADM_SW_MDIO_OUTPUT);
/* dummy clock */
op = ADM_SW_BIT_MASK_4;
ifx_mdio_lo();
while(op)
{
ifx_sw_mdc_pulse();
op >>= 1;
}
ifx_mdc_lo();
ifx_mdio_lo();
ifx_mdcs_hi();
/* EEPROM registers */
if (!(addr & 0x200))
{
if (addr % 2)
*dat >>= 16;
else
*dat &= 0xffff;
}
return 0;
}
static int ifx_sw_read(unsigned int addr, unsigned int *dat)
{
#ifdef ADM6996_MDC_MDIO_MODE //smi mode ////000001.joelin
ifx_sw_read_adm6996i_smi(addr,dat);
#else
if (adm6996_mode==adm6996i) ifx_sw_read_adm6996i(addr,dat);
else ifx_sw_read_adm6996l(addr,dat);
#endif
return 0;
}
/*
write register to ADM6996 eeprom registers
*/
//for adm6996i -start
#ifdef ADM6996_MDC_MDIO_MODE //smi mode //000001.joelin
static int ifx_sw_write_adm6996i_smi(unsigned int addr, unsigned int dat)
{
AMAZON_SW_REG(AMAZON_SW_MDIO_ACC) = ((addr<<16)&0x3ff0000)|dat|0x80000000;
while ((AMAZON_SW_REG(AMAZON_SW_MDIO_ACC))&0x80000000){};
return 0;
}
#endif //ADM6996_MDC_MDIO_MODE //000001.joelin
static int ifx_sw_write_adm6996i(unsigned int addr, unsigned int dat)
{
unsigned int op;
ifx_gpio_init();
ifx_mdcs_hi();
udelay(ADM_SW_CS_DELAY);
ifx_mdcs_lo();
ifx_mdc_lo();
ifx_mdio_lo();
udelay(ADM_SW_CS_DELAY);
/* preamble, 32 bit 1 */
ifx_mdio_hi();
op = ADM_SW_BIT_MASK_32;
while (op)
{
ifx_sw_mdc_pulse();
op >>= 1;
}
/* command start (01b) */
op = ADM_SW_BIT_MASK_2;
while (op)
{
if (op & ADM_SW_SMI_START)
ifx_mdio_hi();
else
ifx_mdio_lo();
ifx_sw_mdc_pulse();
op >>= 1;
}
/* write command (01b) */
op = ADM_SW_BIT_MASK_2;
while (op)
{
if (op & ADM_SW_SMI_WRITE)
ifx_mdio_hi();
else
ifx_mdio_lo();
ifx_sw_mdc_pulse();
op >>= 1;
}
/* send address A9 ~ A0 */
op = ADM_SW_BIT_MASK_10;
while (op)
{
if (op & addr)
ifx_mdio_hi();
else
ifx_mdio_lo();
ifx_sw_mdc_pulse();
op >>= 1;
}
/* turnaround bits */
op = ADM_SW_BIT_MASK_2;
ifx_mdio_hi();
while (op)
{
ifx_sw_mdc_pulse();
op >>= 1;
}
udelay(ADM_SW_MDC_DOWN_DELAY);
/* set MDIO pin to output mode */
ifx_mdio_mode(ADM_SW_MDIO_OUTPUT);
/* start write data */
op = ADM_SW_BIT_MASK_16;
while (op)
{
if (op & dat)
ifx_mdio_hi();
else
ifx_mdio_lo();
ifx_sw_mdc_toggle();
op >>= 1;
}
// /* set MDIO to output mode */
// ifx_mdio_mode(ADM_SW_MDIO_OUTPUT);
/* dummy clock */
op = ADM_SW_BIT_MASK_4;
ifx_mdio_lo();
while(op)
{
ifx_sw_mdc_pulse();
op >>= 1;
}
ifx_mdc_lo();
ifx_mdio_lo();
ifx_mdcs_hi();
/* EEPROM registers */
//adm6996i if (!(addr & 0x200))
//adm6996i {
//adm6996i if (addr % 2)
//adm6996i *dat >>= 16;
//adm6996i else
//adm6996i *dat &= 0xffff;
//adm6996i }
return 0;
}
//for adm6996i-end
static int ifx_sw_write_adm6996l(unsigned int addr, unsigned int dat)
{
unsigned int op;
ifx_gpio_init();
/* enable write */
ifx_sw_eeprom_write_enable();
/* chip select */
ifx_mdcs_hi();
udelay(ADM_SW_CS_DELAY);
/* issue write command */
/* start bit */
ifx_mdio_hi();
ifx_sw_mdc_pulse();
/* EEPROM write command */
op = ADM_SW_BIT_MASK_2;
while (op)
{
if (op & ADM_SW_EEPROM_WRITE)
ifx_mdio_hi();
else
ifx_mdio_lo();
ifx_sw_mdc_pulse();
op >>= 1;
}
/* send address A7 ~ A0 */
op = ADM_SW_BIT_MASK_1 << (EEPROM_TYPE - 1);
while (op)
{
if (op & addr)
ifx_mdio_hi();
else
ifx_mdio_lo();
ifx_sw_mdc_toggle();
op >>= 1;
}
/* start write data */
op = ADM_SW_BIT_MASK_16;
while (op)
{
if (op & dat)
ifx_mdio_hi();
else
ifx_mdio_lo();
ifx_sw_mdc_toggle();
op >>= 1;
}
/* disable cs & wait 1 clock */
ifx_mdcs_lo();
udelay(ADM_SW_CS_DELAY);
ifx_sw_mdc_toggle();
ifx_sw_eeprom_write_disable();
return 0;
}
static int ifx_sw_write(unsigned int addr, unsigned int dat)
{
#ifdef ADM6996_MDC_MDIO_MODE //smi mode ////000001.joelin
ifx_sw_write_adm6996i_smi(addr,dat);
#else //000001.joelin
if (adm6996_mode==adm6996i) ifx_sw_write_adm6996i(addr,dat);
else ifx_sw_write_adm6996l(addr,dat);
#endif //000001.joelin
return 0;
}
/*
do switch PHY reset
*/
int ifx_sw_reset(void)
{
/* reset PHY */
ifx_sw_write(ADM_SW_PHY_RESET, 0);
return 0;
}
/* 509201:linmars start */
#if 0
/*
check port status
*/
int ifx_check_port_status(int port)
{
unsigned int val;
if ((port < 0) || (port > ADM_SW_MAX_PORT_NUM))
{
ifx_printf(("error on port number (%d)!!\n", port));
return -1;
}
ifx_sw_read(ifx_sw_conf[port], &val);
if (ifx_sw_conf[port]%2) val >>= 16;
/* only 16bits are effective */
val &= 0xFFFF;
ifx_printf(("Port %d status (%.8x): \n", port, val));
if (val & ADM_SW_PORT_FLOWCTL)
ifx_printf(("\t802.3x flow control supported!\n"));
else
ifx_printf(("\t802.3x flow control not supported!\n"));
if (val & ADM_SW_PORT_AN)
ifx_printf(("\tAuto negotiation ON!\n"));
else
ifx_printf(("\tAuto negotiation OFF!\n"));
if (val & ADM_SW_PORT_100M)
ifx_printf(("\tLink at 100M!\n"));
else
ifx_printf(("\tLink at 10M!\n"));
if (val & ADM_SW_PORT_FULL)
ifx_printf(("\tFull duplex!\n"));
else
ifx_printf(("\tHalf duplex!\n"));
if (val & ADM_SW_PORT_DISABLE)
ifx_printf(("\tPort disabled!\n"));
else
ifx_printf(("\tPort enabled!\n"));
if (val & ADM_SW_PORT_TOS)
ifx_printf(("\tTOS enabled!\n"));
else
ifx_printf(("\tTOS disabled!\n"));
if (val & ADM_SW_PORT_PPRI)
ifx_printf(("\tPort priority first!\n"));
else
ifx_printf(("\tVLAN or TOS priority first!\n"));
if (val & ADM_SW_PORT_MDIX)
ifx_printf(("\tAuto MDIX!\n"));
else
ifx_printf(("\tNo auto MDIX\n"));
ifx_printf(("\tPVID: %d\n", \
((val >> ADM_SW_PORT_PVID_SHIFT)&ifx_sw_bits[ADM_SW_PORT_PVID_BITS])));
return 0;
}
/*
initialize a VLAN
clear all VLAN bits
*/
int ifx_sw_vlan_init(int vlanid)
{
ifx_sw_write(ADM_SW_VLAN0_CONF + vlanid, 0);
return 0;
}
/*
add a port to certain vlan
*/
int ifx_sw_vlan_add(int port, int vlanid)
{
int reg = 0;
if ((port < 0) || (port > ADM_SW_MAX_PORT_NUM) || (vlanid < 0) ||
(vlanid > ADM_SW_MAX_VLAN_NUM))
{
ifx_printf(("Port number or VLAN number ERROR!!\n"));
return -1;
}
ifx_sw_read(ADM_SW_VLAN0_CONF + vlanid, &reg);
reg |= (1 << ifx_sw_vlan_port[port]);
ifx_sw_write(ADM_SW_VLAN0_CONF + vlanid, reg);
return 0;
}
/*
delete a given port from certain vlan
*/
int ifx_sw_vlan_del(int port, int vlanid)
{
unsigned int reg = 0;
if ((port < 0) || (port > ADM_SW_MAX_PORT_NUM) || (vlanid < 0) || (vlanid > ADM_SW_MAX_VLAN_NUM))
{
ifx_printf(("Port number or VLAN number ERROR!!\n"));
return -1;
}
ifx_sw_read(ADM_SW_VLAN0_CONF + vlanid, &reg);
reg &= ~(1 << ifx_sw_vlan_port[port]);
ifx_sw_write(ADM_SW_VLAN0_CONF + vlanid, reg);
return 0;
}
/*
default VLAN setting
port 0~3 as untag port and PVID = 1
VLAN1: port 0~3 and port 5 (MII)
*/
static int ifx_sw_init(void)
{
ifx_printf(("Setting default ADM6996 registers... \n"));
/* MAC clone, 802.1q based VLAN */
ifx_sw_write(ADM_SW_VLAN_MODE, 0xff30);
/* auto MDIX, PVID=1, untag */
ifx_sw_write(ADM_SW_PORT0_CONF, 0x840f);
ifx_sw_write(ADM_SW_PORT1_CONF, 0x840f);
ifx_sw_write(ADM_SW_PORT2_CONF, 0x840f);
ifx_sw_write(ADM_SW_PORT3_CONF, 0x840f);
/* auto MDIX, PVID=2, untag */
ifx_sw_write(ADM_SW_PORT5_CONF, 0x880f);
/* port 0~3 & 5 as VLAN1 */
ifx_sw_write(ADM_SW_VLAN0_CONF+1, 0x0155);
return 0;
}
#endif
/* 509201:linmars end */
int adm_open(struct inode *node, struct file *filp)
{
return 0;
}
ssize_t adm_read(struct file *filep, char *buf, size_t count, loff_t *ppos)
{
return count;
}
ssize_t adm_write(struct file *filep, const char *buf, size_t count, loff_t *ppos)
{
return count;
}
/* close */
int adm_release(struct inode *inode, struct file *filp)
{
return 0;
}
/* IOCTL function */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
static long adm_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
#else
static int adm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long args)
#endif
{
PREGRW uREGRW;
unsigned int rtval;
unsigned int val; //6996i
unsigned int control[6] ; //6996i
unsigned int status[6] ; //6996i
PMACENTRY mMACENTRY;//adm6996i
PPROTOCOLFILTER uPROTOCOLFILTER ;///adm6996i
if (_IOC_TYPE(cmd) != ADM_MAGIC)
{
printk("adm_ioctl: IOC_TYPE(%x) != ADM_MAGIC(%x)! \n", _IOC_TYPE(cmd), ADM_MAGIC);
return (-EINVAL);
}
if(_IOC_NR(cmd) >= KEY_IOCTL_MAX_KEY)
{
printk(KERN_WARNING "adm_ioctl: IOC_NR(%x) invalid! \n", _IOC_NR(cmd));
return (-EINVAL);
}
switch (cmd)
{
case ADM_IOCTL_REGRW:
{
uREGRW = (PREGRW)kmalloc(sizeof(REGRW), GFP_KERNEL);
rtval = copy_from_user(uREGRW, (PREGRW)args, sizeof(REGRW));
if (rtval != 0)
{
printk("ADM_IOCTL_REGRW: copy from user FAILED!! \n");
return (-EFAULT);
}
switch(uREGRW->mode)
{
case REG_READ:
uREGRW->value = 0x12345678;//inl(uREGRW->addr);
copy_to_user((PREGRW)args, uREGRW, sizeof(REGRW));
break;
case REG_WRITE:
//outl(uREGRW->value, uREGRW->addr);
break;
default:
printk("No such Register Read/Write function!! \n");
return (-EFAULT);
}
kfree(uREGRW);
break;
}
case ADM_SW_IOCTL_REGRW:
{
unsigned int val = 0xff;
uREGRW = (PREGRW)kmalloc(sizeof(REGRW), GFP_KERNEL);
rtval = copy_from_user(uREGRW, (PREGRW)args, sizeof(REGRW));
if (rtval != 0)
{
printk("ADM_IOCTL_REGRW: copy from user FAILED!! \n");
return (-EFAULT);
}
switch(uREGRW->mode)
{
case REG_READ:
ifx_sw_read(uREGRW->addr, &val);
uREGRW->value = val;
copy_to_user((PREGRW)args, uREGRW, sizeof(REGRW));
break;
case REG_WRITE:
ifx_sw_write(uREGRW->addr, uREGRW->value);
break;
default:
printk("No such Register Read/Write function!! \n");
return (-EFAULT);
}
kfree(uREGRW);
break;
}
/* 509201:linmars start */
#if 0
case ADM_SW_IOCTL_PORTSTS:
for (rtval = 0; rtval < ADM_SW_MAX_PORT_NUM+1; rtval++)
ifx_check_port_status(rtval);
break;
case ADM_SW_IOCTL_INIT:
ifx_sw_init();
break;
#endif
/* 509201:linmars end */
//adm6996i
case ADM_SW_IOCTL_MACENTRY_ADD:
case ADM_SW_IOCTL_MACENTRY_DEL:
case ADM_SW_IOCTL_MACENTRY_GET_INIT:
case ADM_SW_IOCTL_MACENTRY_GET_MORE:
mMACENTRY = (PMACENTRY)kmalloc(sizeof(MACENTRY), GFP_KERNEL);
rtval = copy_from_user(mMACENTRY, (PMACENTRY)args, sizeof(MACENTRY));
if (rtval != 0)
{
printk("ADM_SW_IOCTL_MACENTRY: copy from user FAILED!! \n");
return (-EFAULT);
}
control[0]=(mMACENTRY->mac_addr[1]<<8)+mMACENTRY->mac_addr[0] ;
control[1]=(mMACENTRY->mac_addr[3]<<8)+mMACENTRY->mac_addr[2] ;
control[2]=(mMACENTRY->mac_addr[5]<<8)+mMACENTRY->mac_addr[4] ;
control[3]=(mMACENTRY->fid&0xf)+((mMACENTRY->portmap&0x3f)<<4);
if (((mMACENTRY->info_type)&0x01)) control[4]=(mMACENTRY->ctrl.info_ctrl)+0x1000; //static ,info control
else control[4]=((mMACENTRY->ctrl.age_timer)&0xff);//not static ,agetimer
if (cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT) {
//initial the pointer to the first address
val=0x8000;//busy ,status5[15]
while(val&0x8000){ //check busy ?
ifx_sw_read(0x125, &val);
}
control[5]=0x030;//initial the first address
ifx_sw_write(0x11f,control[5]);
val=0x8000;//busy ,status5[15]
while(val&0x8000){ //check busy ?
ifx_sw_read(0x125, &val);
}
} //if (cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)
if (cmd==ADM_SW_IOCTL_MACENTRY_ADD) control[5]=0x07;//create a new address
else if (cmd==ADM_SW_IOCTL_MACENTRY_DEL) control[5]=0x01f;//erased an existed address
else if ((cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)||(cmd==ADM_SW_IOCTL_MACENTRY_GET_MORE))
control[5]=0x02c;//search by the mac address field
val=0x8000;//busy ,status5[15]
while(val&0x8000){ //check busy ?
ifx_sw_read(0x125, &val);
}
ifx_sw_write(0x11a,control[0]);
ifx_sw_write(0x11b,control[1]);
ifx_sw_write(0x11c,control[2]);
ifx_sw_write(0x11d,control[3]);
ifx_sw_write(0x11e,control[4]);
ifx_sw_write(0x11f,control[5]);
val=0x8000;//busy ,status5[15]
while(val&0x8000){ //check busy ?
ifx_sw_read(0x125, &val);
}
val=((val&0x7000)>>12);//result ,status5[14:12]
mMACENTRY->result=val;
if (!val) {
printk(" Command OK!! \n");
if ((cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)||(cmd==ADM_SW_IOCTL_MACENTRY_GET_MORE)) {
ifx_sw_read(0x120,&(status[0]));
ifx_sw_read(0x121,&(status[1]));
ifx_sw_read(0x122,&(status[2]));
ifx_sw_read(0x123,&(status[3]));
ifx_sw_read(0x124,&(status[4]));
ifx_sw_read(0x125,&(status[5]));
mMACENTRY->mac_addr[0]=(status[0]&0x00ff) ;
mMACENTRY->mac_addr[1]=(status[0]&0xff00)>>8 ;
mMACENTRY->mac_addr[2]=(status[1]&0x00ff) ;
mMACENTRY->mac_addr[3]=(status[1]&0xff00)>>8 ;
mMACENTRY->mac_addr[4]=(status[2]&0x00ff) ;
mMACENTRY->mac_addr[5]=(status[2]&0xff00)>>8 ;
mMACENTRY->fid=(status[3]&0xf);
mMACENTRY->portmap=((status[3]>>4)&0x3f);
if (status[5]&0x2) {//static info_ctrl //status5[1]????
mMACENTRY->ctrl.info_ctrl=(status[4]&0x00ff);
mMACENTRY->info_type=1;
}
else {//not static age_timer
mMACENTRY->ctrl.age_timer=(status[4]&0x00ff);
mMACENTRY->info_type=0;
}
//status5[13]???? mMACENTRY->occupy=(status[5]&0x02)>>1;//status5[1]
mMACENTRY->occupy=(status[5]&0x02000)>>13;//status5[13] ???
mMACENTRY->bad=(status[5]&0x04)>>2;//status5[2]
}//if ((cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)||(cmd==ADM_SW_IOCTL_MACENTRY_GET_MORE))
}
else if (val==0x001)
printk(" All Entry Used!! \n");
else if (val==0x002)
printk(" Entry Not Found!! \n");
else if (val==0x003)
printk(" Try Next Entry!! \n");
else if (val==0x005)
printk(" Command Error!! \n");
else
printk(" UnKnown Error!! \n");
copy_to_user((PMACENTRY)args, mMACENTRY,sizeof(MACENTRY));
break;
case ADM_SW_IOCTL_FILTER_ADD:
case ADM_SW_IOCTL_FILTER_DEL:
case ADM_SW_IOCTL_FILTER_GET:
uPROTOCOLFILTER = (PPROTOCOLFILTER)kmalloc(sizeof(PROTOCOLFILTER), GFP_KERNEL);
rtval = copy_from_user(uPROTOCOLFILTER, (PPROTOCOLFILTER)args, sizeof(PROTOCOLFILTER));
if (rtval != 0)
{
printk("ADM_SW_IOCTL_FILTER_ADD: copy from user FAILED!! \n");
return (-EFAULT);
}
if(cmd==ADM_SW_IOCTL_FILTER_DEL) { //delete filter
uPROTOCOLFILTER->ip_p=00; //delet filter
uPROTOCOLFILTER->action=00; //delete filter
} //delete filter
ifx_sw_read(((uPROTOCOLFILTER->protocol_filter_num/2)+0x68), &val);//rx68~rx6b,protocol filter0~7
if (((uPROTOCOLFILTER->protocol_filter_num)%2)==00){
if(cmd==ADM_SW_IOCTL_FILTER_GET) uPROTOCOLFILTER->ip_p= val&0x00ff;//get filter ip_p
else val=(val&0xff00)|(uPROTOCOLFILTER->ip_p);//set filter ip_p
}
else {
if(cmd==ADM_SW_IOCTL_FILTER_GET) uPROTOCOLFILTER->ip_p= (val>>8);//get filter ip_p
else val=(val&0x00ff)|((uPROTOCOLFILTER->ip_p)<<8);//set filter ip_p
}
if(cmd!=ADM_SW_IOCTL_FILTER_GET) ifx_sw_write(((uPROTOCOLFILTER->protocol_filter_num/2)+0x68), val);//write rx68~rx6b,protocol filter0~7
ifx_sw_read(0x95, &val); //protocol filter action
if(cmd==ADM_SW_IOCTL_FILTER_GET) {
uPROTOCOLFILTER->action= ((val>>(uPROTOCOLFILTER->protocol_filter_num*2))&0x3);//get filter action
copy_to_user((PPROTOCOLFILTER)args, uPROTOCOLFILTER, sizeof(PROTOCOLFILTER));
}
else {
val=(val&(~(0x03<<(uPROTOCOLFILTER->protocol_filter_num*2))))|(((uPROTOCOLFILTER->action)&0x03)<<(uPROTOCOLFILTER->protocol_filter_num*2));
// printk("%d----\n",val);
ifx_sw_write(0x95, val); //write protocol filter action
}
break;
//adm6996i
/* others */
default:
return -EFAULT;
}
/* end of switch */
return 0;
}
/* Santosh: handle IGMP protocol filter ADD/DEL/GET */
int adm_process_protocol_filter_request (unsigned int cmd, PPROTOCOLFILTER uPROTOCOLFILTER)
{
unsigned int val; //6996i
if(cmd==ADM_SW_IOCTL_FILTER_DEL) { //delete filter
uPROTOCOLFILTER->ip_p=00; //delet filter
uPROTOCOLFILTER->action=00; //delete filter
} //delete filter
ifx_sw_read(((uPROTOCOLFILTER->protocol_filter_num/2)+0x68), &val);//rx68~rx6b,protocol filter0~7
if (((uPROTOCOLFILTER->protocol_filter_num)%2)==00){
if(cmd==ADM_SW_IOCTL_FILTER_GET) uPROTOCOLFILTER->ip_p= val&0x00ff;//get filter ip_p
else val=(val&0xff00)|(uPROTOCOLFILTER->ip_p);//set filter ip_p
}
else {
if(cmd==ADM_SW_IOCTL_FILTER_GET) uPROTOCOLFILTER->ip_p= (val>>8);//get filter ip_p
else val=(val&0x00ff)|((uPROTOCOLFILTER->ip_p)<<8);//set filter ip_p
}
if(cmd!=ADM_SW_IOCTL_FILTER_GET) ifx_sw_write(((uPROTOCOLFILTER->protocol_filter_num/2)+0x68), val);//write rx68~rx6b,protocol filter0~7
ifx_sw_read(0x95, &val); //protocol filter action
if(cmd==ADM_SW_IOCTL_FILTER_GET) {
uPROTOCOLFILTER->action= ((val>>(uPROTOCOLFILTER->protocol_filter_num*2))&0x3);//get filter action
}
else {
val=(val&(~(0x03<<(uPROTOCOLFILTER->protocol_filter_num*2))))|(((uPROTOCOLFILTER->action)&0x03)<<(uPROTOCOLFILTER->protocol_filter_num*2));
ifx_sw_write(0x95, val); //write protocol filter action
}
return 0;
}
/* Santosh: function for MAC ENTRY ADD/DEL/GET */
int adm_process_mac_table_request (unsigned int cmd, PMACENTRY mMACENTRY)
{
unsigned int val; //6996i
unsigned int control[6] ; //6996i
unsigned int status[6] ; //6996i
// printk ("adm_process_mac_table_request: enter\n");
control[0]=(mMACENTRY->mac_addr[1]<<8)+mMACENTRY->mac_addr[0] ;
control[1]=(mMACENTRY->mac_addr[3]<<8)+mMACENTRY->mac_addr[2] ;
control[2]=(mMACENTRY->mac_addr[5]<<8)+mMACENTRY->mac_addr[4] ;
control[3]=(mMACENTRY->fid&0xf)+((mMACENTRY->portmap&0x3f)<<4);
if (((mMACENTRY->info_type)&0x01)) control[4]=(mMACENTRY->ctrl.info_ctrl)+0x1000; //static ,info control
else control[4]=((mMACENTRY->ctrl.age_timer)&0xff);//not static ,agetimer
if (cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT) {
//initial the pointer to the first address
val=0x8000;//busy ,status5[15]
while(val&0x8000){ //check busy ?
ifx_sw_read(0x125, &val);
}
control[5]=0x030;//initial the first address
ifx_sw_write(0x11f,control[5]);
val=0x8000;//busy ,status5[15]
while(val&0x8000){ //check busy ?
ifx_sw_read(0x125, &val);
}
} //if (cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)
if (cmd==ADM_SW_IOCTL_MACENTRY_ADD) control[5]=0x07;//create a new address
else if (cmd==ADM_SW_IOCTL_MACENTRY_DEL) control[5]=0x01f;//erased an existed address
else if ((cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)||(cmd==ADM_SW_IOCTL_MACENTRY_GET_MORE))
control[5]=0x02c;//search by the mac address field
val=0x8000;//busy ,status5[15]
while(val&0x8000){ //check busy ?
ifx_sw_read(0x125, &val);
}
ifx_sw_write(0x11a,control[0]);
ifx_sw_write(0x11b,control[1]);
ifx_sw_write(0x11c,control[2]);
ifx_sw_write(0x11d,control[3]);
ifx_sw_write(0x11e,control[4]);
ifx_sw_write(0x11f,control[5]);
val=0x8000;//busy ,status5[15]
while(val&0x8000){ //check busy ?
ifx_sw_read(0x125, &val);
}
val=((val&0x7000)>>12);//result ,status5[14:12]
mMACENTRY->result=val;
if (!val) {
printk(" Command OK!! \n");
if ((cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)||(cmd==ADM_SW_IOCTL_MACENTRY_GET_MORE)) {
ifx_sw_read(0x120,&(status[0]));
ifx_sw_read(0x121,&(status[1]));
ifx_sw_read(0x122,&(status[2]));
ifx_sw_read(0x123,&(status[3]));
ifx_sw_read(0x124,&(status[4]));
ifx_sw_read(0x125,&(status[5]));
mMACENTRY->mac_addr[0]=(status[0]&0x00ff) ;
mMACENTRY->mac_addr[1]=(status[0]&0xff00)>>8 ;
mMACENTRY->mac_addr[2]=(status[1]&0x00ff) ;
mMACENTRY->mac_addr[3]=(status[1]&0xff00)>>8 ;
mMACENTRY->mac_addr[4]=(status[2]&0x00ff) ;
mMACENTRY->mac_addr[5]=(status[2]&0xff00)>>8 ;
mMACENTRY->fid=(status[3]&0xf);
mMACENTRY->portmap=((status[3]>>4)&0x3f);
if (status[5]&0x2) {//static info_ctrl //status5[1]????
mMACENTRY->ctrl.info_ctrl=(status[4]&0x00ff);
mMACENTRY->info_type=1;
}
else {//not static age_timer
mMACENTRY->ctrl.age_timer=(status[4]&0x00ff);
mMACENTRY->info_type=0;
}
//status5[13]???? mMACENTRY->occupy=(status[5]&0x02)>>1;//status5[1]
mMACENTRY->occupy=(status[5]&0x02000)>>13;//status5[13] ???
mMACENTRY->bad=(status[5]&0x04)>>2;//status5[2]
}//if ((cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)||(cmd==ADM_SW_IOCTL_MACENTRY_GET_MORE))
}
else if (val==0x001)
printk(" All Entry Used!! \n");
else if (val==0x002)
printk(" Entry Not Found!! \n");
else if (val==0x003)
printk(" Try Next Entry!! \n");
else if (val==0x005)
printk(" Command Error!! \n");
else
printk(" UnKnown Error!! \n");
// printk ("adm_process_mac_table_request: Exit\n");
return 0;
}
/* Santosh: End of function for MAC ENTRY ADD/DEL*/
struct file_operations adm_ops =
{
read: adm_read,
write: adm_write,
open: adm_open,
release: adm_release,
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
unlocked_ioctl: adm_ioctl
#else
ioctl: adm_ioctl
#endif
};
int adm_proc(char *buf, char **start, off_t offset, int count, int *eof, void *data)
{
int len = 0;
len += sprintf(buf+len, " ************ Registers ************ \n");
*eof = 1;
return len;
}
int __init init_adm6996_module(void)
{
unsigned int val = 000;
unsigned int val1 = 000;
printk("Loading ADM6996 driver... \n");
/* if running on adm5120 */
/* set GPIO 0~2 as adm6996 control pins */
//outl(0x003f3f00, 0x12000028);
/* enable switch port 5 (MII) as RMII mode (5120MAC <-> 6996MAC) */
//outl(0x18a, 0x12000030);
/* group adm5120 port 1 ~ 5 as VLAN0, port 5 & 6(CPU) as VLAN1 */
//outl(0x417e, 0x12000040);
/* end adm5120 fixup */
#ifdef ADM6996_MDC_MDIO_MODE //smi mode //000001.joelin
register_chrdev(69, "adm6996", &adm_ops);
AMAZON_SW_REG(AMAZON_SW_MDIO_CFG) = 0x27be;
AMAZON_SW_REG(AMAZON_SW_EPHY) = 0xfc;
adm6996_mode=adm6996i;
ifx_sw_read(0xa0, &val);
ifx_sw_read(0xa1, &val1);
val=((val1&0x0f)<<16)|val;
printk ("\nADM6996 SMI Mode-");
printk ("Chip ID:%5x \n ", val);
#else //000001.joelin
AMAZON_SW_REG(AMAZON_SW_MDIO_CFG) = 0x2c50;
AMAZON_SW_REG(AMAZON_SW_EPHY) = 0xff;
AMAZON_SW_REG(AMAZON_GPIO_P1_ALTSEL0) &= ~(GPIO_MDIO|GPIO_MDCS|GPIO_MDC);
AMAZON_SW_REG(AMAZON_GPIO_P1_ALTSEL1) &= ~(GPIO_MDIO|GPIO_MDCS|GPIO_MDC);
AMAZON_SW_REG(AMAZON_GPIO_P1_OD) |= (GPIO_MDIO|GPIO_MDCS|GPIO_MDC);
ifx_gpio_init();
register_chrdev(69, "adm6996", &adm_ops);
mdelay(100);
/* create proc entries */
// create_proc_read_entry("admide", 0, NULL, admide_proc, NULL);
//joelin adm6996i support start
adm6996_mode=adm6996i;
ifx_sw_read(0xa0, &val);
adm6996_mode=adm6996l;
ifx_sw_read(0x200, &val1);
// printk ("\n %0x \n",val1);
if ((val&0xfff0)==0x1020) {
printk ("\n ADM6996I .. \n");
adm6996_mode=adm6996i;
}
else if ((val1&0xffffff00)==0x71000) {//71010 or 71020
printk ("\n ADM6996LC .. \n");
adm6996_mode=adm6996lc;
}
else {
printk ("\n ADM6996L .. \n");
adm6996_mode=adm6996l;
}
#endif //ADM6996_MDC_MDIO_MODE //smi mode //000001.joelin
if ((adm6996_mode==adm6996lc)||(adm6996_mode==adm6996i)){
#if 0 /* removed by MarsLin */
ifx_sw_write(0x29,0xc000);
ifx_sw_write(0x30,0x0985);
#else
ifx_sw_read(0xa0, &val);
if (val == 0x1021) // for both 6996LC and 6996I, only AB version need the patch
ifx_sw_write(0x29, 0x9000);
ifx_sw_write(0x30,0x0985);
#endif
}
//joelin adm6996i support end
return 0;
}
void __exit cleanup_adm6996_module(void)
{
printk("Free ADM device driver... \n");
unregister_chrdev(69, "adm6996");
/* remove proc entries */
// remove_proc_entry("admide", NULL);
}
/* MarsLin, add start */
#if defined(CONFIG_IFX_NFEXT_AMAZON_SWITCH_PHYPORT) || defined(CONFIG_IFX_NFEXT_AMAZON_SWITCH_PHYPORT_MODULE)
#define SET_BIT(reg, mask) reg |= (mask)
#define CLEAR_BIT(reg, mask) reg &= (~mask)
static int ifx_hw_reset(void)
{
CLEAR_BIT((*AMAZON_GPIO_P0_ALTSEL0),0x2000);
CLEAR_BIT((*AMAZON_GPIO_P0_ALTSEL1),0x2000);
SET_BIT((*AMAZON_GPIO_P0_OD),0x2000);
SET_BIT((*AMAZON_GPIO_P0_DIR), 0x2000);
CLEAR_BIT((*AMAZON_GPIO_P0_OUT), 0x2000);
mdelay(500);
SET_BIT((*AMAZON_GPIO_P0_OUT), 0x2000);
cleanup_adm6996_module();
return init_adm6996_module();
}
int (*adm6996_hw_reset)(void) = ifx_hw_reset;
EXPORT_SYMBOL(adm6996_hw_reset);
EXPORT_SYMBOL(adm6996_mode);
int (*adm6996_sw_read)(unsigned int addr, unsigned int *data) = ifx_sw_read;
EXPORT_SYMBOL(adm6996_sw_read);
int (*adm6996_sw_write)(unsigned int addr, unsigned int data) = ifx_sw_write;
EXPORT_SYMBOL(adm6996_sw_write);
#endif
/* MarsLin, add end */
/* Santosh: for IGMP proxy/snooping, Begin */
EXPORT_SYMBOL (adm_process_mac_table_request);
EXPORT_SYMBOL (adm_process_protocol_filter_request);
/* Santosh: for IGMP proxy/snooping, End */
MODULE_DESCRIPTION("ADMtek 6996 Driver");
MODULE_AUTHOR("Joe Lin <joe.lin@infineon.com>");
MODULE_LICENSE("GPL");
module_init(init_adm6996_module);
module_exit(cleanup_adm6996_module);