X-Git-Url: https://git.archive.openwrt.org/?p=openwrt.git;a=blobdiff_plain;f=package%2Fbroadcom-diag%2Fsrc%2Fdiag.c;h=ccbaee2d264c501f8b7844fb6743a126156ecdf4;hp=8e7ffa6cc77aaa347e8c14e51f2ce9090a4f5382;hb=801985e5286881dd578a19280b2a6c8e212a530d;hpb=6c4398bc6add362d5b399ba361720cf1afd7176b diff --git a/package/broadcom-diag/src/diag.c b/package/broadcom-diag/src/diag.c index 8e7ffa6cc7..ccbaee2d26 100644 --- a/package/broadcom-diag/src/diag.c +++ b/package/broadcom-diag/src/diag.c @@ -32,6 +32,7 @@ #include #include #include +#include extern u64 uevent_next_seqnum(void); #include "gpio.h" @@ -53,12 +54,19 @@ enum { WRTSL54GS, WRT54G3G, WRT54G3GV2_VF, - WRT160N, + WRT150NV1, + WRT150NV11, + WRT160NV1, + WRT160NV3, WRT300NV11, WRT350N, WRT600N, WRT600NV11, WRT610N, + WRT610NV2, + E1000V1, + E3000V1, + E3200V1, /* ASUS */ WLHDD, @@ -74,6 +82,7 @@ enum { WL520GU, ASUS_4702, WL700GE, + RTN16, /* Buffalo */ WBR2_G54, @@ -107,11 +116,14 @@ enum { /* Belkin */ BELKIN_UNKNOWN, + BELKIN_F7D4301, /* Netgear */ WGT634U, WNR834BV1, WNR834BV2, + WNDR3400V1, + WNDR3700V3, /* Trendware */ TEW411BRPP, @@ -149,9 +161,9 @@ static void __init bcm4780_init(void) { /* Enables GPIO 3 that controls HDD and led power on ASUS WL-700gE */ printk(MODULE_NAME ": Spinning up HDD and enabling leds\n"); - ssb_gpio_outen(&ssb_bcm47xx, pin, pin); - ssb_gpio_control(&ssb_bcm47xx, pin, 0); - ssb_gpio_out(&ssb_bcm47xx, pin, pin); + bcm47xx_gpio_outen(pin, pin); + bcm47xx_gpio_control(pin, 0); + bcm47xx_gpio_out(pin, pin); /* Wait 5s, so the HDD can spin up */ set_current_state(TASK_INTERRUPTIBLE); @@ -161,14 +173,14 @@ static void __init bcm4780_init(void) { static void __init NetCenter_init(void) { /* unset pin 6 (+12V) */ int pin = 1 << 6; - ssb_gpio_outen(&ssb_bcm47xx, pin, pin); - ssb_gpio_control(&ssb_bcm47xx, pin, 0); - ssb_gpio_out(&ssb_bcm47xx, pin, pin); + bcm47xx_gpio_outen(pin, pin); + bcm47xx_gpio_control(pin, 0); + bcm47xx_gpio_out(pin, pin); /* unset pin 1 (turn off red led, blue will light alone if +5V comes up) */ pin = 1 << 1; - ssb_gpio_outen(&ssb_bcm47xx, pin, pin); - ssb_gpio_control(&ssb_bcm47xx, pin, 0); - ssb_gpio_out(&ssb_bcm47xx, pin, pin); + bcm47xx_gpio_outen(pin, pin); + bcm47xx_gpio_control(pin, 0); + bcm47xx_gpio_out(pin, pin); /* unset pin 3 (+5V) and wait 5 seconds (harddisk spin up) */ bcm4780_init(); } @@ -177,9 +189,9 @@ static void __init bcm57xx_init(void) { int pin = 1 << 2; /* FIXME: switch comes up, but port mappings/vlans not right */ - ssb_gpio_outen(&ssb_bcm47xx, pin, pin); - ssb_gpio_control(&ssb_bcm47xx, pin, 0); - ssb_gpio_out(&ssb_bcm47xx, pin, pin); + bcm47xx_gpio_outen(pin, pin); + bcm47xx_gpio_control(pin, 0); + bcm47xx_gpio_out(pin, pin); } static struct platform_t __initdata platforms[] = { @@ -279,8 +291,32 @@ static struct platform_t __initdata platforms[] = { { .name = "3g_blue", .gpio = 1 << 3, .polarity = NORMAL }, }, }, - [WRT160N] = { - .name = "Linksys WRT160N", + [WRT150NV1] = { + .name = "Linksys WRT150N V1", + .buttons = { + { .name = "reset", .gpio = 1 << 6 }, + { .name = "ses", .gpio = 1 << 4 }, + }, + .leds = { + { .name = "power", .gpio = 1 << 1, .polarity = NORMAL }, + { .name = "ses_green", .gpio = 1 << 5, .polarity = REVERSE }, + { .name = "ses_amber", .gpio = 1 << 3, .polarity = REVERSE }, + }, + }, + [WRT150NV11] = { + .name = "Linksys WRT150N V1.1", + .buttons = { + { .name = "reset", .gpio = 1 << 6 }, + { .name = "ses", .gpio = 1 << 4 }, + }, + .leds = { + { .name = "power", .gpio = 1 << 1, .polarity = NORMAL }, + { .name = "ses_green", .gpio = 1 << 5, .polarity = REVERSE }, + { .name = "ses_amber", .gpio = 1 << 3, .polarity = REVERSE }, + }, + }, + [WRT160NV1] = { + .name = "Linksys WRT160N v1.x", .buttons = { { .name = "reset", .gpio = 1 << 6 }, { .name = "ses", .gpio = 1 << 4 }, @@ -291,6 +327,18 @@ static struct platform_t __initdata platforms[] = { { .name = "ses_orange", .gpio = 1 << 3, .polarity = REVERSE }, }, }, + [WRT160NV3] = { + .name = "Linksys WRT160N V3", + .buttons = { + { .name = "reset", .gpio = 1 << 6 }, + { .name = "ses", .gpio = 1 << 5 }, + }, + .leds = { + { .name = "power", .gpio = 1 << 1, .polarity = NORMAL }, + { .name = "ses_blue", .gpio = 1 << 4, .polarity = REVERSE }, + { .name = "ses_orange", .gpio = 1 << 2, .polarity = REVERSE }, + }, + }, [WRT300NV11] = { .name = "Linksys WRT300N V1.1", .buttons = { @@ -364,6 +412,65 @@ static struct platform_t __initdata platforms[] = { { .name = "ses_blue", .gpio = 1 << 9, .polarity = REVERSE }, // WiFi protected setup LED blue }, }, + [WRT610NV2] = { + .name = "Linksys WRT610N V2", + .buttons = { + { .name = "reset", .gpio = 1 << 6 }, + { .name = "ses", .gpio = 1 << 4 }, + }, + .leds = { + { .name = "power", .gpio = 1 << 5, .polarity = NORMAL }, // Power LED + { .name = "usb", .gpio = 1 << 7, .polarity = NORMAL }, // USB LED + { .name = "ses_amber", .gpio = 1 << 0, .polarity = REVERSE }, // WiFi protected setup LED amber + { .name = "ses_blue", .gpio = 1 << 3, .polarity = REVERSE }, // WiFi protected setup LED blue + { .name = "wlan", .gpio = 1 << 1, .polarity = NORMAL }, // Wireless LED + }, + }, + /* same hardware as WRT160NV3 and Cisco Valet M10V1, but different board detection, combine? */ + [E1000V1] = { + .name = "Linksys E1000 V1", + .buttons = { + { .name = "reset", .gpio = 1 << 6 }, + { .name = "wps", .gpio = 1 << 5 }, /* nvram get gpio5=wps_button */ + }, + .leds = { + /** turns on leds for all ethernet ports (wan too) + * this also disconnects some, or maybe all, ethernet ports + * 1: leds work normally + * 0: all lit all the time */ + /* nvram get gpio3=robo_reset */ + { .name = "wlan", .gpio = 1 << 0, .polarity = NORMAL }, + { .name = "power", .gpio = 1 << 1, .polarity = NORMAL }, + { .name = "ses_blue", .gpio = 1 << 4, .polarity = REVERSE }, /* nvram get gpio4=wps_led */ + { .name = "ses_orange", .gpio = 1 << 2, .polarity = REVERSE }, /* nvram get gpio2=wps_status_led */ + }, + }, + [E3000V1] = { + .name = "Linksys E3000 V1", + .buttons = { + { .name = "reset", .gpio = 1 << 6 }, + { .name = "ses", .gpio = 1 << 4 }, + }, + .leds = { + { .name = "power", .gpio = 1 << 5, .polarity = NORMAL }, // Power LED + { .name = "usb", .gpio = 1 << 7, .polarity = NORMAL }, // USB LED + { .name = "ses_amber", .gpio = 1 << 0, .polarity = REVERSE }, // WiFi protected setup LED amber + { .name = "ses_blue", .gpio = 1 << 3, .polarity = REVERSE }, // WiFi protected setup LED blue + { .name = "wlan", .gpio = 1 << 1, .polarity = NORMAL }, // Wireless LED + }, + }, + [E3200V1] = { + .name = "Linksys E3200 V1", + .buttons = { + /* { .name = "switch", .gpio = 1 << 4 },*/ /* nvram get gpio4=robo_reset */ + { .name = "reset", .gpio = 1 << 5 }, /* nvram get reset_gpio=5 */ + { .name = "wps", .gpio = 1 << 8 }, /* nvram get gpio8=wps_button */ + /* { .name = "wombo", .gpio = 1 << 23 },*/ /* nvram get gpio23=wombo_reset - wireless on motherboard */ + }, + .leds = { + { .name = "power", .gpio = 1 << 3, .polarity = REVERSE }, /* Power LED */ + }, + }, /* Asus */ [WLHDD] = { .name = "ASUS WL-HDD", @@ -503,6 +610,17 @@ static struct platform_t __initdata platforms[] = { }, .platform_init = bcm4780_init, }, + [RTN16] = { + .name = "ASUS RT-N16", + .buttons = { + { .name = "reset", .gpio = 1 << 8 }, + { .name = "ses", .gpio = 1 << 5 }, + }, + .leds = { + { .name = "power", .gpio = 1 << 1, .polarity = REVERSE }, + { .name = "wlan", .gpio = 1 << 7, .polarity = NORMAL }, + }, + }, /* Buffalo */ [WHR_G54S] = { .name = "Buffalo WHR-G54S", @@ -749,6 +867,19 @@ static struct platform_t __initdata platforms[] = { { .name = "connected", .gpio = 1 << 0, .polarity = NORMAL }, }, }, + [BELKIN_F7D4301] = { + .name = "Belkin PlayMax F7D4301", + .buttons = { + { .name = "reset", .gpio = 1 << 6 }, + { .name = "wps", .gpio = 1 << 8 }, + }, + .leds = { + { .name = "power", .gpio = 1 << 11, .polarity = REVERSE }, + { .name = "wlan", .gpio = 1 << 13, .polarity = REVERSE }, + { .name = "led0", .gpio = 1 << 14, .polarity = REVERSE }, + { .name = "led1", .gpio = 1 << 15, .polarity = REVERSE }, + }, + }, /* Netgear */ [WGT634U] = { .name = "Netgear WGT634U", @@ -781,6 +912,44 @@ static struct platform_t __initdata platforms[] = { { .name = "connected", .gpio = 1 << 7, .polarity = NORMAL }, }, }, + [WNDR3400V1] = { + .name = "Netgear WNDR3400 V1", + .buttons = { + /* nvram get gpio5=robo_reset */ + { .name = "reset", .gpio = 1 << 4 }, + { .name = "wps", .gpio = 1 << 6 }, + { .name = "wlan", .gpio = 1 << 8 }, + }, + .leds = { + { .name = "wlan", .gpio = 0 << 0, .polarity = NORMAL }, + { .name = "connected", .gpio = 1 << 0, .polarity = NORMAL }, + { .name = "power", .gpio = 1 << 3, .polarity = NORMAL }, + { .name = "diag", .gpio = 1 << 7, .polarity = NORMAL }, + { .name = "usb", .gpio = 1 << 2, .polarity = REVERSE }, + }, + }, + [WNDR3700V3] = { + .name = "Netgear WNDR3700 V3", + .buttons = { + /* { .name = "usb", .gpio = 1 << 1 }, */ /* this button doesn't seem to exist. */ + { .name = "wlan", .gpio = 1 << 2 }, + { .name = "reset", .gpio = 1 << 3 }, + { .name = "wps", .gpio = 1 << 4 }, + /* { .name = "switch", .gpio = 1 << 5 },*/ /* nvram get gpio5=robo_reset */ + }, + .leds = { + { .name = "power", .gpio = (1 << 0) | GPIO_TYPE_SHIFT, .polarity = REVERSE }, + { .name = "diag", .gpio = (1 << 1) | GPIO_TYPE_SHIFT, .polarity = REVERSE }, + /* WAN LED doesn't respond to GPIO control. The switch is probably driving it. + * { .name = "wan", .gpio = (1 << 2) | GPIO_TYPE_SHIFT, .polarity = REVERSE }, + */ + { .name = "wlan2g", .gpio = (1 << 3) | GPIO_TYPE_SHIFT, .polarity = REVERSE }, + { .name = "wlan5g", .gpio = (1 << 4) | GPIO_TYPE_SHIFT, .polarity = REVERSE }, + { .name = "usb", .gpio = (1 << 5) | GPIO_TYPE_SHIFT, .polarity = REVERSE }, + { .name = "wps", .gpio = (1 << 6) | GPIO_TYPE_SHIFT, .polarity = REVERSE }, + { .name = "wlan", .gpio = (1 << 7) | GPIO_TYPE_SHIFT, .polarity = REVERSE }, + }, + }, /* Trendware */ [TEW411BRPP] = { .name = "Trendware TEW411BRP+", @@ -923,81 +1092,13 @@ static struct platform_t __initdata platforms[] = { }, }; -static struct platform_t __init *platform_detect(void) +static struct platform_t __init *platform_detect_legacy(void) { char *boardnum, *boardtype, *buf; if (strcmp(getvar("nvram_type"), "cfe") == 0) return &platforms[WGT634U]; - /* Look for a model identifier */ - - /* Based on "model_name" */ - if ((buf = nvram_get("model_name"))) { - if (!strcmp(buf, "DIR-130")) - return &platforms[DIR130]; - if (!strcmp(buf, "DIR-330")) - return &platforms[DIR330]; - } - - /* Based on "wsc_modelname */ - if ((buf = nvram_get("wsc_modelname"))) { - if (!strcmp(buf, "WRT610N")) - return &platforms[WRT610N]; - } - - /* Based on "model_no" */ - if ((buf = nvram_get("model_no"))) { - if (startswith(buf,"WL700")) /* WL700* */ - return &platforms[WL700GE]; - } - - /* Based on "hardware_version" */ - if ((buf = nvram_get("hardware_version"))) { - if (startswith(buf,"WL500GPV2-")) /* WL500GPV2-* */ - return &platforms[WL500GPV2]; - if (startswith(buf,"WL520GC-")) /* WL520GU-* */ - return &platforms[WL520GC]; - if (startswith(buf,"WL520GU-")) /* WL520GU-* */ - return &platforms[WL520GU]; - if (startswith(buf,"WL330GE-")) /* WL330GE-* */ - return &platforms[WL330GE]; - } - - /* Based on "ModelId" */ - if ((buf = nvram_get("ModelId"))) { - if (!strcmp(buf, "WR850GP")) - return &platforms[WR850GP]; - if (!strcmp(buf, "WR850G")) - return &platforms[WR850GV2V3]; - if (!strcmp(buf, "WX-5565") && !strcmp(getvar("boardtype"),"bcm94710ap")) - return &platforms[TM2300]; /* Dell TrueMobile 2300 */ - if (startswith(buf,"WE800G")) /* WE800G* */ - return &platforms[WE800G]; - } - - /* Buffalo */ - if ((buf = (nvram_get("melco_id") ?: nvram_get("buffalo_id")))) { - /* Buffalo hardware, check id for specific hardware matches */ - if (!strcmp(buf, "29bb0332")) - return &platforms[WBR2_G54]; - if (!strcmp(buf, "29129")) - return &platforms[WLA2_G54L]; - if (!strcmp(buf, "30189")) - return &platforms[WHR_HP_G54]; - if (!strcmp(buf, "32093")) - return &platforms[WHR_G125]; - if (!strcmp(buf, "30182")) - return &platforms[WHR_G54S]; - if (!strcmp(buf, "290441dd")) - return &platforms[WHR2_A54G54]; - if (!strcmp(buf, "31120")) - return &platforms[WZR_G300N]; - if (!strcmp(buf, "30083")) - return &platforms[WZR_RS_G54]; - if (!strcmp(buf, "30103")) - return &platforms[WZR_RS_G54HP]; - } /* no easy model number, attempt to guess */ boardnum = getvar("boardnum"); @@ -1014,24 +1115,15 @@ static struct platform_t __init *platform_detect(void) if (startswith(getvar("pmon_ver"), "CFE")) { /* CFE based - newer hardware */ if (!strcmp(boardnum, "42")) { /* Linksys */ - if (!strcmp(boardtype, "0x478") && !strcmp(getvar("boot_hw_model"), "WRT300N") && !strcmp(getvar("boot_hw_ver"), "1.1")) - return &platforms[WRT300NV11]; - if (!strcmp(boardtype, "0x478") && !strcmp(getvar("cardbus"), "1")) return &platforms[WRT350N]; if (!strcmp(boardtype, "0x0101") && !strcmp(getvar("boot_ver"), "v3.6")) return &platforms[WRT54G3G]; - if (!strcmp(boardtype, "0x042f") && !strcmp(getvar("model_name"), "WRT54G3GV2-VF")) - return &platforms[WRT54G3GV2_VF]; - if (!strcmp(getvar("et1phyaddr"),"5") && !strcmp(getvar("et1mdcport"), "1")) return &platforms[WRTSL54GS]; - if (!strcmp(boardtype, "0x0472")) - return &platforms[WRT160N]; - /* default to WRT54G */ return &platforms[WRT54G]; } @@ -1048,9 +1140,7 @@ static struct platform_t __init *platform_detect(void) } if (!strcmp(boardnum, "45")) { /* ASUS */ - if (!strcmp(boardtype,"0x042f")) - return &platforms[WL500GP]; - else if (!strcmp(boardtype,"0x0472")) + if (!strcmp(boardtype,"0x0472")) return &platforms[WL500W]; else if (!strcmp(boardtype,"0x467")) return &platforms[WL320GE]; @@ -1159,6 +1249,138 @@ static struct platform_t __init *platform_detect(void) return NULL; } +static struct platform_t __init *platform_detect(void) +{ + enum bcm47xx_board board; + const char *board_name; + + + board = bcm47xx_board_get(); + board_name = bcm47xx_board_get_name(); + if (board != BCM47XX_BOARD_UNKNOWN && board != BCM47XX_BOARD_NON) + printk(MODULE_NAME ": kernel found a \"%s\"\n", board_name); + + switch(board) { + case BCM47XX_BOARD_ASUS_RTN16: + return &platforms[RTN16]; + case BCM47XX_BOARD_ASUS_WL330GE: + return &platforms[WL330GE]; + case BCM47XX_BOARD_ASUS_WL500GPV1: + return &platforms[WL500GP]; + case BCM47XX_BOARD_ASUS_WL500GPV2: + return &platforms[WL500GPV2]; + case BCM47XX_BOARD_ASUS_WL520GC: + return &platforms[WL520GC]; + case BCM47XX_BOARD_ASUS_WL520GU: + return &platforms[WL520GU]; + case BCM47XX_BOARD_ASUS_WL700GE: + return &platforms[WL700GE]; + case BCM47XX_BOARD_BELKIN_F7D4301: + return &platforms[BELKIN_F7D4301]; + case BCM47XX_BOARD_BUFFALO_WBR2_G54: + return &platforms[WBR2_G54]; + case BCM47XX_BOARD_BUFFALO_WHR2_A54G54: + return &platforms[WHR2_A54G54]; + case BCM47XX_BOARD_BUFFALO_WHR_G125: + return &platforms[WHR_G125]; + case BCM47XX_BOARD_BUFFALO_WHR_G54S: + return &platforms[WHR_G54S]; + case BCM47XX_BOARD_BUFFALO_WHR_HP_G54: + return &platforms[WHR_HP_G54]; + case BCM47XX_BOARD_BUFFALO_WLA2_G54L: + return &platforms[WLA2_G54L]; + case BCM47XX_BOARD_BUFFALO_WZR_G300N: + return &platforms[WZR_G300N]; + case BCM47XX_BOARD_BUFFALO_WZR_RS_G54: + return &platforms[WZR_RS_G54]; + case BCM47XX_BOARD_BUFFALO_WZR_RS_G54HP: + return &platforms[WZR_RS_G54HP]; + case BCM47XX_BOARD_DELL_TM2300: + return &platforms[TM2300]; + case BCM47XX_BOARD_DLINK_DIR130: + return &platforms[DIR130]; + case BCM47XX_BOARD_DLINK_DIR330: + return &platforms[DIR330]; + case BCM47XX_BOARD_LINKSYS_E1000V1: + return &platforms[E1000V1]; + case BCM47XX_BOARD_LINKSYS_E3000V1: + return &platforms[E3000V1]; + case BCM47XX_BOARD_LINKSYS_E3200V1: + return &platforms[E3200V1]; + case BCM47XX_BOARD_LINKSYS_WRT150NV1: + return &platforms[WRT150NV1]; + case BCM47XX_BOARD_LINKSYS_WRT150NV11: + return &platforms[WRT150NV11]; + case BCM47XX_BOARD_LINKSYS_WRT160NV1: + return &platforms[WRT160NV1]; + case BCM47XX_BOARD_LINKSYS_WRT160NV3: + return &platforms[WRT160NV3]; + case BCM47XX_BOARD_LINKSYS_WRT300NV11: + return &platforms[WRT300NV11]; + case BCM47XX_BOARD_LINKSYS_WRT54G3GV2: + return &platforms[WRT54G3GV2_VF]; + case BCM47XX_BOARD_LINKSYS_WRT610NV1: + return &platforms[WRT610N]; + case BCM47XX_BOARD_LINKSYS_WRT610NV2: + return &platforms[WRT610NV2]; + case BCM47XX_BOARD_MOTOROLA_WE800G: + return &platforms[WE800G]; + case BCM47XX_BOARD_MOTOROLA_WR850GP: + return &platforms[WR850GP]; + case BCM47XX_BOARD_MOTOROLA_WR850GV2V3: + return &platforms[WR850GV2V3]; + case BCM47XX_BOARD_NETGEAR_WNDR3400V1: + return &platforms[WNDR3400V1]; + case BCM47XX_BOARD_NETGEAR_WNDR3700V3: + return &platforms[WNDR3700V3]; + case BCM47XX_BOARD_UNKNOWN: + case BCM47XX_BOARD_NON: + printk(MODULE_NAME ": unknown board found, try legacy detect\n"); + printk(MODULE_NAME ": please open a ticket at https://dev.openwrt.org and attach the complete nvram\n"); + return platform_detect_legacy(); + default: + printk(MODULE_NAME ": board was detected as \"%s\", but not gpio configuration available\n", board_name); + printk(MODULE_NAME ": now trying legacy detect\n"); + return platform_detect_legacy(); + } +} + +static inline void ssb_maskset32(struct ssb_device *dev, + u16 offset, u32 mask, u32 set) +{ + ssb_write32(dev, offset, (ssb_read32(dev, offset) & mask) | set); +} + +static void gpio_set_irqenable(int enabled, irqreturn_t (*handler)(int, void *)) +{ + int irq; + + irq = gpio_to_irq(0); + if (irq == -EINVAL) return; + + if (enabled) { + if (request_irq(irq, handler, IRQF_SHARED, "gpio", handler)) + return; + } else { + free_irq(irq, handler); + } + + switch (bcm47xx_bus_type) { +#ifdef CONFIG_BCM47XX_SSB + case BCM47XX_BUS_TYPE_SSB: + if (bcm47xx_bus.ssb.chipco.dev) + ssb_maskset32(bcm47xx_bus.ssb.chipco.dev, SSB_CHIPCO_IRQMASK, ~SSB_CHIPCO_IRQ_GPIO, (enabled ? SSB_CHIPCO_IRQ_GPIO : 0)); + break; +#endif +#ifdef CONFIG_BCM47XX_BCMA + case BCM47XX_BUS_TYPE_BCMA: + if (bcm47xx_bus.bcma.bus.drv_cc.core) + bcma_maskset32(bcm47xx_bus.bcma.bus.drv_cc.core, BCMA_CC_IRQMASK, ~BCMA_CC_IRQ_GPIO, (enabled ? BCMA_CC_IRQ_GPIO : 0)); + break; +#endif + } +} + static void register_buttons(struct button_t *b) { for (; b->name; b++) @@ -1166,18 +1388,18 @@ static void register_buttons(struct button_t *b) platform.button_mask &= ~gpiomask; - ssb_gpio_outen(&ssb_bcm47xx, platform.button_mask, 0); - ssb_gpio_control(&ssb_bcm47xx, platform.button_mask, 0); - platform.button_polarity = ssb_gpio_in(&ssb_bcm47xx, ~0) & platform.button_mask; - ssb_gpio_polarity(&ssb_bcm47xx, platform.button_mask, platform.button_polarity); - ssb_gpio_intmask(&ssb_bcm47xx, platform.button_mask, platform.button_mask); + bcm47xx_gpio_outen(platform.button_mask, 0); + bcm47xx_gpio_control(platform.button_mask, 0); + platform.button_polarity = bcm47xx_gpio_in(~0) & platform.button_mask; + bcm47xx_gpio_polarity(platform.button_mask, platform.button_polarity); + bcm47xx_gpio_intmask(platform.button_mask, platform.button_mask); gpio_set_irqenable(1, button_handler); } static void unregister_buttons(struct button_t *b) { - ssb_gpio_intmask(&ssb_bcm47xx, platform.button_mask, 0); + bcm47xx_gpio_intmask(platform.button_mask, 0); gpio_set_irqenable(0, button_handler); } @@ -1237,12 +1459,12 @@ static irqreturn_t button_handler(int irq, void *dev_id) struct button_t *b; u32 in, changed; - in = ssb_gpio_in(&ssb_bcm47xx, ~0) & platform.button_mask; - ssb_gpio_polarity(&ssb_bcm47xx, platform.button_mask, in); + in = bcm47xx_gpio_in(~0) & platform.button_mask; + bcm47xx_gpio_polarity(platform.button_mask, in); changed = platform.button_polarity ^ in; platform.button_polarity = in; - changed &= ~ssb_gpio_outen(&ssb_bcm47xx, 0, 0); + changed &= ~bcm47xx_gpio_outen(0, 0); for (b = platform.buttons; b->name; b++) { struct event_t *event; @@ -1279,13 +1501,23 @@ static void register_leds(struct led_t *l) if (l->gpio & gpiomask) continue; - if (l->gpio & GPIO_TYPE_EXTIF) { + switch (l->gpio & GPIO_TYPE_MASK) { + case GPIO_TYPE_EXTIF: l->state = 0; set_led_extif(l); - } else { + break; + case GPIO_TYPE_SHIFT: + mask |= (SHIFTREG_DATA | SHIFTREG_CLK); + oe_mask |= (SHIFTREG_DATA | SHIFTREG_CLK); + l->state = (l->polarity != NORMAL); + set_led_shift(l); + break; + case GPIO_TYPE_NORMAL: + default: if (l->polarity != INPUT) oe_mask |= l->gpio; mask |= l->gpio; val |= (l->polarity == NORMAL)?0:l->gpio; + break; } if (l->polarity == INPUT) continue; @@ -1298,10 +1530,10 @@ static void register_leds(struct led_t *l) } } - ssb_gpio_outen(&ssb_bcm47xx, mask, oe_mask); - ssb_gpio_control(&ssb_bcm47xx, mask, 0); - ssb_gpio_out(&ssb_bcm47xx, mask, val); - ssb_gpio_intmask(&ssb_bcm47xx, mask, 0); + bcm47xx_gpio_outen(mask, oe_mask); + bcm47xx_gpio_control(mask, 0); + bcm47xx_gpio_out(mask, val); + bcm47xx_gpio_intmask(mask, 0); } static void unregister_leds(struct led_t *l) @@ -1314,33 +1546,85 @@ static void unregister_leds(struct led_t *l) static void set_led_extif(struct led_t *led) { - gpio_set_extif(led->gpio, led->state); + volatile u8 *addr = (volatile u8 *) KSEG1ADDR(EXTIF_UART) + (led->gpio & ~GPIO_TYPE_MASK); + if (led->state) + *addr = 0xFF; + else + *addr; +} + +/* + * This should be extended to allow the platform to specify the pins and width + * of the shift register. They're hardcoded for now because only the WNDR3700v3 + * uses it. + */ +static void shiftreg_output(unsigned int val) +{ + unsigned int mask; + + bcm47xx_gpio_out(SHIFTREG_DATA, SHIFTREG_DATA); /* init off, pull high */ + bcm47xx_gpio_out(SHIFTREG_CLK, 0); /* init reset */ + + /* shift 8 times */ + for(mask = 1 << (SHIFTREG_MAX_BITS-1); mask; mask >>= 1) + { + bcm47xx_gpio_out(SHIFTREG_DATA, (val & mask) ? SHIFTREG_DATA : 0); + bcm47xx_gpio_out(SHIFTREG_CLK, SHIFTREG_CLK); /* pull high to trigger */ + bcm47xx_gpio_out(SHIFTREG_CLK, 0); /* reset to low */ + } +} + +static void set_led_shift(struct led_t *led) +{ + static u32 shiftreg = 0; + u32 old = shiftreg; + u32 pin = (led->gpio & ~GPIO_TYPE_MASK); + + if (led->state) { + shiftreg |= pin; + } else { + shiftreg &= ~pin; + } + + /* Clock the bits out. */ + if (shiftreg != old) { + shiftreg_output(shiftreg); + } } + static void led_flash(unsigned long dummy) { struct led_t *l; u32 mask = 0; u8 extif_blink = 0; for (l = platform.leds; l->name; l++) { - if (l->flash) { - if (l->gpio & GPIO_TYPE_EXTIF) { - extif_blink = 1; - l->state = !l->state; - set_led_extif(l); - } else { - mask |= l->gpio; - } + if (!l->flash) continue; + switch (l->gpio & GPIO_TYPE_MASK) { + case GPIO_TYPE_EXTIF: + extif_blink = 1; + l->state = !l->state; + set_led_extif(l); + break; + case GPIO_TYPE_SHIFT: + extif_blink = 1; + l->state = !l->state; + set_led_shift(l); + break; + case GPIO_TYPE_NORMAL: + default: + mask |= l->gpio; + break; } } mask &= ~gpiomask; if (mask) { - u32 val = ~ssb_gpio_in(&ssb_bcm47xx, ~0); + u32 val = ~bcm47xx_gpio_in(~0); - ssb_gpio_outen(&ssb_bcm47xx, mask, mask); - ssb_gpio_control(&ssb_bcm47xx, mask, 0); - ssb_gpio_out(&ssb_bcm47xx, mask, val); + bcm47xx_gpio_outen(mask, mask); + bcm47xx_gpio_control(mask, 0); + bcm47xx_gpio_out(mask, val); } if (mask || extif_blink) { mod_timer(&led_timer, jiffies + FLASH_TIME); @@ -1361,16 +1645,14 @@ static ssize_t diag_proc_read(struct file *file, char *buf, size_t count, loff_t switch (handler->type) { case PROC_LED: { struct led_t * led = (struct led_t *) handler->ptr; + u8 p = (led->polarity == NORMAL ? 0 : 1); if (led->flash) { len = sprintf(page, "f\n"); + } else if ((led->gpio & GPIO_TYPE_MASK) != GPIO_TYPE_NORMAL) { + len = sprintf(page, "%d\n", ((led->state ^ p) ? 1 : 0)); } else { - if (led->gpio & GPIO_TYPE_EXTIF) { - len = sprintf(page, "%d\n", led->state); - } else { - u32 in = (ssb_gpio_in(&ssb_bcm47xx, ~0) & led->gpio ? 1 : 0); - u8 p = (led->polarity == NORMAL ? 0 : 1); - len = sprintf(page, "%d\n", ((in ^ p) ? 1 : 0)); - } + u32 in = (bcm47xx_gpio_in(~0) & led->gpio ? 1 : 0); + len = sprintf(page, "%d\n", ((in ^ p) ? 1 : 0)); } break; } @@ -1427,13 +1709,16 @@ static ssize_t diag_proc_write(struct file *file, const char *buf, size_t count, led_flash(0); } else { led->flash = 0; - if (led->gpio & GPIO_TYPE_EXTIF) { + if ((led->gpio & GPIO_TYPE_MASK) == GPIO_TYPE_EXTIF) { led->state = p ^ ((page[0] == '1') ? 1 : 0); set_led_extif(led); + } else if ((led->gpio & GPIO_TYPE_MASK) == GPIO_TYPE_SHIFT) { + led->state = p ^ ((page[0] == '1') ? 1 : 0); + set_led_shift(led); } else { - ssb_gpio_outen(&ssb_bcm47xx, led->gpio, led->gpio); - ssb_gpio_control(&ssb_bcm47xx, led->gpio, 0); - ssb_gpio_out(&ssb_bcm47xx, led->gpio, ((p ^ (page[0] == '1')) ? led->gpio : 0)); + bcm47xx_gpio_outen(led->gpio, led->gpio); + bcm47xx_gpio_control(led->gpio, 0); + bcm47xx_gpio_out(led->gpio, ((p ^ (page[0] == '1')) ? led->gpio : 0)); } } break; @@ -1464,13 +1749,6 @@ static int __init diag_init(void) static struct proc_dir_entry *p; static struct platform_t *detected; -#ifdef CONFIG_BCM47XX_SSB - if (bcm47xx_active_bus_type != BCM47XX_BUS_TYPE_SSB) { - printk(MODULE_NAME ": bcma bus is not supported.\n"); - return -ENODEV; - } -#endif - detected = platform_detect(); if (!detected) { printk(MODULE_NAME ": Router model not detected.\n");