--- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -36,6 +36,7 @@ #include <linux/ssb/ssb.h> #include <linux/ssb/ssb_embedded.h> #include <linux/bcma/bcma_soc.h> +#include <linux/old_gpio_wdt.h> #include <asm/bootinfo.h> #include <asm/idle.h> #include <asm/prom.h> @@ -262,6 +263,33 @@ static struct fixed_phy_status bcm47xx_f .duplex = DUPLEX_FULL, }; +static struct gpio_wdt_platform_data gpio_wdt_data; + +static struct platform_device gpio_wdt_device = { + .name = "gpio-wdt", + .id = 0, + .dev = { + .platform_data = &gpio_wdt_data, + }, +}; + +static int __init bcm47xx_register_gpio_watchdog(void) +{ + enum bcm47xx_board board = bcm47xx_board_get(); + + switch (board) { + case BCM47XX_BOARD_HUAWEI_E970: + pr_info("bcm47xx: detected Huawei E970 or similar, starting early gpio_wdt timer\n"); + gpio_wdt_data.gpio = 7; + gpio_wdt_data.interval = HZ; + gpio_wdt_data.first_interval = HZ / 5; + return platform_device_register(&gpio_wdt_device); + default: + /* Nothing to do */ + return 0; + } +} + static int __init bcm47xx_register_bus_complete(void) { switch (bcm47xx_bus_type) { @@ -281,6 +309,7 @@ static int __init bcm47xx_register_bus_c bcm47xx_workarounds(); fixed_phy_add(PHY_POLL, 0, &bcm47xx_fixed_phy_status); + bcm47xx_register_gpio_watchdog(); return 0; } device_initcall(bcm47xx_register_bus_complete); --- a/arch/mips/configs/bcm47xx_defconfig +++ b/arch/mips/configs/bcm47xx_defconfig @@ -67,6 +67,7 @@ CONFIG_HW_RANDOM=y CONFIG_GPIO_SYSFS=y CONFIG_WATCHDOG=y CONFIG_BCM47XX_WDT=y +CONFIG_GPIO_WDT=y CONFIG_SSB_DEBUG=y CONFIG_SSB_DRIVER_GIGE=y CONFIG_BCMA_DRIVER_GMAC_CMN=y --- a/drivers/ssb/embedded.c +++ b/drivers/ssb/embedded.c @@ -34,11 +34,36 @@ int ssb_watchdog_timer_set(struct ssb_bu } EXPORT_SYMBOL(ssb_watchdog_timer_set); +#ifdef CONFIG_BCM47XX +#include <bcm47xx_board.h> + +static bool ssb_watchdog_supported(void) +{ + enum bcm47xx_board board = bcm47xx_board_get(); + + /* The Huawei E970 has a hardware watchdog using a GPIO */ + switch (board) { + case BCM47XX_BOARD_HUAWEI_E970: + return false; + default: + return true; + } +} +#else +static bool ssb_watchdog_supported(void) +{ + return true; +} +#endif + int ssb_watchdog_register(struct ssb_bus *bus) { struct bcm47xx_wdt wdt = {}; struct platform_device *pdev; + if (!ssb_watchdog_supported()) + return 0; + if (ssb_chipco_available(&bus->chipco)) { wdt.driver_data = &bus->chipco; wdt.timer_set = ssb_chipco_watchdog_timer_set_wdt;