diff options
Diffstat (limited to 'arch/mips/bcm47xx')
| -rw-r--r-- | arch/mips/bcm47xx/Kconfig | 4 | ||||
| -rw-r--r-- | arch/mips/bcm47xx/Makefile | 2 | ||||
| -rw-r--r-- | arch/mips/bcm47xx/bcm47xx_private.h | 15 | ||||
| -rw-r--r-- | arch/mips/bcm47xx/board.c | 335 | ||||
| -rw-r--r-- | arch/mips/bcm47xx/buttons.c | 562 | ||||
| -rw-r--r-- | arch/mips/bcm47xx/irq.c | 25 | ||||
| -rw-r--r-- | arch/mips/bcm47xx/leds.c | 591 | ||||
| -rw-r--r-- | arch/mips/bcm47xx/nvram.c | 23 | ||||
| -rw-r--r-- | arch/mips/bcm47xx/prom.c | 127 | ||||
| -rw-r--r-- | arch/mips/bcm47xx/serial.c | 6 | ||||
| -rw-r--r-- | arch/mips/bcm47xx/setup.c | 50 | ||||
| -rw-r--r-- | arch/mips/bcm47xx/sprom.c | 19 | ||||
| -rw-r--r-- | arch/mips/bcm47xx/time.c | 23 | ||||
| -rw-r--r-- | arch/mips/bcm47xx/wgt634u.c | 174 | ||||
| -rw-r--r-- | arch/mips/bcm47xx/workarounds.c | 31 | 
15 files changed, 1700 insertions, 287 deletions
diff --git a/arch/mips/bcm47xx/Kconfig b/arch/mips/bcm47xx/Kconfig index 2b8b118398c..09cb6f7aa3d 100644 --- a/arch/mips/bcm47xx/Kconfig +++ b/arch/mips/bcm47xx/Kconfig @@ -2,6 +2,7 @@ if BCM47XX  config BCM47XX_SSB  	bool "SSB Support for Broadcom BCM47XX" +	select SYS_HAS_CPU_BMIPS32_3300  	select SSB  	select SSB_DRIVER_MIPS  	select SSB_DRIVER_EXTIF @@ -11,6 +12,7 @@ config BCM47XX_SSB  	select SSB_PCICORE_HOSTMODE if PCI  	select SSB_DRIVER_GPIO  	select GPIOLIB +	select LEDS_GPIO_REGISTER  	default y  	help  	 Add support for old Broadcom BCM47xx boards with Sonics Silicon Backplane support. @@ -20,6 +22,7 @@ config BCM47XX_SSB  config BCM47XX_BCMA  	bool "BCMA Support for Broadcom BCM47XX"  	select SYS_HAS_CPU_MIPS32_R2 +	select CPU_MIPSR2_IRQ_VI  	select BCMA  	select BCMA_HOST_SOC  	select BCMA_DRIVER_MIPS @@ -27,6 +30,7 @@ config BCM47XX_BCMA  	select BCMA_DRIVER_PCI_HOSTMODE if PCI  	select BCMA_DRIVER_GPIO  	select GPIOLIB +	select LEDS_GPIO_REGISTER  	default y  	help  	 Add support for new Broadcom BCM47xx boards with Broadcom specific Advanced Microcontroller Bus. diff --git a/arch/mips/bcm47xx/Makefile b/arch/mips/bcm47xx/Makefile index f3bf6d5bfb9..d58c51b5e50 100644 --- a/arch/mips/bcm47xx/Makefile +++ b/arch/mips/bcm47xx/Makefile @@ -4,4 +4,4 @@  #  obj-y				+= irq.o nvram.o prom.o serial.o setup.o time.o sprom.o -obj-$(CONFIG_BCM47XX_SSB)	+= wgt634u.o +obj-y				+= board.o buttons.o leds.o workarounds.o diff --git a/arch/mips/bcm47xx/bcm47xx_private.h b/arch/mips/bcm47xx/bcm47xx_private.h new file mode 100644 index 00000000000..0194c3b9a72 --- /dev/null +++ b/arch/mips/bcm47xx/bcm47xx_private.h @@ -0,0 +1,15 @@ +#ifndef LINUX_BCM47XX_PRIVATE_H_ +#define LINUX_BCM47XX_PRIVATE_H_ + +#include <linux/kernel.h> + +/* buttons.c */ +int __init bcm47xx_buttons_register(void); + +/* leds.c */ +void __init bcm47xx_leds_register(void); + +/* workarounds.c */ +void __init bcm47xx_workarounds(void); + +#endif diff --git a/arch/mips/bcm47xx/board.c b/arch/mips/bcm47xx/board.c new file mode 100644 index 00000000000..44ab1be68c3 --- /dev/null +++ b/arch/mips/bcm47xx/board.c @@ -0,0 +1,335 @@ +#include <linux/errno.h> +#include <linux/export.h> +#include <linux/string.h> +#include <bcm47xx_board.h> +#include <bcm47xx_nvram.h> + +struct bcm47xx_board_type { +	const enum bcm47xx_board board; +	const char *name; +}; + +struct bcm47xx_board_type_list1 { +	struct bcm47xx_board_type board; +	const char *value1; +}; + +struct bcm47xx_board_type_list2 { +	struct bcm47xx_board_type board; +	const char *value1; +	const char *value2; +}; + +struct bcm47xx_board_type_list3 { +	struct bcm47xx_board_type board; +	const char *value1; +	const char *value2; +	const char *value3; +}; + +struct bcm47xx_board_store { +	enum bcm47xx_board board; +	char name[BCM47XX_BOARD_MAX_NAME]; +}; + +/* model_name */ +static const +struct bcm47xx_board_type_list1 bcm47xx_board_list_model_name[] __initconst = { +	{{BCM47XX_BOARD_DLINK_DIR130, "D-Link DIR-130"}, "DIR-130"}, +	{{BCM47XX_BOARD_DLINK_DIR330, "D-Link DIR-330"}, "DIR-330"}, +	{ {0}, NULL}, +}; + +/* model_no */ +static const +struct bcm47xx_board_type_list1 bcm47xx_board_list_model_no[] __initconst = { +	{{BCM47XX_BOARD_ASUS_WL700GE, "Asus WL700"}, "WL700"}, +	{ {0}, NULL}, +}; + +/* machine_name */ +static const +struct bcm47xx_board_type_list1 bcm47xx_board_list_machine_name[] __initconst = { +	{{BCM47XX_BOARD_LINKSYS_WRTSL54GS, "Linksys WRTSL54GS"}, "WRTSL54GS"}, +	{ {0}, NULL}, +}; + +/* hardware_version */ +static const +struct bcm47xx_board_type_list1 bcm47xx_board_list_hardware_version[] __initconst = { +	{{BCM47XX_BOARD_ASUS_RTN10U, "Asus RT-N10U"}, "RTN10U"}, +	{{BCM47XX_BOARD_ASUS_RTN12, "Asus RT-N12"}, "RT-N12"}, +	{{BCM47XX_BOARD_ASUS_RTN12B1, "Asus RT-N12B1"}, "RTN12B1"}, +	{{BCM47XX_BOARD_ASUS_RTN12C1, "Asus RT-N12C1"}, "RTN12C1"}, +	{{BCM47XX_BOARD_ASUS_RTN12D1, "Asus RT-N12D1"}, "RTN12D1"}, +	{{BCM47XX_BOARD_ASUS_RTN12HP, "Asus RT-N12HP"}, "RTN12HP"}, +	{{BCM47XX_BOARD_ASUS_RTN16, "Asus RT-N16"}, "RT-N16-"}, +	{{BCM47XX_BOARD_ASUS_WL320GE, "Asus WL320GE"}, "WL320G-"}, +	{{BCM47XX_BOARD_ASUS_WL330GE, "Asus WL330GE"}, "WL330GE-"}, +	{{BCM47XX_BOARD_ASUS_WL500GD, "Asus WL500GD"}, "WL500gd-"}, +	{{BCM47XX_BOARD_ASUS_WL500GPV1, "Asus WL500GP V1"}, "WL500gp-"}, +	{{BCM47XX_BOARD_ASUS_WL500GPV2, "Asus WL500GP V2"}, "WL500GPV2-"}, +	{{BCM47XX_BOARD_ASUS_WL500W, "Asus WL500W"}, "WL500gW-"}, +	{{BCM47XX_BOARD_ASUS_WL520GC, "Asus WL520GC"}, "WL520GC-"}, +	{{BCM47XX_BOARD_ASUS_WL520GU, "Asus WL520GU"}, "WL520GU-"}, +	{{BCM47XX_BOARD_BELKIN_F7D3301, "Belkin F7D3301"}, "F7D3301"}, +	{{BCM47XX_BOARD_BELKIN_F7D3302, "Belkin F7D3302"}, "F7D3302"}, +	{{BCM47XX_BOARD_BELKIN_F7D4301, "Belkin F7D4301"}, "F7D4301"}, +	{{BCM47XX_BOARD_BELKIN_F7D4302, "Belkin F7D4302"}, "F7D4302"}, +	{{BCM47XX_BOARD_BELKIN_F7D4401, "Belkin F7D4401"}, "F7D4401"}, +	{ {0}, NULL}, +}; + +/* productid */ +static const +struct bcm47xx_board_type_list1 bcm47xx_board_list_productid[] __initconst = { +	{{BCM47XX_BOARD_ASUS_RTAC66U, "Asus RT-AC66U"}, "RT-AC66U"}, +	{{BCM47XX_BOARD_ASUS_RTN10, "Asus RT-N10"}, "RT-N10"}, +	{{BCM47XX_BOARD_ASUS_RTN10D, "Asus RT-N10D"}, "RT-N10D"}, +	{{BCM47XX_BOARD_ASUS_RTN15U, "Asus RT-N15U"}, "RT-N15U"}, +	{{BCM47XX_BOARD_ASUS_RTN16, "Asus RT-N16"}, "RT-N16"}, +	{{BCM47XX_BOARD_ASUS_RTN53, "Asus RT-N53"}, "RT-N53"}, +	{{BCM47XX_BOARD_ASUS_RTN66U, "Asus RT-N66U"}, "RT-N66U"}, +	{{BCM47XX_BOARD_ASUS_WL300G, "Asus WL300G"}, "WL300g"}, +	{{BCM47XX_BOARD_ASUS_WLHDD, "Asus WLHDD"}, "WLHDD"}, +	{ {0}, NULL}, +}; + +/* ModelId */ +static const +struct bcm47xx_board_type_list1 bcm47xx_board_list_ModelId[] __initconst = { +	{{BCM47XX_BOARD_DELL_TM2300, "Dell WX-5565"}, "WX-5565"}, +	{{BCM47XX_BOARD_MOTOROLA_WE800G, "Motorola WE800G"}, "WE800G"}, +	{{BCM47XX_BOARD_MOTOROLA_WR850GP, "Motorola WR850GP"}, "WR850GP"}, +	{{BCM47XX_BOARD_MOTOROLA_WR850GV2V3, "Motorola WR850G"}, "WR850G"}, +	{ {0}, NULL}, +}; + +/* melco_id or buf1falo_id */ +static const +struct bcm47xx_board_type_list1 bcm47xx_board_list_melco_id[] __initconst = { +	{{BCM47XX_BOARD_BUFFALO_WBR2_G54, "Buffalo WBR2-G54"}, "29bb0332"}, +	{{BCM47XX_BOARD_BUFFALO_WHR2_A54G54, "Buffalo WHR2-A54G54"}, "290441dd"}, +	{{BCM47XX_BOARD_BUFFALO_WHR_G125, "Buffalo WHR-G125"}, "32093"}, +	{{BCM47XX_BOARD_BUFFALO_WHR_G54S, "Buffalo WHR-G54S"}, "30182"}, +	{{BCM47XX_BOARD_BUFFALO_WHR_HP_G54, "Buffalo WHR-HP-G54"}, "30189"}, +	{{BCM47XX_BOARD_BUFFALO_WLA2_G54L, "Buffalo WLA2-G54L"}, "29129"}, +	{{BCM47XX_BOARD_BUFFALO_WZR_G300N, "Buffalo WZR-G300N"}, "31120"}, +	{{BCM47XX_BOARD_BUFFALO_WZR_RS_G54, "Buffalo WZR-RS-G54"}, "30083"}, +	{{BCM47XX_BOARD_BUFFALO_WZR_RS_G54HP, "Buffalo WZR-RS-G54HP"}, "30103"}, +	{ {0}, NULL}, +}; + +/* boot_hw_model, boot_hw_ver */ +static const +struct bcm47xx_board_type_list2 bcm47xx_board_list_boot_hw[] __initconst = { +	/* like WRT160N v3.0 */ +	{{BCM47XX_BOARD_CISCO_M10V1, "Cisco M10"}, "M10", "1.0"}, +	/* like WRT310N v2.0 */ +	{{BCM47XX_BOARD_CISCO_M20V1, "Cisco M20"}, "M20", "1.0"}, +	{{BCM47XX_BOARD_LINKSYS_E900V1, "Linksys E900 V1"}, "E900", "1.0"}, +	/* like WRT160N v3.0 */ +	{{BCM47XX_BOARD_LINKSYS_E1000V1, "Linksys E1000 V1"}, "E100", "1.0"}, +	{{BCM47XX_BOARD_LINKSYS_E1000V2, "Linksys E1000 V2"}, "E1000", "2.0"}, +	{{BCM47XX_BOARD_LINKSYS_E1000V21, "Linksys E1000 V2.1"}, "E1000", "2.1"}, +	{{BCM47XX_BOARD_LINKSYS_E1200V2, "Linksys E1200 V2"}, "E1200", "2.0"}, +	{{BCM47XX_BOARD_LINKSYS_E2000V1, "Linksys E2000 V1"}, "Linksys E2000", "1.0"}, +	/* like WRT610N v2.0 */ +	{{BCM47XX_BOARD_LINKSYS_E3000V1, "Linksys E3000 V1"}, "E300", "1.0"}, +	{{BCM47XX_BOARD_LINKSYS_E3200V1, "Linksys E3200 V1"}, "E3200", "1.0"}, +	{{BCM47XX_BOARD_LINKSYS_E4200V1, "Linksys E4200 V1"}, "E4200", "1.0"}, +	{{BCM47XX_BOARD_LINKSYS_WRT150NV11, "Linksys WRT150N V1.1"}, "WRT150N", "1.1"}, +	{{BCM47XX_BOARD_LINKSYS_WRT150NV1, "Linksys WRT150N V1"}, "WRT150N", "1"}, +	{{BCM47XX_BOARD_LINKSYS_WRT160NV1, "Linksys WRT160N V1"}, "WRT160N", "1.0"}, +	{{BCM47XX_BOARD_LINKSYS_WRT160NV3, "Linksys WRT160N V3"}, "WRT160N", "3.0"}, +	{{BCM47XX_BOARD_LINKSYS_WRT300NV11, "Linksys WRT300N V1.1"}, "WRT300N", "1.1"}, +	{{BCM47XX_BOARD_LINKSYS_WRT310NV1, "Linksys WRT310N V1"}, "WRT310N", "1.0"}, +	{{BCM47XX_BOARD_LINKSYS_WRT310NV2, "Linksys WRT310N V2"}, "WRT310N", "2.0"}, +	{{BCM47XX_BOARD_LINKSYS_WRT54G3GV2, "Linksys WRT54G3GV2-VF"}, "WRT54G3GV2-VF", "1.0"}, +	{{BCM47XX_BOARD_LINKSYS_WRT610NV1, "Linksys WRT610N V1"}, "WRT610N", "1.0"}, +	{{BCM47XX_BOARD_LINKSYS_WRT610NV2, "Linksys WRT610N V2"}, "WRT610N", "2.0"}, +	{ {0}, NULL}, +}; + +/* board_id */ +static const +struct bcm47xx_board_type_list1 bcm47xx_board_list_board_id[] __initconst = { +	{{BCM47XX_BOARD_NETGEAR_WGR614V8, "Netgear WGR614 V8"}, "U12H072T00_NETGEAR"}, +	{{BCM47XX_BOARD_NETGEAR_WGR614V9, "Netgear WGR614 V9"}, "U12H094T00_NETGEAR"}, +	{{BCM47XX_BOARD_NETGEAR_WNDR3300, "Netgear WNDR3300"}, "U12H093T00_NETGEAR"}, +	{{BCM47XX_BOARD_NETGEAR_WNDR3400V1, "Netgear WNDR3400 V1"}, "U12H155T00_NETGEAR"}, +	{{BCM47XX_BOARD_NETGEAR_WNDR3400V2, "Netgear WNDR3400 V2"}, "U12H187T00_NETGEAR"}, +	{{BCM47XX_BOARD_NETGEAR_WNDR3400VCNA, "Netgear WNDR3400 Vcna"}, "U12H155T01_NETGEAR"}, +	{{BCM47XX_BOARD_NETGEAR_WNDR3700V3, "Netgear WNDR3700 V3"}, "U12H194T00_NETGEAR"}, +	{{BCM47XX_BOARD_NETGEAR_WNDR4000, "Netgear WNDR4000"}, "U12H181T00_NETGEAR"}, +	{{BCM47XX_BOARD_NETGEAR_WNDR4500V1, "Netgear WNDR4500 V1"}, "U12H189T00_NETGEAR"}, +	{{BCM47XX_BOARD_NETGEAR_WNDR4500V2, "Netgear WNDR4500 V2"}, "U12H224T00_NETGEAR"}, +	{{BCM47XX_BOARD_NETGEAR_WNR2000, "Netgear WNR2000"}, "U12H114T00_NETGEAR"}, +	{{BCM47XX_BOARD_NETGEAR_WNR3500L, "Netgear WNR3500L"}, "U12H136T99_NETGEAR"}, +	{{BCM47XX_BOARD_NETGEAR_WNR3500U, "Netgear WNR3500U"}, "U12H136T00_NETGEAR"}, +	{{BCM47XX_BOARD_NETGEAR_WNR3500V2, "Netgear WNR3500 V2"}, "U12H127T00_NETGEAR"}, +	{{BCM47XX_BOARD_NETGEAR_WNR3500V2VC, "Netgear WNR3500 V2vc"}, "U12H127T70_NETGEAR"}, +	{{BCM47XX_BOARD_NETGEAR_WNR834BV2, "Netgear WNR834B V2"}, "U12H081T00_NETGEAR"}, +	{ {0}, NULL}, +}; + +/* boardtype, boardnum, boardrev */ +static const +struct bcm47xx_board_type_list3 bcm47xx_board_list_board[] __initconst = { +	{{BCM47XX_BOARD_HUAWEI_E970, "Huawei E970"}, "0x048e", "0x5347", "0x11"}, +	{{BCM47XX_BOARD_PHICOMM_M1, "Phicomm M1"}, "0x0590", "80", "0x1104"}, +	{{BCM47XX_BOARD_ZTE_H218N, "ZTE H218N"}, "0x053d", "1234", "0x1305"}, +	{{BCM47XX_BOARD_NETGEAR_WNR3500L, "Netgear WNR3500L"}, "0x04CF", "3500", "02"}, +	{{BCM47XX_BOARD_LINKSYS_WRT54G, "Linksys WRT54G/GS/GL"}, "0x0101", "42", "0x10"}, +	{{BCM47XX_BOARD_LINKSYS_WRT54G, "Linksys WRT54G/GS/GL"}, "0x0467", "42", "0x10"}, +	{{BCM47XX_BOARD_LINKSYS_WRT54G, "Linksys WRT54G/GS/GL"}, "0x0708", "42", "0x10"}, +	{ {0}, NULL}, +}; + +/* boardtype, boardrev */ +static const +struct bcm47xx_board_type_list2 bcm47xx_board_list_board_type_rev[] __initconst = { +	{{BCM47XX_BOARD_SIEMENS_SE505V2, "Siemens SE505 V2"}, "0x0101", "0x10"}, +	{ {0}, NULL}, +}; + +static const +struct bcm47xx_board_type bcm47xx_board_unknown[] __initconst = { +	{BCM47XX_BOARD_UNKNOWN, "Unknown Board"}, +}; + +static struct bcm47xx_board_store bcm47xx_board = {BCM47XX_BOARD_NO, "Unknown Board"}; + +static __init const struct bcm47xx_board_type *bcm47xx_board_get_nvram(void) +{ +	char buf1[30]; +	char buf2[30]; +	char buf3[30]; +	const struct bcm47xx_board_type_list1 *e1; +	const struct bcm47xx_board_type_list2 *e2; +	const struct bcm47xx_board_type_list3 *e3; + +	if (bcm47xx_nvram_getenv("model_name", buf1, sizeof(buf1)) >= 0) { +		for (e1 = bcm47xx_board_list_model_name; e1->value1; e1++) { +			if (!strcmp(buf1, e1->value1)) +				return &e1->board; +		} +	} + +	if (bcm47xx_nvram_getenv("model_no", buf1, sizeof(buf1)) >= 0) { +		for (e1 = bcm47xx_board_list_model_no; e1->value1; e1++) { +			if (strstarts(buf1, e1->value1)) +				return &e1->board; +		} +	} + +	if (bcm47xx_nvram_getenv("machine_name", buf1, sizeof(buf1)) >= 0) { +		for (e1 = bcm47xx_board_list_machine_name; e1->value1; e1++) { +			if (strstarts(buf1, e1->value1)) +				return &e1->board; +		} +	} + +	if (bcm47xx_nvram_getenv("hardware_version", buf1, sizeof(buf1)) >= 0) { +		for (e1 = bcm47xx_board_list_hardware_version; e1->value1; e1++) { +			if (strstarts(buf1, e1->value1)) +				return &e1->board; +		} +	} + +	if (bcm47xx_nvram_getenv("productid", buf1, sizeof(buf1)) >= 0) { +		for (e1 = bcm47xx_board_list_productid; e1->value1; e1++) { +			if (!strcmp(buf1, e1->value1)) +				return &e1->board; +		} +	} + +	if (bcm47xx_nvram_getenv("ModelId", buf1, sizeof(buf1)) >= 0) { +		for (e1 = bcm47xx_board_list_ModelId; e1->value1; e1++) { +			if (!strcmp(buf1, e1->value1)) +				return &e1->board; +		} +	} + +	if (bcm47xx_nvram_getenv("melco_id", buf1, sizeof(buf1)) >= 0 || +	    bcm47xx_nvram_getenv("buf1falo_id", buf1, sizeof(buf1)) >= 0) { +		/* buffalo hardware, check id for specific hardware matches */ +		for (e1 = bcm47xx_board_list_melco_id; e1->value1; e1++) { +			if (!strcmp(buf1, e1->value1)) +				return &e1->board; +		} +	} + +	if (bcm47xx_nvram_getenv("boot_hw_model", buf1, sizeof(buf1)) >= 0 && +	    bcm47xx_nvram_getenv("boot_hw_ver", buf2, sizeof(buf2)) >= 0) { +		for (e2 = bcm47xx_board_list_boot_hw; e2->value1; e2++) { +			if (!strcmp(buf1, e2->value1) && +			    !strcmp(buf2, e2->value2)) +				return &e2->board; +		} +	} + +	if (bcm47xx_nvram_getenv("board_id", buf1, sizeof(buf1)) >= 0) { +		for (e1 = bcm47xx_board_list_board_id; e1->value1; e1++) { +			if (!strcmp(buf1, e1->value1)) +				return &e1->board; +		} +	} + +	if (bcm47xx_nvram_getenv("boardtype", buf1, sizeof(buf1)) >= 0 && +	    bcm47xx_nvram_getenv("boardnum", buf2, sizeof(buf2)) >= 0 && +	    bcm47xx_nvram_getenv("boardrev", buf3, sizeof(buf3)) >= 0) { +		for (e3 = bcm47xx_board_list_board; e3->value1; e3++) { +			if (!strcmp(buf1, e3->value1) && +			    !strcmp(buf2, e3->value2) && +			    !strcmp(buf3, e3->value3)) +				return &e3->board; +		} +	} + +	if (bcm47xx_nvram_getenv("boardtype", buf1, sizeof(buf1)) >= 0 && +	    bcm47xx_nvram_getenv("boardrev", buf2, sizeof(buf2)) >= 0 && +	    bcm47xx_nvram_getenv("boardnum", buf3, sizeof(buf3)) ==  -ENOENT) { +		for (e2 = bcm47xx_board_list_board_type_rev; e2->value1; e2++) { +			if (!strcmp(buf1, e2->value1) && +			    !strcmp(buf2, e2->value2)) +				return &e2->board; +		} +	} +	return bcm47xx_board_unknown; +} + +void __init bcm47xx_board_detect(void) +{ +	int err; +	char buf[10]; +	const struct bcm47xx_board_type *board_detected; + +	if (bcm47xx_board.board != BCM47XX_BOARD_NO) +		return; + +	/* check if the nvram is available */ +	err = bcm47xx_nvram_getenv("boardtype", buf, sizeof(buf)); + +	/* init of nvram failed, probably too early now */ +	if (err == -ENXIO) { +		return; +	} + +	board_detected = bcm47xx_board_get_nvram(); +	bcm47xx_board.board = board_detected->board; +	strlcpy(bcm47xx_board.name, board_detected->name, +		BCM47XX_BOARD_MAX_NAME); +} + +enum bcm47xx_board bcm47xx_board_get(void) +{ +	return bcm47xx_board.board; +} +EXPORT_SYMBOL(bcm47xx_board_get); + +const char *bcm47xx_board_get_name(void) +{ +	return bcm47xx_board.name; +} +EXPORT_SYMBOL(bcm47xx_board_get_name); diff --git a/arch/mips/bcm47xx/buttons.c b/arch/mips/bcm47xx/buttons.c new file mode 100644 index 00000000000..49a1ce06844 --- /dev/null +++ b/arch/mips/bcm47xx/buttons.c @@ -0,0 +1,562 @@ +#include "bcm47xx_private.h" + +#include <linux/input.h> +#include <linux/gpio_keys.h> +#include <linux/interrupt.h> +#include <bcm47xx_board.h> +#include <bcm47xx.h> + +/************************************************** + * Database + **************************************************/ + +#define BCM47XX_GPIO_KEY(_gpio, _code)					\ +	{								\ +		.code		= _code,				\ +		.gpio		= _gpio,				\ +		.active_low	= 1,					\ +	} + +/* Asus */ + +static const struct gpio_keys_button +bcm47xx_buttons_asus_rtn12[] __initconst = { +	BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON), +	BCM47XX_GPIO_KEY(1, KEY_RESTART), +	BCM47XX_GPIO_KEY(4, BTN_0), /* Router mode */ +	BCM47XX_GPIO_KEY(5, BTN_1), /* Repeater mode */ +	BCM47XX_GPIO_KEY(6, BTN_2), /* AP mode */ +}; + +static const struct gpio_keys_button +bcm47xx_buttons_asus_rtn16[] __initconst = { +	BCM47XX_GPIO_KEY(6, KEY_WPS_BUTTON), +	BCM47XX_GPIO_KEY(8, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_asus_rtn66u[] __initconst = { +	BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON), +	BCM47XX_GPIO_KEY(9, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_asus_wl300g[] __initconst = { +	BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_asus_wl320ge[] __initconst = { +	BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_asus_wl330ge[] __initconst = { +	BCM47XX_GPIO_KEY(2, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_asus_wl500gd[] __initconst = { +	BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_asus_wl500gpv1[] __initconst = { +	BCM47XX_GPIO_KEY(0, KEY_RESTART), +	BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_asus_wl500gpv2[] __initconst = { +	BCM47XX_GPIO_KEY(2, KEY_RESTART), +	BCM47XX_GPIO_KEY(3, KEY_WPS_BUTTON), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_asus_wl500w[] __initconst = { +	BCM47XX_GPIO_KEY(6, KEY_RESTART), +	BCM47XX_GPIO_KEY(7, KEY_WPS_BUTTON), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_asus_wl520gc[] __initconst = { +	BCM47XX_GPIO_KEY(2, KEY_RESTART), +	BCM47XX_GPIO_KEY(3, KEY_WPS_BUTTON), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_asus_wl520gu[] __initconst = { +	BCM47XX_GPIO_KEY(2, KEY_RESTART), +	BCM47XX_GPIO_KEY(3, KEY_WPS_BUTTON), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_asus_wl700ge[] __initconst = { +	BCM47XX_GPIO_KEY(0, KEY_POWER), /* Hard disk power switch */ +	BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON), /* EZSetup */ +	BCM47XX_GPIO_KEY(6, KEY_COPY), /* Copy data from USB to internal disk */ +	BCM47XX_GPIO_KEY(7, KEY_RESTART), /* Hard reset */ +}; + +static const struct gpio_keys_button +bcm47xx_buttons_asus_wlhdd[] __initconst = { +	BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +/* Huawei */ + +static const struct gpio_keys_button +bcm47xx_buttons_huawei_e970[] __initconst = { +	BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +/* Belkin */ + +static const struct gpio_keys_button +bcm47xx_buttons_belkin_f7d4301[] __initconst = { +	BCM47XX_GPIO_KEY(6, KEY_RESTART), +	BCM47XX_GPIO_KEY(8, KEY_WPS_BUTTON), +}; + +/* Buffalo */ + +static const struct gpio_keys_button +bcm47xx_buttons_buffalo_whr2_a54g54[] __initconst = { +	BCM47XX_GPIO_KEY(4, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_buffalo_whr_g125[] __initconst = { +	BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON), +	BCM47XX_GPIO_KEY(4, KEY_RESTART), +	BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode swtich */ +}; + +static const struct gpio_keys_button +bcm47xx_buttons_buffalo_whr_g54s[] __initconst = { +	BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON), +	BCM47XX_GPIO_KEY(4, KEY_RESTART), +	BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode swtich */ +}; + +static const struct gpio_keys_button +bcm47xx_buttons_buffalo_whr_hp_g54[] __initconst = { +	BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON), +	BCM47XX_GPIO_KEY(4, KEY_RESTART), +	BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode swtich */ +}; + +static const struct gpio_keys_button +bcm47xx_buttons_buffalo_wzr_g300n[] __initconst = { +	BCM47XX_GPIO_KEY(4, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_buffalo_wzr_rs_g54[] __initconst = { +	BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON), +	BCM47XX_GPIO_KEY(4, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_buffalo_wzr_rs_g54hp[] __initconst = { +	BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON), +	BCM47XX_GPIO_KEY(4, KEY_RESTART), +}; + +/* Dell */ + +static const struct gpio_keys_button +bcm47xx_buttons_dell_tm2300[] __initconst = { +	BCM47XX_GPIO_KEY(0, KEY_RESTART), +}; + +/* D-Link */ + +static const struct gpio_keys_button +bcm47xx_buttons_dlink_dir130[] __initconst = { +	BCM47XX_GPIO_KEY(3, KEY_RESTART), +	BCM47XX_GPIO_KEY(7, KEY_UNKNOWN), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_dlink_dir330[] __initconst = { +	BCM47XX_GPIO_KEY(3, KEY_RESTART), +	BCM47XX_GPIO_KEY(7, KEY_UNKNOWN), +}; + +/* Linksys */ + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_e1000v1[] __initconst = { +	BCM47XX_GPIO_KEY(5, KEY_WPS_BUTTON), +	BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_e1000v21[] __initconst = { +	BCM47XX_GPIO_KEY(9, KEY_WPS_BUTTON), +	BCM47XX_GPIO_KEY(10, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_e2000v1[] __initconst = { +	BCM47XX_GPIO_KEY(5, KEY_WPS_BUTTON), +	BCM47XX_GPIO_KEY(8, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_e3000v1[] __initconst = { +	BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON), +	BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_e3200v1[] __initconst = { +	BCM47XX_GPIO_KEY(5, KEY_RESTART), +	BCM47XX_GPIO_KEY(8, KEY_WPS_BUTTON), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_e4200v1[] __initconst = { +	BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON), +	BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_wrt150nv1[] __initconst = { +	BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON), +	BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_wrt150nv11[] __initconst = { +	BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON), +	BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_wrt160nv1[] __initconst = { +	BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON), +	BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_wrt160nv3[] __initconst = { +	BCM47XX_GPIO_KEY(5, KEY_WPS_BUTTON), +	BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_wrt300nv11[] __initconst = { +	BCM47XX_GPIO_KEY(4, KEY_UNKNOWN), +	BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_wrt310nv1[] __initconst = { +	BCM47XX_GPIO_KEY(6, KEY_RESTART), +	BCM47XX_GPIO_KEY(8, KEY_UNKNOWN), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_wrt54g3gv2[] __initconst = { +	BCM47XX_GPIO_KEY(5, KEY_WIMAX), +	BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_wrt54gsv1[] __initconst = { +	BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON), +	BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_wrt610nv1[] __initconst = { +	BCM47XX_GPIO_KEY(6, KEY_RESTART), +	BCM47XX_GPIO_KEY(8, KEY_WPS_BUTTON), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_wrt610nv2[] __initconst = { +	BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON), +	BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_linksys_wrtsl54gs[] __initconst = { +	BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON), +	BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +/* Motorola */ + +static const struct gpio_keys_button +bcm47xx_buttons_motorola_we800g[] __initconst = { +	BCM47XX_GPIO_KEY(0, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_motorola_wr850gp[] __initconst = { +	BCM47XX_GPIO_KEY(5, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_motorola_wr850gv2v3[] __initconst = { +	BCM47XX_GPIO_KEY(5, KEY_RESTART), +}; + +/* Netgear */ + +static const struct gpio_keys_button +bcm47xx_buttons_netgear_wndr3400v1[] __initconst = { +	BCM47XX_GPIO_KEY(4, KEY_RESTART), +	BCM47XX_GPIO_KEY(6, KEY_WPS_BUTTON), +	BCM47XX_GPIO_KEY(8, KEY_RFKILL), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_netgear_wndr3700v3[] __initconst = { +	BCM47XX_GPIO_KEY(2, KEY_RFKILL), +	BCM47XX_GPIO_KEY(3, KEY_RESTART), +	BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_netgear_wndr4500v1[] __initconst = { +	BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON), +	BCM47XX_GPIO_KEY(5, KEY_RFKILL), +	BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +static const struct gpio_keys_button +bcm47xx_buttons_netgear_wnr834bv2[] __initconst = { +	BCM47XX_GPIO_KEY(6, KEY_RESTART), +}; + +/* SimpleTech */ + +static const struct gpio_keys_button +bcm47xx_buttons_simpletech_simpleshare[] __initconst = { +	BCM47XX_GPIO_KEY(0, KEY_RESTART), +}; + +/************************************************** + * Init + **************************************************/ + +static struct gpio_keys_platform_data bcm47xx_button_pdata; + +static struct platform_device bcm47xx_buttons_gpio_keys = { +	.name = "gpio-keys", +	.dev = { +		.platform_data = &bcm47xx_button_pdata, +	} +}; + +/* Copy data from __initconst */ +static int __init bcm47xx_buttons_copy(const struct gpio_keys_button *buttons, +				       size_t nbuttons) +{ +	size_t size = nbuttons * sizeof(*buttons); + +	bcm47xx_button_pdata.buttons = kmalloc(size, GFP_KERNEL); +	if (!bcm47xx_button_pdata.buttons) +		return -ENOMEM; +	memcpy(bcm47xx_button_pdata.buttons, buttons, size); +	bcm47xx_button_pdata.nbuttons = nbuttons; + +	return 0; +} + +#define bcm47xx_copy_bdata(dev_buttons)					\ +	bcm47xx_buttons_copy(dev_buttons, ARRAY_SIZE(dev_buttons)); + +int __init bcm47xx_buttons_register(void) +{ +	enum bcm47xx_board board = bcm47xx_board_get(); +	int err; + +	switch (board) { +	case BCM47XX_BOARD_ASUS_RTN12: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_rtn12); +		break; +	case BCM47XX_BOARD_ASUS_RTN16: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_rtn16); +		break; +	case BCM47XX_BOARD_ASUS_RTN66U: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_rtn66u); +		break; +	case BCM47XX_BOARD_ASUS_WL300G: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl300g); +		break; +	case BCM47XX_BOARD_ASUS_WL320GE: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl320ge); +		break; +	case BCM47XX_BOARD_ASUS_WL330GE: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl330ge); +		break; +	case BCM47XX_BOARD_ASUS_WL500GD: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl500gd); +		break; +	case BCM47XX_BOARD_ASUS_WL500GPV1: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl500gpv1); +		break; +	case BCM47XX_BOARD_ASUS_WL500GPV2: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl500gpv2); +		break; +	case BCM47XX_BOARD_ASUS_WL500W: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl500w); +		break; +	case BCM47XX_BOARD_ASUS_WL520GC: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl520gc); +		break; +	case BCM47XX_BOARD_ASUS_WL520GU: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl520gu); +		break; +	case BCM47XX_BOARD_ASUS_WL700GE: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl700ge); +		break; +	case BCM47XX_BOARD_ASUS_WLHDD: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wlhdd); +		break; + +	case BCM47XX_BOARD_BELKIN_F7D3301: +	case BCM47XX_BOARD_BELKIN_F7D3302: +	case BCM47XX_BOARD_BELKIN_F7D4301: +	case BCM47XX_BOARD_BELKIN_F7D4302: +	case BCM47XX_BOARD_BELKIN_F7D4401: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_belkin_f7d4301); +		break; + +	case BCM47XX_BOARD_BUFFALO_WHR2_A54G54: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_whr2_a54g54); +		break; +	case BCM47XX_BOARD_BUFFALO_WHR_G125: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_whr_g125); +		break; +	case BCM47XX_BOARD_BUFFALO_WHR_G54S: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_whr_g54s); +		break; +	case BCM47XX_BOARD_BUFFALO_WHR_HP_G54: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_whr_hp_g54); +		break; +	case BCM47XX_BOARD_BUFFALO_WZR_G300N: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_wzr_g300n); +		break; +	case BCM47XX_BOARD_BUFFALO_WZR_RS_G54: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_wzr_rs_g54); +		break; +	case BCM47XX_BOARD_BUFFALO_WZR_RS_G54HP: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_wzr_rs_g54hp); +		break; + +	case BCM47XX_BOARD_DELL_TM2300: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_dell_tm2300); +		break; + +	case BCM47XX_BOARD_DLINK_DIR130: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_dlink_dir130); +		break; +	case BCM47XX_BOARD_DLINK_DIR330: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_dlink_dir330); +		break; + +	case BCM47XX_BOARD_HUAWEI_E970: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_huawei_e970); +		break; + +	case BCM47XX_BOARD_LINKSYS_E1000V1: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_e1000v1); +		break; +	case BCM47XX_BOARD_LINKSYS_E1000V21: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_e1000v21); +		break; +	case BCM47XX_BOARD_LINKSYS_E2000V1: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_e2000v1); +		break; +	case BCM47XX_BOARD_LINKSYS_E3000V1: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_e3000v1); +		break; +	case BCM47XX_BOARD_LINKSYS_E3200V1: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_e3200v1); +		break; +	case BCM47XX_BOARD_LINKSYS_E4200V1: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_e4200v1); +		break; +	case BCM47XX_BOARD_LINKSYS_WRT150NV1: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt150nv1); +		break; +	case BCM47XX_BOARD_LINKSYS_WRT150NV11: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt150nv11); +		break; +	case BCM47XX_BOARD_LINKSYS_WRT160NV1: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt160nv1); +		break; +	case BCM47XX_BOARD_LINKSYS_WRT160NV3: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt160nv3); +		break; +	case BCM47XX_BOARD_LINKSYS_WRT300NV11: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt300nv11); +		break; +	case BCM47XX_BOARD_LINKSYS_WRT310NV1: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt310nv1); +		break; +	case BCM47XX_BOARD_LINKSYS_WRT54G: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt54gsv1); +		break; +	case BCM47XX_BOARD_LINKSYS_WRT54G3GV2: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt54g3gv2); +		break; +	case BCM47XX_BOARD_LINKSYS_WRT610NV1: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt610nv1); +		break; +	case BCM47XX_BOARD_LINKSYS_WRT610NV2: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt610nv2); +		break; +	case BCM47XX_BOARD_LINKSYS_WRTSL54GS: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrtsl54gs); +		break; + +	case BCM47XX_BOARD_MOTOROLA_WE800G: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_motorola_we800g); +		break; +	case BCM47XX_BOARD_MOTOROLA_WR850GP: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_motorola_wr850gp); +		break; +	case BCM47XX_BOARD_MOTOROLA_WR850GV2V3: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_motorola_wr850gv2v3); +		break; + +	case BCM47XX_BOARD_NETGEAR_WNDR3400V1: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_netgear_wndr3400v1); +		break; +	case BCM47XX_BOARD_NETGEAR_WNDR3700V3: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_netgear_wndr3700v3); +		break; +	case BCM47XX_BOARD_NETGEAR_WNDR4500V1: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_netgear_wndr4500v1); +		break; +	case BCM47XX_BOARD_NETGEAR_WNR834BV2: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_netgear_wnr834bv2); +		break; + +	case BCM47XX_BOARD_SIMPLETECH_SIMPLESHARE: +		err = bcm47xx_copy_bdata(bcm47xx_buttons_simpletech_simpleshare); +		break; + +	default: +		pr_debug("No buttons configuration found for this device\n"); +		return -ENOTSUPP; +	} + +	if (err) +		return -ENOMEM; + +	err = platform_device_register(&bcm47xx_buttons_gpio_keys); +	if (err) { +		pr_err("Failed to register platform device: %d\n", err); +		return err; +	} + +	return 0; +} diff --git a/arch/mips/bcm47xx/irq.c b/arch/mips/bcm47xx/irq.c index 8cf3833b2d2..e0585b76ec1 100644 --- a/arch/mips/bcm47xx/irq.c +++ b/arch/mips/bcm47xx/irq.c @@ -25,10 +25,11 @@  #include <linux/types.h>  #include <linux/interrupt.h>  #include <linux/irq.h> +#include <asm/setup.h>  #include <asm/irq_cpu.h>  #include <bcm47xx.h> -void plat_irq_dispatch(void) +asmlinkage void plat_irq_dispatch(void)  {  	u32 cause; @@ -50,6 +51,18 @@ void plat_irq_dispatch(void)  		do_IRQ(6);  } +#define DEFINE_HWx_IRQDISPATCH(x)					\ +	static void bcm47xx_hw ## x ## _irqdispatch(void)		\ +	{								\ +		do_IRQ(x);						\ +	} +DEFINE_HWx_IRQDISPATCH(2) +DEFINE_HWx_IRQDISPATCH(3) +DEFINE_HWx_IRQDISPATCH(4) +DEFINE_HWx_IRQDISPATCH(5) +DEFINE_HWx_IRQDISPATCH(6) +DEFINE_HWx_IRQDISPATCH(7) +  void __init arch_init_irq(void)  {  #ifdef CONFIG_BCM47XX_BCMA @@ -64,4 +77,14 @@ void __init arch_init_irq(void)  	}  #endif  	mips_cpu_irq_init(); + +	if (cpu_has_vint) { +		pr_info("Setting up vectored interrupts\n"); +		set_vi_handler(2, bcm47xx_hw2_irqdispatch); +		set_vi_handler(3, bcm47xx_hw3_irqdispatch); +		set_vi_handler(4, bcm47xx_hw4_irqdispatch); +		set_vi_handler(5, bcm47xx_hw5_irqdispatch); +		set_vi_handler(6, bcm47xx_hw6_irqdispatch); +		set_vi_handler(7, bcm47xx_hw7_irqdispatch); +	}  } diff --git a/arch/mips/bcm47xx/leds.c b/arch/mips/bcm47xx/leds.c new file mode 100644 index 00000000000..adcb547a91c --- /dev/null +++ b/arch/mips/bcm47xx/leds.c @@ -0,0 +1,591 @@ +#include "bcm47xx_private.h" + +#include <linux/leds.h> +#include <bcm47xx_board.h> + +/************************************************** + * Database + **************************************************/ + +#define BCM47XX_GPIO_LED(_gpio, _color, _function, _active_low,		\ +			 _default_state)				\ +	{								\ +		.name		= "bcm47xx:" _color ":" _function,	\ +		.gpio		= _gpio,				\ +		.active_low	= _active_low,				\ +		.default_state	= _default_state,			\ +	} + +#define BCM47XX_GPIO_LED_TRIGGER(_gpio, _color, _function, _active_low,	\ +				 _default_trigger)			\ +	{								\ +		.name		= "bcm47xx:" _color ":" _function,	\ +		.gpio		= _gpio,				\ +		.active_low	= _active_low,				\ +		.default_state	= LEDS_GPIO_DEFSTATE_OFF,		\ +		.default_trigger	= _default_trigger,		\ +	} + +/* Asus */ + +static const struct gpio_led +bcm47xx_leds_asus_rtn12[] __initconst = { +	BCM47XX_GPIO_LED(2, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(7, "unk", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_asus_rtn16[] __initconst = { +	BCM47XX_GPIO_LED(1, "blue", "power", 1, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(7, "blue", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_asus_rtn66u[] __initconst = { +	BCM47XX_GPIO_LED(12, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(15, "unk", "usb", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_asus_wl300g[] __initconst = { +	BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), +}; + +static const struct gpio_led +bcm47xx_leds_asus_wl320ge[] __initconst = { +	BCM47XX_GPIO_LED(0, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(2, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(11, "unk", "link", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_asus_wl330ge[] __initconst = { +	BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), +}; + +static const struct gpio_led +bcm47xx_leds_asus_wl500gd[] __initconst = { +	BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), +}; + +static const struct gpio_led +bcm47xx_leds_asus_wl500gpv1[] __initconst = { +	BCM47XX_GPIO_LED(1, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), +}; + +static const struct gpio_led +bcm47xx_leds_asus_wl500gpv2[] __initconst = { +	BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(1, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_asus_wl500w[] __initconst = { +	BCM47XX_GPIO_LED(5, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), +}; + +static const struct gpio_led +bcm47xx_leds_asus_wl520gc[] __initconst = { +	BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(1, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_asus_wl520gu[] __initconst = { +	BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(1, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_asus_wl700ge[] __initconst = { +	BCM47XX_GPIO_LED(1, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), /* Labeled "READY" (there is no "power" LED). Originally ON, flashing on USB activity. */ +}; + +static const struct gpio_led +bcm47xx_leds_asus_wlhdd[] __initconst = { +	BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(2, "unk", "usb", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +/* Belkin */ + +static const struct gpio_led +bcm47xx_leds_belkin_f7d4301[] __initconst = { +	BCM47XX_GPIO_LED(10, "green", "power", 1, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(11, "amber", "power", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(12, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(13, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(14, "unk", "usb0", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(15, "unk", "usb1", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +/* Buffalo */ + +static const struct gpio_led +bcm47xx_leds_buffalo_whr2_a54g54[] __initconst = { +	BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_buffalo_whr_g125[] __initconst = { +	BCM47XX_GPIO_LED(1, "unk", "bridge", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(2, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(3, "unk", "internal", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(6, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_buffalo_whr_g54s[] __initconst = { +	BCM47XX_GPIO_LED(1, "unk", "bridge", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(2, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(3, "unk", "internal", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(6, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_buffalo_whr_hp_g54[] __initconst = { +	BCM47XX_GPIO_LED(1, "unk", "bridge", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(2, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(3, "unk", "internal", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(6, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_buffalo_wzr_g300n[] __initconst = { +	BCM47XX_GPIO_LED(1, "unk", "bridge", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(6, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_buffalo_wzr_rs_g54[] __initconst = { +	BCM47XX_GPIO_LED(6, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(1, "unk", "vpn", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_buffalo_wzr_rs_g54hp[] __initconst = { +	BCM47XX_GPIO_LED(6, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(1, "unk", "vpn", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +/* Dell */ + +static const struct gpio_led +bcm47xx_leds_dell_tm2300[] __initconst = { +	BCM47XX_GPIO_LED(6, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(7, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), +}; + +/* D-Link */ + +static const struct gpio_led +bcm47xx_leds_dlink_dir130[] __initconst = { +	BCM47XX_GPIO_LED_TRIGGER(0, "green", "status", 1, "timer"), /* Originally blinking when device is ready, separated from "power" LED */ +	BCM47XX_GPIO_LED(6, "blue", "unk", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_dlink_dir330[] __initconst = { +	BCM47XX_GPIO_LED_TRIGGER(0, "green", "status", 1, "timer"), /* Originally blinking when device is ready, separated from "power" LED */ +	BCM47XX_GPIO_LED(4, "unk", "usb", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(6, "blue", "unk", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +/* Huawei */ + +static const struct gpio_led +bcm47xx_leds_huawei_e970[] __initconst = { +	BCM47XX_GPIO_LED(0, "unk", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF), +}; + +/* Linksys */ + +static const struct gpio_led +bcm47xx_leds_linksys_e1000v1[] __initconst = { +	BCM47XX_GPIO_LED(0, "blue", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(1, "blue", "power", 0, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(2, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(4, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_e1000v21[] __initconst = { +	BCM47XX_GPIO_LED(5, "unk", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(6, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(7, "amber", "wps", 0, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(8, "blue", "wps", 0, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_e2000v1[] __initconst = { +	BCM47XX_GPIO_LED(1, "blue", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(2, "blue", "power", 0, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(3, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(4, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_e3000v1[] __initconst = { +	BCM47XX_GPIO_LED(0, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(1, "unk", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(3, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(5, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(7, "unk", "usb", 0, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_e3200v1[] __initconst = { +	BCM47XX_GPIO_LED(3, "green", "power", 1, LEDS_GPIO_DEFSTATE_ON), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_e4200v1[] __initconst = { +	BCM47XX_GPIO_LED(5, "white", "power", 1, LEDS_GPIO_DEFSTATE_ON), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_wrt150nv1[] __initconst = { +	BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(3, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(5, "green", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_wrt150nv11[] __initconst = { +	BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(3, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(5, "green", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_wrt160nv1[] __initconst = { +	BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(3, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(5, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_wrt160nv3[] __initconst = { +	BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(2, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(4, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_wrt300nv11[] __initconst = { +	BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(3, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(5, "green", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_wrt310nv1[] __initconst = { +	BCM47XX_GPIO_LED(1, "blue", "power", 0, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(3, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(9, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_wrt54gsv1[] __initconst = { +	BCM47XX_GPIO_LED(0, "unk", "dmz", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(5, "white", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(7, "orange", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_wrt54g3gv2[] __initconst = { +	BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(2, "green", "3g", 0, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(3, "blue", "3g", 0, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_wrt610nv1[] __initconst = { +	BCM47XX_GPIO_LED(0, "unk", "usb",  1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(1, "unk", "power",  0, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(3, "amber", "wps",  1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(9, "blue", "wps",  1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_wrt610nv2[] __initconst = { +	BCM47XX_GPIO_LED(0, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(1, "unk", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(3, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(5, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(7, "unk", "usb", 0, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_linksys_wrtsl54gs[] __initconst = { +	BCM47XX_GPIO_LED(0, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(2, "white", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(3, "orange", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(7, "unk", "dmz", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +/* Motorola */ + +static const struct gpio_led +bcm47xx_leds_motorola_we800g[] __initconst = { +	BCM47XX_GPIO_LED(1, "amber", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(2, "unk", "unk", 1, LEDS_GPIO_DEFSTATE_OFF), /* There are only 3 LEDs: Power, Wireless and Device (ethernet) */ +	BCM47XX_GPIO_LED(4, "green", "power", 0, LEDS_GPIO_DEFSTATE_ON), +}; + +static const struct gpio_led +bcm47xx_leds_motorola_wr850gp[] __initconst = { +	BCM47XX_GPIO_LED(0, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(6, "unk", "dmz", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_motorola_wr850gv2v3[] __initconst = { +	BCM47XX_GPIO_LED(0, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +/* Netgear */ + +static const struct gpio_led +bcm47xx_leds_netgear_wndr3400v1[] __initconst = { +	BCM47XX_GPIO_LED(2, "green", "usb", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(3, "green", "power", 0, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(7, "amber", "power", 0, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_netgear_wndr4500v1[] __initconst = { +	BCM47XX_GPIO_LED(1, "green", "wps", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(2, "green", "power", 1, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(3, "amber", "power", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(8, "green", "usb1", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(9, "green", "2ghz", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(11, "blue", "5ghz", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(14, "green", "usb2", 1, LEDS_GPIO_DEFSTATE_OFF), +}; + +static const struct gpio_led +bcm47xx_leds_netgear_wnr834bv2[] __initconst = { +	BCM47XX_GPIO_LED(2, "green", "power", 0, LEDS_GPIO_DEFSTATE_ON), +	BCM47XX_GPIO_LED(3, "amber", "power", 0, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(7, "unk", "connected", 0, LEDS_GPIO_DEFSTATE_OFF), +}; + +/* Siemens */ +static const struct gpio_led +bcm47xx_leds_siemens_se505v2[] __initconst = { +	BCM47XX_GPIO_LED(0, "unk", "dmz", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(3, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), +	BCM47XX_GPIO_LED(5, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), +}; + +/* SimpleTech */ + +static const struct gpio_led +bcm47xx_leds_simpletech_simpleshare[] __initconst = { +	BCM47XX_GPIO_LED(1, "unk", "status", 1, LEDS_GPIO_DEFSTATE_OFF), /* "Ready" LED */ +}; + +/************************************************** + * Init + **************************************************/ + +static struct gpio_led_platform_data bcm47xx_leds_pdata; + +#define bcm47xx_set_pdata(dev_leds) do {				\ +	bcm47xx_leds_pdata.leds = dev_leds;				\ +	bcm47xx_leds_pdata.num_leds = ARRAY_SIZE(dev_leds);		\ +} while (0) + +void __init bcm47xx_leds_register(void) +{ +	enum bcm47xx_board board = bcm47xx_board_get(); + +	switch (board) { +	case BCM47XX_BOARD_ASUS_RTN12: +		bcm47xx_set_pdata(bcm47xx_leds_asus_rtn12); +		break; +	case BCM47XX_BOARD_ASUS_RTN16: +		bcm47xx_set_pdata(bcm47xx_leds_asus_rtn16); +		break; +	case BCM47XX_BOARD_ASUS_RTN66U: +		bcm47xx_set_pdata(bcm47xx_leds_asus_rtn66u); +		break; +	case BCM47XX_BOARD_ASUS_WL300G: +		bcm47xx_set_pdata(bcm47xx_leds_asus_wl300g); +		break; +	case BCM47XX_BOARD_ASUS_WL320GE: +		bcm47xx_set_pdata(bcm47xx_leds_asus_wl320ge); +		break; +	case BCM47XX_BOARD_ASUS_WL330GE: +		bcm47xx_set_pdata(bcm47xx_leds_asus_wl330ge); +		break; +	case BCM47XX_BOARD_ASUS_WL500GD: +		bcm47xx_set_pdata(bcm47xx_leds_asus_wl500gd); +		break; +	case BCM47XX_BOARD_ASUS_WL500GPV1: +		bcm47xx_set_pdata(bcm47xx_leds_asus_wl500gpv1); +		break; +	case BCM47XX_BOARD_ASUS_WL500GPV2: +		bcm47xx_set_pdata(bcm47xx_leds_asus_wl500gpv2); +		break; +	case BCM47XX_BOARD_ASUS_WL500W: +		bcm47xx_set_pdata(bcm47xx_leds_asus_wl500w); +		break; +	case BCM47XX_BOARD_ASUS_WL520GC: +		bcm47xx_set_pdata(bcm47xx_leds_asus_wl520gc); +		break; +	case BCM47XX_BOARD_ASUS_WL520GU: +		bcm47xx_set_pdata(bcm47xx_leds_asus_wl520gu); +		break; +	case BCM47XX_BOARD_ASUS_WL700GE: +		bcm47xx_set_pdata(bcm47xx_leds_asus_wl700ge); +		break; +	case BCM47XX_BOARD_ASUS_WLHDD: +		bcm47xx_set_pdata(bcm47xx_leds_asus_wlhdd); +		break; + +	case BCM47XX_BOARD_BELKIN_F7D3301: +	case BCM47XX_BOARD_BELKIN_F7D3302: +	case BCM47XX_BOARD_BELKIN_F7D4301: +	case BCM47XX_BOARD_BELKIN_F7D4302: +	case BCM47XX_BOARD_BELKIN_F7D4401: +		bcm47xx_set_pdata(bcm47xx_leds_belkin_f7d4301); +		break; + +	case BCM47XX_BOARD_BUFFALO_WHR2_A54G54: +		bcm47xx_set_pdata(bcm47xx_leds_buffalo_whr2_a54g54); +		break; +	case BCM47XX_BOARD_BUFFALO_WHR_G125: +		bcm47xx_set_pdata(bcm47xx_leds_buffalo_whr_g125); +		break; +	case BCM47XX_BOARD_BUFFALO_WHR_G54S: +		bcm47xx_set_pdata(bcm47xx_leds_buffalo_whr_g54s); +		break; +	case BCM47XX_BOARD_BUFFALO_WHR_HP_G54: +		bcm47xx_set_pdata(bcm47xx_leds_buffalo_whr_hp_g54); +		break; +	case BCM47XX_BOARD_BUFFALO_WZR_G300N: +		bcm47xx_set_pdata(bcm47xx_leds_buffalo_wzr_g300n); +		break; +	case BCM47XX_BOARD_BUFFALO_WZR_RS_G54: +		bcm47xx_set_pdata(bcm47xx_leds_buffalo_wzr_rs_g54); +		break; +	case BCM47XX_BOARD_BUFFALO_WZR_RS_G54HP: +		bcm47xx_set_pdata(bcm47xx_leds_buffalo_wzr_rs_g54hp); +		break; + +	case BCM47XX_BOARD_DELL_TM2300: +		bcm47xx_set_pdata(bcm47xx_leds_dell_tm2300); +		break; + +	case BCM47XX_BOARD_DLINK_DIR130: +		bcm47xx_set_pdata(bcm47xx_leds_dlink_dir130); +		break; +	case BCM47XX_BOARD_DLINK_DIR330: +		bcm47xx_set_pdata(bcm47xx_leds_dlink_dir330); +		break; + +	case BCM47XX_BOARD_HUAWEI_E970: +		bcm47xx_set_pdata(bcm47xx_leds_huawei_e970); +		break; + +	case BCM47XX_BOARD_LINKSYS_E1000V1: +		bcm47xx_set_pdata(bcm47xx_leds_linksys_e1000v1); +		break; +	case BCM47XX_BOARD_LINKSYS_E1000V21: +		bcm47xx_set_pdata(bcm47xx_leds_linksys_e1000v21); +		break; +	case BCM47XX_BOARD_LINKSYS_E2000V1: +		bcm47xx_set_pdata(bcm47xx_leds_linksys_e2000v1); +		break; +	case BCM47XX_BOARD_LINKSYS_E3000V1: +		bcm47xx_set_pdata(bcm47xx_leds_linksys_e3000v1); +		break; +	case BCM47XX_BOARD_LINKSYS_E3200V1: +		bcm47xx_set_pdata(bcm47xx_leds_linksys_e3200v1); +		break; +	case BCM47XX_BOARD_LINKSYS_E4200V1: +		bcm47xx_set_pdata(bcm47xx_leds_linksys_e4200v1); +		break; +	case BCM47XX_BOARD_LINKSYS_WRT150NV1: +		bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt150nv1); +		break; +	case BCM47XX_BOARD_LINKSYS_WRT150NV11: +		bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt150nv11); +		break; +	case BCM47XX_BOARD_LINKSYS_WRT160NV1: +		bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt160nv1); +		break; +	case BCM47XX_BOARD_LINKSYS_WRT160NV3: +		bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt160nv3); +		break; +	case BCM47XX_BOARD_LINKSYS_WRT300NV11: +		bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt300nv11); +		break; +	case BCM47XX_BOARD_LINKSYS_WRT310NV1: +		bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt310nv1); +		break; +	case BCM47XX_BOARD_LINKSYS_WRT54G: +		bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt54gsv1); +		break; +	case BCM47XX_BOARD_LINKSYS_WRT54G3GV2: +		bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt54g3gv2); +		break; +	case BCM47XX_BOARD_LINKSYS_WRT610NV1: +		bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt610nv1); +		break; +	case BCM47XX_BOARD_LINKSYS_WRT610NV2: +		bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt610nv2); +		break; +	case BCM47XX_BOARD_LINKSYS_WRTSL54GS: +		bcm47xx_set_pdata(bcm47xx_leds_linksys_wrtsl54gs); +		break; + +	case BCM47XX_BOARD_MOTOROLA_WE800G: +		bcm47xx_set_pdata(bcm47xx_leds_motorola_we800g); +		break; +	case BCM47XX_BOARD_MOTOROLA_WR850GP: +		bcm47xx_set_pdata(bcm47xx_leds_motorola_wr850gp); +		break; +	case BCM47XX_BOARD_MOTOROLA_WR850GV2V3: +		bcm47xx_set_pdata(bcm47xx_leds_motorola_wr850gv2v3); +		break; + +	case BCM47XX_BOARD_NETGEAR_WNDR3400V1: +		bcm47xx_set_pdata(bcm47xx_leds_netgear_wndr3400v1); +		break; +	case BCM47XX_BOARD_NETGEAR_WNDR4500V1: +		bcm47xx_set_pdata(bcm47xx_leds_netgear_wndr4500v1); +		break; +	case BCM47XX_BOARD_NETGEAR_WNR834BV2: +		bcm47xx_set_pdata(bcm47xx_leds_netgear_wnr834bv2); +		break; + +	case BCM47XX_BOARD_SIEMENS_SE505V2: +		bcm47xx_set_pdata(bcm47xx_leds_siemens_se505v2); +		break; + +	case BCM47XX_BOARD_SIMPLETECH_SIMPLESHARE: +		bcm47xx_set_pdata(bcm47xx_leds_simpletech_simpleshare); +		break; + +	default: +		pr_debug("No LEDs configuration found for this device\n"); +		return; +	} + +	gpio_led_register_device(-1, &bcm47xx_leds_pdata); +} diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c index cc40b74940f..2bed73a684a 100644 --- a/arch/mips/bcm47xx/nvram.c +++ b/arch/mips/bcm47xx/nvram.c @@ -11,7 +11,6 @@   * option) any later version.   */ -#include <linux/init.h>  #include <linux/types.h>  #include <linux/module.h>  #include <linux/ssb/ssb.h> @@ -22,11 +21,11 @@  #include <asm/mach-bcm47xx/bcm47xx.h>  static char nvram_buf[NVRAM_SPACE]; +static const u32 nvram_sizes[] = {0x8000, 0xF000, 0x10000};  static u32 find_nvram_size(u32 end)  {  	struct nvram_header *header; -	u32 nvram_sizes[] = {0x8000, 0xF000, 0x10000};  	int i;  	for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) { @@ -190,3 +189,23 @@ int bcm47xx_nvram_getenv(char *name, char *val, size_t val_len)  	return -ENOENT;  }  EXPORT_SYMBOL(bcm47xx_nvram_getenv); + +int bcm47xx_nvram_gpio_pin(const char *name) +{ +	int i, err; +	char nvram_var[10]; +	char buf[30]; + +	for (i = 0; i < 32; i++) { +		err = snprintf(nvram_var, sizeof(nvram_var), "gpio%i", i); +		if (err <= 0) +			continue; +		err = bcm47xx_nvram_getenv(nvram_var, buf, sizeof(buf)); +		if (err <= 0) +			continue; +		if (!strcmp(name, buf)) +			return i; +	} +	return -ENOENT; +} +EXPORT_SYMBOL(bcm47xx_nvram_gpio_pin); diff --git a/arch/mips/bcm47xx/prom.c b/arch/mips/bcm47xx/prom.c index 8c155afb129..1a03a2f4349 100644 --- a/arch/mips/bcm47xx/prom.c +++ b/arch/mips/bcm47xx/prom.c @@ -28,101 +28,27 @@  #include <linux/types.h>  #include <linux/kernel.h>  #include <linux/spinlock.h> +#include <linux/ssb/ssb_driver_chipcommon.h> +#include <linux/ssb/ssb_regs.h>  #include <linux/smp.h>  #include <asm/bootinfo.h> -#include <asm/fw/cfe/cfe_api.h> -#include <asm/fw/cfe/cfe_error.h> +#include <bcm47xx.h> +#include <bcm47xx_board.h> -static int cfe_cons_handle; -const char *get_system_type(void) -{ -	return "Broadcom BCM47XX"; -} - -void prom_putchar(char c) -{ -	while (cfe_write(cfe_cons_handle, &c, 1) == 0) -		; -} - -static __init void prom_init_cfe(void) -{ -	uint32_t cfe_ept; -	uint32_t cfe_handle; -	uint32_t cfe_eptseal; -	int argc = fw_arg0; -	char **envp = (char **) fw_arg2; -	int *prom_vec = (int *) fw_arg3; - -	/* -	 * Check if a loader was used; if NOT, the 4 arguments are -	 * what CFE gives us (handle, 0, EPT and EPTSEAL) -	 */ -	if (argc < 0) { -		cfe_handle = (uint32_t)argc; -		cfe_ept = (uint32_t)envp; -		cfe_eptseal = (uint32_t)prom_vec; -	} else { -		if ((int)prom_vec < 0) { -			/* -			 * Old loader; all it gives us is the handle, -			 * so use the "known" entrypoint and assume -			 * the seal. -			 */ -			cfe_handle = (uint32_t)prom_vec; -			cfe_ept = 0xBFC00500; -			cfe_eptseal = CFE_EPTSEAL; -		} else { -			/* -			 * Newer loaders bundle the handle/ept/eptseal -			 * Note: prom_vec is in the loader's useg -			 * which is still alive in the TLB. -			 */ -			cfe_handle = prom_vec[0]; -			cfe_ept = prom_vec[2]; -			cfe_eptseal = prom_vec[3]; -		} -	} - -	if (cfe_eptseal != CFE_EPTSEAL) { -		/* too early for panic to do any good */ -		printk(KERN_ERR "CFE's entrypoint seal doesn't match."); -		while (1) ; -	} +static char bcm47xx_system_type[20] = "Broadcom BCM47XX"; -	cfe_init(cfe_handle, cfe_ept); -} - -static __init void prom_init_console(void) +const char *get_system_type(void)  { -	/* Initialize CFE console */ -	cfe_cons_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE); +	return bcm47xx_system_type;  } -static __init void prom_init_cmdline(void) +__init void bcm47xx_set_system_type(u16 chip_id)  { -	static char buf[COMMAND_LINE_SIZE] __initdata; - -	/* Get the kernel command line from CFE */ -	if (cfe_getenv("LINUX_CMDLINE", buf, COMMAND_LINE_SIZE) >= 0) { -		buf[COMMAND_LINE_SIZE - 1] = 0; -		strcpy(arcs_cmdline, buf); -	} - -	/* Force a console handover by adding a console= argument if needed, -	 * as CFE is not available anymore later in the boot process. */ -	if ((strstr(arcs_cmdline, "console=")) == NULL) { -		/* Try to read the default serial port used by CFE */ -		if ((cfe_getenv("BOOT_CONSOLE", buf, COMMAND_LINE_SIZE) < 0) -		    || (strncmp("uart", buf, 4))) -			/* Default to uart0 */ -			strcpy(buf, "uart0"); - -		/* Compute the new command line */ -		snprintf(arcs_cmdline, COMMAND_LINE_SIZE, "%s console=ttyS%c,115200", -			 arcs_cmdline, buf[4]); -	} +	snprintf(bcm47xx_system_type, sizeof(bcm47xx_system_type), +		 (chip_id > 0x9999) ? "Broadcom BCM%d" : +				      "Broadcom BCM%04X", +		 chip_id);  }  static __init void prom_init_mem(void) @@ -143,15 +69,18 @@ static __init void prom_init_mem(void)  	 * BCM47XX uses 128MB for addressing the ram, if the system contains  	 * less that that amount of ram it remaps the ram more often into the  	 * available space. -	 * Accessing memory after 128MB will cause an exception. -	 * max contains the biggest possible address supported by the platform. -	 * If the method wants to try something above we assume 128MB ram.  	 */ -	off = (unsigned long)prom_init; -	max = off | ((128 << 20) - 1); -	for (mem = (1 << 20); mem < (128 << 20); mem += (1 << 20)) { -		if ((off + mem) > max) { -			mem = (128 << 20); + +	/* Physical address, without mapping to any kernel segment */ +	off = CPHYSADDR((unsigned long)prom_init); + +	/* Accessing memory after 128 MiB will cause an exception */ +	max = 128 << 20; + +	for (mem = 1 << 20; mem < max; mem += 1 << 20) { +		/* Loop condition may be not enough, off may be over 1 MiB */ +		if (off + mem >= max) { +			mem = max;  			printk(KERN_DEBUG "assume 128MB RAM\n");  			break;  		} @@ -170,12 +99,16 @@ static __init void prom_init_mem(void)  	add_memory_region(0, mem, BOOT_MEM_RAM);  } +/* + * This is the first serial on the chip common core, it is at this position + * for sb (ssb) and ai (bcma) bus. + */ +#define BCM47XX_SERIAL_ADDR (SSB_ENUM_BASE + SSB_CHIPCO_UART0_DATA) +  void __init prom_init(void)  { -	prom_init_cfe(); -	prom_init_console(); -	prom_init_cmdline();  	prom_init_mem(); +	setup_8250_early_printk_port(CKSEG1ADDR(BCM47XX_SERIAL_ADDR), 0, 0);  }  void __init prom_free_prom_memory(void) diff --git a/arch/mips/bcm47xx/serial.c b/arch/mips/bcm47xx/serial.c index b8ef965705c..2f5bbd68e9a 100644 --- a/arch/mips/bcm47xx/serial.c +++ b/arch/mips/bcm47xx/serial.c @@ -31,7 +31,8 @@ static int __init uart8250_init_ssb(void)  	memset(&uart8250_data, 0,  sizeof(uart8250_data)); -	for (i = 0; i < mcore->nr_serial_ports; i++) { +	for (i = 0; i < mcore->nr_serial_ports && +		    i < ARRAY_SIZE(uart8250_data) - 1; i++) {  		struct plat_serial8250_port *p = &(uart8250_data[i]);  		struct ssb_serial_port *ssb_port = &(mcore->serial_ports[i]); @@ -55,7 +56,8 @@ static int __init uart8250_init_bcma(void)  	memset(&uart8250_data, 0,  sizeof(uart8250_data)); -	for (i = 0; i < cc->nr_serial_ports; i++) { +	for (i = 0; i < cc->nr_serial_ports && +		    i < ARRAY_SIZE(uart8250_data) - 1; i++) {  		struct plat_serial8250_port *p = &(uart8250_data[i]);  		struct bcma_serial_port *bcma_port;  		bcma_port = &(cc->serial_ports[i]); diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index b2246cd9ca1..63a4b0e915d 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -26,16 +26,24 @@   *  675 Mass Ave, Cambridge, MA 02139, USA.   */ +#include "bcm47xx_private.h" +  #include <linux/export.h>  #include <linux/types.h> +#include <linux/ethtool.h> +#include <linux/phy.h> +#include <linux/phy_fixed.h>  #include <linux/ssb/ssb.h>  #include <linux/ssb/ssb_embedded.h>  #include <linux/bcma/bcma_soc.h>  #include <asm/bootinfo.h> +#include <asm/idle.h> +#include <asm/prom.h>  #include <asm/reboot.h>  #include <asm/time.h>  #include <bcm47xx.h>  #include <bcm47xx_nvram.h> +#include <bcm47xx_board.h>  union bcm47xx_bus bcm47xx_bus;  EXPORT_SYMBOL(bcm47xx_bus); @@ -204,24 +212,59 @@ void __init plat_mem_setup(void)  {  	struct cpuinfo_mips *c = ¤t_cpu_data; -	if (c->cputype == CPU_74K) { +	if ((c->cputype == CPU_74K) || (c->cputype == CPU_1074K)) {  		printk(KERN_INFO "bcm47xx: using bcma bus\n");  #ifdef CONFIG_BCM47XX_BCMA  		bcm47xx_bus_type = BCM47XX_BUS_TYPE_BCMA;  		bcm47xx_register_bcma(); +		bcm47xx_set_system_type(bcm47xx_bus.bcma.bus.chipinfo.id);  #endif  	} else {  		printk(KERN_INFO "bcm47xx: using ssb bus\n");  #ifdef CONFIG_BCM47XX_SSB  		bcm47xx_bus_type = BCM47XX_BUS_TYPE_SSB;  		bcm47xx_register_ssb(); +		bcm47xx_set_system_type(bcm47xx_bus.ssb.chip_id);  #endif  	}  	_machine_restart = bcm47xx_machine_restart;  	_machine_halt = bcm47xx_machine_halt;  	pm_power_off = bcm47xx_machine_halt; +	bcm47xx_board_detect(); +	mips_set_machine_name(bcm47xx_board_get_name()); +} + +static int __init bcm47xx_cpu_fixes(void) +{ +	switch (bcm47xx_bus_type) { +#ifdef CONFIG_BCM47XX_SSB +	case BCM47XX_BUS_TYPE_SSB: +		/* Nothing to do */ +		break; +#endif +#ifdef CONFIG_BCM47XX_BCMA +	case BCM47XX_BUS_TYPE_BCMA: +		/* The BCM4706 has a problem with the CPU wait instruction. +		 * When r4k_wait or r4k_wait_irqoff is used will just hang and +		 * not return from a msleep(). Removing the cpu_wait +		 * functionality is a workaround for this problem. The BCM4716 +		 * does not have this problem. +		 */ +		if (bcm47xx_bus.bcma.bus.chipinfo.id == BCMA_CHIP_ID_BCM4706) +			cpu_wait = NULL; +		break; +#endif +	} +	return 0;  } +arch_initcall(bcm47xx_cpu_fixes); + +static struct fixed_phy_status bcm47xx_fixed_phy_status __initdata = { +	.link	= 1, +	.speed	= SPEED_100, +	.duplex	= DUPLEX_FULL, +};  static int __init bcm47xx_register_bus_complete(void)  { @@ -237,6 +280,11 @@ static int __init bcm47xx_register_bus_complete(void)  		break;  #endif  	} +	bcm47xx_buttons_register(); +	bcm47xx_leds_register(); +	bcm47xx_workarounds(); + +	fixed_phy_add(PHY_POLL, 0, &bcm47xx_fixed_phy_status);  	return 0;  }  device_initcall(bcm47xx_register_bus_complete); diff --git a/arch/mips/bcm47xx/sprom.c b/arch/mips/bcm47xx/sprom.c index ad03c931b90..da4cdb16844 100644 --- a/arch/mips/bcm47xx/sprom.c +++ b/arch/mips/bcm47xx/sprom.c @@ -135,7 +135,7 @@ static void nvram_read_leddc(const char *prefix, const char *name,  }  static void nvram_read_macaddr(const char *prefix, const char *name, -			       u8 (*val)[6], bool fallback) +			       u8 val[6], bool fallback)  {  	char buf[100];  	int err; @@ -144,11 +144,11 @@ static void nvram_read_macaddr(const char *prefix, const char *name,  	if (err < 0)  		return; -	bcm47xx_nvram_parse_macaddr(buf, *val); +	bcm47xx_nvram_parse_macaddr(buf, val);  }  static void nvram_read_alpha2(const char *prefix, const char *name, -			     char (*val)[2], bool fallback) +			     char val[2], bool fallback)  {  	char buf[10];  	int err; @@ -162,12 +162,13 @@ static void nvram_read_alpha2(const char *prefix, const char *name,  		pr_warn("alpha2 is too long %s\n", buf);  		return;  	} -	memcpy(val, buf, sizeof(val)); +	memcpy(val, buf, 2);  }  static void bcm47xx_fill_sprom_r1234589(struct ssb_sprom *sprom,  					const char *prefix, bool fallback)  { +	nvram_read_u16(prefix, NULL, "devid", &sprom->dev_id, 0, fallback);  	nvram_read_u8(prefix, NULL, "ledbh0", &sprom->gpio0, 0xff, fallback);  	nvram_read_u8(prefix, NULL, "ledbh1", &sprom->gpio1, 0xff, fallback);  	nvram_read_u8(prefix, NULL, "ledbh2", &sprom->gpio2, 0xff, fallback); @@ -180,7 +181,7 @@ static void bcm47xx_fill_sprom_r1234589(struct ssb_sprom *sprom,  		      fallback);  	nvram_read_s8(prefix, NULL, "ag1", &sprom->antenna_gain.a1, 0,  		      fallback); -	nvram_read_alpha2(prefix, "ccode", &sprom->alpha2, fallback); +	nvram_read_alpha2(prefix, "ccode", sprom->alpha2, fallback);  }  static void bcm47xx_fill_sprom_r12389(struct ssb_sprom *sprom, @@ -633,20 +634,20 @@ static void bcm47xx_fill_sprom_path_r45(struct ssb_sprom *sprom,  static void bcm47xx_fill_sprom_ethernet(struct ssb_sprom *sprom,  					const char *prefix, bool fallback)  { -	nvram_read_macaddr(prefix, "et0macaddr", &sprom->et0mac, fallback); +	nvram_read_macaddr(prefix, "et0macaddr", sprom->et0mac, fallback);  	nvram_read_u8(prefix, NULL, "et0mdcport", &sprom->et0mdcport, 0,  		      fallback);  	nvram_read_u8(prefix, NULL, "et0phyaddr", &sprom->et0phyaddr, 0,  		      fallback); -	nvram_read_macaddr(prefix, "et1macaddr", &sprom->et1mac, fallback); +	nvram_read_macaddr(prefix, "et1macaddr", sprom->et1mac, fallback);  	nvram_read_u8(prefix, NULL, "et1mdcport", &sprom->et1mdcport, 0,  		      fallback);  	nvram_read_u8(prefix, NULL, "et1phyaddr", &sprom->et1phyaddr, 0,  		      fallback); -	nvram_read_macaddr(prefix, "macaddr", &sprom->il0mac, fallback); -	nvram_read_macaddr(prefix, "il0macaddr", &sprom->il0mac, fallback); +	nvram_read_macaddr(prefix, "macaddr", sprom->il0mac, fallback); +	nvram_read_macaddr(prefix, "il0macaddr", sprom->il0mac, fallback);  }  static void bcm47xx_fill_board_data(struct ssb_sprom *sprom, const char *prefix, diff --git a/arch/mips/bcm47xx/time.c b/arch/mips/bcm47xx/time.c index 536374dcba7..2c85d9254b5 100644 --- a/arch/mips/bcm47xx/time.c +++ b/arch/mips/bcm47xx/time.c @@ -27,10 +27,16 @@  #include <linux/ssb/ssb.h>  #include <asm/time.h>  #include <bcm47xx.h> +#include <bcm47xx_nvram.h> +#include <bcm47xx_board.h>  void __init plat_time_init(void)  {  	unsigned long hz = 0; +	u16 chip_id = 0; +	char buf[10]; +	int len; +	enum bcm47xx_board board = bcm47xx_board_get();  	/*  	 * Use deterministic values for initial counter interrupt @@ -43,15 +49,32 @@ void __init plat_time_init(void)  #ifdef CONFIG_BCM47XX_SSB  	case BCM47XX_BUS_TYPE_SSB:  		hz = ssb_cpu_clock(&bcm47xx_bus.ssb.mipscore) / 2; +		chip_id = bcm47xx_bus.ssb.chip_id;  		break;  #endif  #ifdef CONFIG_BCM47XX_BCMA  	case BCM47XX_BUS_TYPE_BCMA:  		hz = bcma_cpu_clock(&bcm47xx_bus.bcma.bus.drv_mips) / 2; +		chip_id = bcm47xx_bus.bcma.bus.chipinfo.id;  		break;  #endif  	} +	if (chip_id == 0x5354) { +		len = bcm47xx_nvram_getenv("clkfreq", buf, sizeof(buf)); +		if (len >= 0 && !strncmp(buf, "200", 4)) +			hz = 100000000; +	} + +	switch (board) { +	case BCM47XX_BOARD_ASUS_WL520GC: +	case BCM47XX_BOARD_ASUS_WL520GU: +		hz = 100000000; +		break; +	default: +		break; +	} +  	if (!hz)  		hz = 100000000; diff --git a/arch/mips/bcm47xx/wgt634u.c b/arch/mips/bcm47xx/wgt634u.c deleted file mode 100644 index c63a4c287b5..00000000000 --- a/arch/mips/bcm47xx/wgt634u.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License.  See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2007 Aurelien Jarno <aurelien@aurel32.net> - */ - -#include <linux/platform_device.h> -#include <linux/module.h> -#include <linux/leds.h> -#include <linux/mtd/physmap.h> -#include <linux/ssb/ssb.h> -#include <linux/ssb/ssb_embedded.h> -#include <linux/interrupt.h> -#include <linux/reboot.h> -#include <linux/gpio.h> -#include <asm/mach-bcm47xx/bcm47xx.h> - -/* GPIO definitions for the WGT634U */ -#define WGT634U_GPIO_LED	3 -#define WGT634U_GPIO_RESET	2 -#define WGT634U_GPIO_TP1	7 -#define WGT634U_GPIO_TP2	6 -#define WGT634U_GPIO_TP3	5 -#define WGT634U_GPIO_TP4	4 -#define WGT634U_GPIO_TP5	1 - -static struct gpio_led wgt634u_leds[] = { -	{ -		.name = "power", -		.gpio = WGT634U_GPIO_LED, -		.active_low = 1, -		.default_trigger = "heartbeat", -	}, -}; - -static struct gpio_led_platform_data wgt634u_led_data = { -	.num_leds =	ARRAY_SIZE(wgt634u_leds), -	.leds =		wgt634u_leds, -}; - -static struct platform_device wgt634u_gpio_leds = { -	.name =		"leds-gpio", -	.id =		-1, -	.dev = { -		.platform_data = &wgt634u_led_data, -	} -}; - - -/* 8MiB flash. The struct mtd_partition matches original Netgear WGT634U -   firmware. */ -static struct mtd_partition wgt634u_partitions[] = { -	{ -		.name	    = "cfe", -		.offset	    = 0, -		.size	    = 0x60000,		/* 384k */ -		.mask_flags = MTD_WRITEABLE	/* force read-only */ -	}, -	{ -		.name	= "config", -		.offset = 0x60000, -		.size	= 0x20000		/* 128k */ -	}, -	{ -		.name	= "linux", -		.offset = 0x80000, -		.size	= 0x140000		/* 1280k */ -	}, -	{ -		.name	= "jffs", -		.offset = 0x1c0000, -		.size	= 0x620000		/* 6272k */ -	}, -	{ -		.name	= "nvram", -		.offset = 0x7e0000, -		.size	= 0x20000		/* 128k */ -	}, -}; - -static struct physmap_flash_data wgt634u_flash_data = { -	.parts	  = wgt634u_partitions, -	.nr_parts = ARRAY_SIZE(wgt634u_partitions) -}; - -static struct resource wgt634u_flash_resource = { -	.flags = IORESOURCE_MEM, -}; - -static struct platform_device wgt634u_flash = { -	.name	       = "physmap-flash", -	.id	       = 0, -	.dev	       = { .platform_data = &wgt634u_flash_data, }, -	.resource      = &wgt634u_flash_resource, -	.num_resources = 1, -}; - -/* Platform devices */ -static struct platform_device *wgt634u_devices[] __initdata = { -	&wgt634u_flash, -	&wgt634u_gpio_leds, -}; - -static irqreturn_t gpio_interrupt(int irq, void *ignored) -{ -	int state; - -	/* Interrupts are shared, check if the current one is -	   a GPIO interrupt. */ -	if (!ssb_chipco_irq_status(&bcm47xx_bus.ssb.chipco, -				   SSB_CHIPCO_IRQ_GPIO)) -		return IRQ_NONE; - -	state = gpio_get_value(WGT634U_GPIO_RESET); - -	/* Interrupt are level triggered, revert the interrupt polarity -	   to clear the interrupt. */ -	ssb_gpio_polarity(&bcm47xx_bus.ssb, 1 << WGT634U_GPIO_RESET, -			  state ? 1 << WGT634U_GPIO_RESET : 0); - -	if (!state) { -		printk(KERN_INFO "Reset button pressed"); -		ctrl_alt_del(); -	} - -	return IRQ_HANDLED; -} - -static int __init wgt634u_init(void) -{ -	/* There is no easy way to detect that we are running on a WGT634U -	 * machine. Use the MAC address as an heuristic. Netgear Inc. has -	 * been allocated ranges 00:09:5b:xx:xx:xx and 00:0f:b5:xx:xx:xx. -	 */ -	u8 *et0mac; - -	if (bcm47xx_bus_type != BCM47XX_BUS_TYPE_SSB) -		return -ENODEV; - -	et0mac = bcm47xx_bus.ssb.sprom.et0mac; - -	if (et0mac[0] == 0x00 && -	    ((et0mac[1] == 0x09 && et0mac[2] == 0x5b) || -	     (et0mac[1] == 0x0f && et0mac[2] == 0xb5))) { -		struct ssb_mipscore *mcore = &bcm47xx_bus.ssb.mipscore; - -		printk(KERN_INFO "WGT634U machine detected.\n"); - -		if (!request_irq(gpio_to_irq(WGT634U_GPIO_RESET), -				 gpio_interrupt, IRQF_SHARED, -				 "WGT634U GPIO", &bcm47xx_bus.ssb.chipco)) { -			gpio_direction_input(WGT634U_GPIO_RESET); -			ssb_gpio_intmask(&bcm47xx_bus.ssb, -					 1 << WGT634U_GPIO_RESET, -					 1 << WGT634U_GPIO_RESET); -			ssb_chipco_irq_mask(&bcm47xx_bus.ssb.chipco, -					    SSB_CHIPCO_IRQ_GPIO, -					    SSB_CHIPCO_IRQ_GPIO); -		} - -		wgt634u_flash_data.width = mcore->pflash.buswidth; -		wgt634u_flash_resource.start = mcore->pflash.window; -		wgt634u_flash_resource.end = mcore->pflash.window -					   + mcore->pflash.window_size -					   - 1; -		return platform_add_devices(wgt634u_devices, -					    ARRAY_SIZE(wgt634u_devices)); -	} else -		return -ENODEV; -} - -module_init(wgt634u_init); diff --git a/arch/mips/bcm47xx/workarounds.c b/arch/mips/bcm47xx/workarounds.c new file mode 100644 index 00000000000..e81ce462307 --- /dev/null +++ b/arch/mips/bcm47xx/workarounds.c @@ -0,0 +1,31 @@ +#include "bcm47xx_private.h" + +#include <linux/gpio.h> +#include <bcm47xx_board.h> +#include <bcm47xx.h> + +static void __init bcm47xx_workarounds_netgear_wnr3500l(void) +{ +	const int usb_power = 12; +	int err; + +	err = gpio_request_one(usb_power, GPIOF_OUT_INIT_HIGH, "usb_power"); +	if (err) +		pr_err("Failed to request USB power gpio: %d\n", err); +	else +		gpio_free(usb_power); +} + +void __init bcm47xx_workarounds(void) +{ +	enum bcm47xx_board board = bcm47xx_board_get(); + +	switch (board) { +	case BCM47XX_BOARD_NETGEAR_WNR3500L: +		bcm47xx_workarounds_netgear_wnr3500l(); +		break; +	default: +		/* No workaround(s) needed */ +		break; +	} +}  | 
