* ADMTEK Adm6996 switch configuration module
*
* Copyright (C) 2005 Felix Fietkau <nbd@nbd.name>
- *
+ *
* Partially based on Broadcom Home Networking Division 10/100 Mbit/s
* Ethernet Device Driver (from Montavista 2.4.20_mvl31 Kernel).
* Copyright (C) 2004 Broadcom Corporation
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/if.h>
#include "switch-core.h"
#include "gpio.h"
+#ifdef CONFIG_BCM47XX
+#include <nvram.h>
+#endif
+
#define DRIVER_NAME "adm6996"
#define DRIVER_VERSION "0.01"
MODULE_AUTHOR("Felix Fietkau <openwrt@nbd.name>");
MODULE_LICENSE("GPL");
-MODULE_PARM(eecs, "i");
-MODULE_PARM(eesk, "i");
-MODULE_PARM(eedi, "i");
-MODULE_PARM(eerc, "i");
-MODULE_PARM(force, "i");
+module_param(eecs, int, 0);
+module_param(eesk, int, 0);
+module_param(eedi, int, 0);
+module_param(eerc, int, 0);
+module_param(force, int, 0);
/* Minimum timing constants */
#define EECK_EDGE_TIME 3 /* 3us - max(adm 2.5us, 93c 1us) */
#define atoi(str) simple_strtoul(((str != NULL) ? str : ""), NULL, 0)
-#if defined(BCMGPIO2) || defined(BCMGPIO)
-extern char *nvram_get(char *name);
+#ifdef CONFIG_BCM47XX
/* Return gpio pin number assigned to the named pin */
/*
*
* 'def_pin' is returned if there is no such variable found.
*/
-static unsigned int getgpiopin(char *pin_name, unsigned int def_pin)
+static unsigned int get_gpiopin(char *pin_name, unsigned int def_pin)
{
char name[] = "gpioXXXX";
- char *val;
+ char val[10];
unsigned int pin;
/* Go thru all possibilities till a match in pin name */
for (pin = 0; pin < 16; pin ++) {
sprintf(name, "gpio%d", pin);
- val = nvram_get(name);
- if (val && !strcmp(val, pin_name))
- return pin;
+ if (nvram_getenv(name, val, sizeof(val)) >= 0) {
+ if (!strcmp(val, pin_name))
+ return pin;
+ }
}
return def_pin;
}
int i, len = (bits + 7) / 8;
__u8 mask;
- gpioout(eecs, (cs ? eecs : 0));
+ gpio_out(eecs, (cs ? eecs : 0));
udelay(EECK_EDGE_TIME);
/* Byte assemble from MSB to LSB */
/* Bit bang from MSB to LSB */
for (mask = 0x80; mask && bits > 0; mask >>= 1, bits --) {
/* Clock low */
- gpioout(eesk, 0);
+ gpio_out(eesk, 0);
udelay(EECK_EDGE_TIME);
/* Output on rising edge */
- gpioout(eedi, ((mask & buf[i]) ? eedi : 0));
+ gpio_out(eedi, ((mask & buf[i]) ? eedi : 0));
udelay(EEDI_SETUP_TIME);
/* Clock high */
- gpioout(eesk, eesk);
+ gpio_out(eesk, eesk);
udelay(EECK_EDGE_TIME);
}
}
/* Clock low */
- gpioout(eesk, 0);
+ gpio_out(eesk, 0);
udelay(EECK_EDGE_TIME);
if (cs)
- gpioout(eecs, 0);
+ gpio_out(eecs, 0);
}
int i, len = (bits + 7) / 8;
__u8 mask;
- gpioout(eecs, (cs ? eecs : 0));
+ gpio_out(eecs, (cs ? eecs : 0));
udelay(EECK_EDGE_TIME);
/* Byte assemble from MSB to LSB */
__u8 gp;
/* Clock low */
- gpioout(eesk, 0);
+ gpio_out(eesk, 0);
udelay(EECK_EDGE_TIME);
/* Input on rising edge */
- gp = gpioin();
+ gp = gpio_in();
if (gp & eedi)
byte |= mask;
/* Clock high */
- gpioout(eesk, eesk);
+ gpio_out(eesk, eesk);
udelay(EECK_EDGE_TIME);
}
}
/* Clock low */
- gpioout(eesk, 0);
+ gpio_out(eesk, 0);
udelay(EECK_EDGE_TIME);
if (cs)
- gpioout(eecs, 0);
+ gpio_out(eecs, 0);
}
/* Enable outputs with specified value to the chip */
static void adm_enout(__u8 pins, __u8 val)
-{
+{
/* Prepare GPIO output value */
- gpioout(pins, val);
-
+ gpio_out(pins, val);
+
/* Enable GPIO outputs */
- gpioouten(pins, pins);
+ gpio_outen(pins, pins);
udelay(EECK_EDGE_TIME);
}
/* Disable outputs to the chip */
static void adm_disout(__u8 pins)
-{
+{
/* Disable GPIO outputs */
- gpioouten(pins, 0);
+ gpio_outen(pins, 0);
udelay(EECK_EDGE_TIME);
}
int i;
for (i = 0; i < clocks; i++) {
/* Clock high */
- gpioout(eesk, eesk);
+ gpio_out(eesk, eesk);
udelay(EECK_EDGE_TIME);
/* Clock low */
- gpioout(eesk, 0);
+ gpio_out(eesk, 0);
udelay(EECK_EDGE_TIME);
}
}
__u8 bits[6] = {
0xFF, 0xFF, 0xFF, 0xFF,
(0x06 << 4) | ((table & 0x01) << 3 | (addr&64)>>6),
- ((addr&62)<<2)
+ ((addr&63)<<2)
};
__u8 rbits[4];
static int handle_vlan_port_read(void *driver, char *buf, int nr)
{
int ports, i, c, len = 0;
-
+
if ((nr < 0) || (nr > 15))
return 0;
/* Get VLAN port map */
ports = adm_rreg(0, 0x13 + nr);
-
+
for (i = 0; i <= 5; i++) {
if (ports & vlan_ports[i]) {
c = adm_rreg(0, port_conf[i]);
-
+
len += sprintf(buf + len, "%d", i);
if (c & (1 << 4)) {
buf[len++] = 't';
ports |= vlan_ports[i];
cfg = adm_rreg(0, port_conf[i]);
-
+
/* Tagging */
if (c->untag & (1 << i))
cfg &= ~(1 << 4);
else
cfg |= (1 << 4);
-
+
if ((c->untag | c->pvid) & (1 << i)) {
cfg = (cfg & ~(0xf << 10)) | (nr << 10);
}
-
+
adm_wreg(port_conf[i], (__u16) cfg);
} else {
ports &= ~(vlan_ports[i]);
}
adm_wreg(0x13 + nr, (__u16) ports);
+ kfree(c);
return 0;
}
static int handle_port_enable_write(void *driver, char *buf, int nr)
{
int reg = adm_rreg(0, port_conf[nr]);
-
+
if (buf[0] == '0')
reg |= (1 << 5);
else if (buf[0] == '1')
if (media < 0)
return -1;
-
+
reg &= ~((1 << 1) | (1 << 2) | (1 << 3));
if (media & SWITCH_MEDIA_AUTO)
reg |= 1 << 1;
reg |= 1 << 3;
adm_wreg(port_conf[nr], reg);
-
+
return 0;
}
static int handle_vlan_enable_write(void *driver, char *buf, int nr)
{
int reg = adm_rreg(0, 0x11);
-
+
if (buf[0] == '1')
reg |= (1 << 5);
else if (buf[0] == '0')
udelay(1000);
/* Leave RC high and disable GPIO outputs */
adm_disout((__u8)(eecs | eesk | eedi));
-
+
}
/* set up initial configuration for cpu port */
(1 << 4) | /* Tagging */
0xf); /* full duplex, 100Mbps, auto neg, flow ctrl */
adm_wreg(port_conf[5], cfg);
-
+
/* vlan mode select register (0x11): vlan on, mac clone */
adm_wreg(0x11, 0xff30);
static int handle_registers(void *driver, char *buf, int nr)
{
int i, len = 0;
-
+
for (i = 0; i <= 0x33; i++) {
len += sprintf(buf + len, "0x%02x: 0x%04x\n", i, adm_rreg(0, i));
}
return len;
}
-static int detect_adm()
+static int detect_adm(void)
{
int ret = 0;
-#if defined(BCMGPIO2) || defined(BCMGPIO)
- int boardflags = atoi(nvram_get("boardflags"));
+#ifdef CONFIG_BCM47XX
+ char buf[20];
+ int boardflags = 0;
+ int boardnum = 0;
+
+ if (nvram_getenv("boardflags", buf, sizeof(buf)) >= 0)
+ boardflags = simple_strtoul(buf, NULL, 0);
- if ((boardflags & 0x80) || force) {
- ret = 1;
+ if (nvram_getenv("boardnum", buf, sizeof(buf)) >= 0)
+ boardnum = simple_strtoul(buf, NULL, 0);
- eecs = getgpiopin("adm_eecs", 2);
- eesk = getgpiopin("adm_eesk", 3);
- eedi = getgpiopin("adm_eedi", 4);
- eerc = getgpiopin("adm_rc", 0);
+ if ((boardnum == 44) && (boardflags == 0x0388)) { /* Trendware TEW-411BRP+ */
+ ret = 1;
- } else if ((strcmp(nvram_get("boardtype") ?: "", "bcm94710dev") == 0) &&
- (strncmp(nvram_get("boardnum") ?: "", "42", 2) == 0)) {
- /* WRT54G v1.1 hack */
- eecs = 2;
- eesk = 3;
- eedi = 5;
+ eecs = get_gpiopin("adm_eecs", 2);
+ eesk = get_gpiopin("adm_eesk", 3);
+ eedi = get_gpiopin("adm_eedi", 4);
+ eerc = get_gpiopin("adm_rc", 5);
+ } else if ((boardflags & 0x80) || force) {
ret = 1;
- } else
- printk("BFL_ENETADM not set in boardflags. Use force=1 to ignore.\n");
-
+
+ eecs = get_gpiopin("adm_eecs", 2);
+ eesk = get_gpiopin("adm_eesk", 3);
+ eedi = get_gpiopin("adm_eedi", 4);
+ eerc = get_gpiopin("adm_rc", 0);
+
+ } else if (nvram_getenv("boardtype", buf, sizeof(buf)) >= 0) {
+ if (strcmp(buf, "bcm94710dev") == 0) {
+ if (nvram_getenv("boardnum", buf, sizeof(buf)) >= 0) {
+ if (strncmp(buf, "42", 2) == 0) {
+ /* WRT54G v1.1 hack */
+ eecs = 2;
+ eesk = 3;
+ eedi = 5;
+
+ ret = 1;
+ }
+ }
+ }
+ }
+
if (eecs)
eecs = (1 << eecs);
if (eesk)
return ret;
}
-static int __init adm_init()
+static int __init adm_init(void)
{
switch_config cfg[] = {
{"registers", handle_registers, NULL},
return switch_register_driver(&driver);
}
-static void __exit adm_exit()
+static void __exit adm_exit(void)
{
switch_unregister_driver(DRIVER_NAME);
}