From ca7f9638d59b62454c660dd0342367b861764a80 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 28 Apr 2013 21:11:17 +0000 Subject: [PATCH] broadcom-diag: support for the WNDR3700v3 I recently picked up a WNDR3700 to put OpenWRT on, and only after tearing into the box did I find it was one of the v3 boards, with poor OpenWRT support. This patch should add the board detection and LED/button control to the broadcom-diag module, and should generate a netgear .chk image that the bootloader and stock firmware will accept. The changes to the broadcom-diag module are more than a few lines because the WNDR3700v3 is driving its LEDs through an HC164 8-bit shift register. Signed-off-by: Owen Kirby SVN-Revision: 36482 --- package/broadcom-diag/src/diag.c | 120 +++++++++++++++++++++++---- package/broadcom-diag/src/diag.h | 1 + package/broadcom-diag/src/gpio.h | 6 ++ target/linux/brcm47xx/image/Makefile | 1 + 4 files changed, 110 insertions(+), 18 deletions(-) diff --git a/package/broadcom-diag/src/diag.c b/package/broadcom-diag/src/diag.c index 168f81d77e..ccbaee2d26 100644 --- a/package/broadcom-diag/src/diag.c +++ b/package/broadcom-diag/src/diag.c @@ -123,6 +123,7 @@ enum { WNR834BV1, WNR834BV2, WNDR3400V1, + WNDR3700V3, /* Trendware */ TEW411BRPP, @@ -927,6 +928,28 @@ static struct platform_t __initdata platforms[] = { { .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+", @@ -1308,6 +1331,8 @@ static struct platform_t __init *platform_detect(void) 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"); @@ -1476,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; @@ -1518,20 +1553,68 @@ static void set_led_extif(struct led_t *led) *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; } } @@ -1562,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 = (bcm47xx_gpio_in(~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; } @@ -1628,9 +1709,12 @@ 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 { bcm47xx_gpio_outen(led->gpio, led->gpio); bcm47xx_gpio_control(led->gpio, 0); diff --git a/package/broadcom-diag/src/diag.h b/package/broadcom-diag/src/diag.h index 698c376519..d9b5b006fe 100644 --- a/package/broadcom-diag/src/diag.h +++ b/package/broadcom-diag/src/diag.h @@ -104,6 +104,7 @@ static void register_leds(struct led_t *l); static void unregister_leds(struct led_t *l); static void set_led_extif(struct led_t *led); +static void set_led_shift(struct led_t *led); static void led_flash(unsigned long dummy); /* 2.4 compatibility */ diff --git a/package/broadcom-diag/src/gpio.h b/package/broadcom-diag/src/gpio.h index d0e3e06c8a..8bd3fe02f8 100644 --- a/package/broadcom-diag/src/gpio.h +++ b/package/broadcom-diag/src/gpio.h @@ -9,8 +9,14 @@ #define EXTIF_ADDR 0x1f000000 #define EXTIF_UART (EXTIF_ADDR + 0x00800000) +/* GPIO pins driving LEDs through a shift register */ +#define SHIFTREG_DATA (1 << 6) +#define SHIFTREG_CLK (1 << 7) +#define SHIFTREG_MAX_BITS 8 + #define GPIO_TYPE_NORMAL (0x0 << 24) #define GPIO_TYPE_EXTIF (0x1 << 24) +#define GPIO_TYPE_SHIFT (0x2 << 24) #define GPIO_TYPE_MASK (0xf << 24) #endif /* __DIAG_GPIO_H */ diff --git a/target/linux/brcm47xx/image/Makefile b/target/linux/brcm47xx/image/Makefile index 4043613c7f..09109573f7 100644 --- a/target/linux/brcm47xx/image/Makefile +++ b/target/linux/brcm47xx/image/Makefile @@ -140,6 +140,7 @@ define Image/Build $(call Image/Build/Chk,$(1),wndr3400_v1,U12H155T00_NETGEAR,2,$(patsubst jffs2-%,jffs2,$(1))) $(call Image/Build/Chk,$(1),wndr3400_v2,U12H187T00_NETGEAR,2,$(patsubst jffs2-%,jffs2,$(1))) # $(call Image/Build/Chk,$(1),wndr3400_vcna,U12H155T01_NETGEAR,2,$(patsubst jffs2-%,jffs2,$(1))) + $(call Image/Build/Chk,$(1),wndr3700_v3,U12H194T00_NETGEAR,2,$(patsubst jffs2-%,jffs2,$(1))) $(call Image/Build/Chk,$(1),wndr4000,U12H181T00_NETGEAR,2,$(patsubst jffs2-%,jffs2,$(1))) $(call Image/Build/Chk,$(1),wnr834b_v2,U12H081T00_NETGEAR,2,$(patsubst jffs2-%,jffs2,$(1))) $(call Image/Build/Chk,$(1),wnr2000v2,U12H114T00_NETGEAR,2,$(patsubst jffs2-%,jffs2,$(1))) -- 2.30.2