2007-09-25 15:43:07 +02:00
/*
* 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>
2008-02-07 03:17:16 +01:00
# include <linux/mtd/physmap.h>
2007-09-25 15:43:07 +02:00
# include <linux/ssb/ssb.h>
2012-11-20 22:24:34 +00:00
# include <linux/ssb/ssb_embedded.h>
2008-10-14 11:44:43 +02:00
# include <linux/interrupt.h>
# include <linux/reboot.h>
# include <linux/gpio.h>
2007-09-25 15:43:07 +02:00
# 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 = {
2013-01-22 12:59:30 +01:00
. num_leds = ARRAY_SIZE ( wgt634u_leds ) ,
. leds = wgt634u_leds ,
2007-09-25 15:43:07 +02:00
} ;
static struct platform_device wgt634u_gpio_leds = {
2013-01-22 12:59:30 +01:00
. name = " leds-gpio " ,
. id = - 1 ,
2007-09-25 15:43:07 +02:00
. dev = {
. platform_data = & wgt634u_led_data ,
}
} ;
2008-02-07 03:17:16 +01:00
/* 8MiB flash. The struct mtd_partition matches original Netgear WGT634U
firmware . */
static struct mtd_partition wgt634u_partitions [ ] = {
{
2013-01-22 12:59:30 +01:00
. name = " cfe " ,
. offset = 0 ,
. size = 0x60000 , /* 384k */
. mask_flags = MTD_WRITEABLE /* force read-only */
2008-02-07 03:17:16 +01:00
} ,
{
2013-01-22 12:59:30 +01:00
. name = " config " ,
2008-02-07 03:17:16 +01:00
. offset = 0x60000 ,
2013-01-22 12:59:30 +01:00
. size = 0x20000 /* 128k */
2008-02-07 03:17:16 +01:00
} ,
{
2013-01-22 12:59:30 +01:00
. name = " linux " ,
2008-02-07 03:17:16 +01:00
. offset = 0x80000 ,
2013-01-22 12:59:30 +01:00
. size = 0x140000 /* 1280k */
2008-02-07 03:17:16 +01:00
} ,
{
2013-01-22 12:59:30 +01:00
. name = " jffs " ,
2008-02-07 03:17:16 +01:00
. offset = 0x1c0000 ,
2013-01-22 12:59:30 +01:00
. size = 0x620000 /* 6272k */
2008-02-07 03:17:16 +01:00
} ,
{
2013-01-22 12:59:30 +01:00
. name = " nvram " ,
2008-02-07 03:17:16 +01:00
. offset = 0x7e0000 ,
2013-01-22 12:59:30 +01:00
. size = 0x20000 /* 128k */
2008-02-07 03:17:16 +01:00
} ,
} ;
static struct physmap_flash_data wgt634u_flash_data = {
2013-01-22 12:59:30 +01:00
. parts = wgt634u_partitions ,
2008-02-07 03:17:16 +01:00
. nr_parts = ARRAY_SIZE ( wgt634u_partitions )
} ;
static struct resource wgt634u_flash_resource = {
. flags = IORESOURCE_MEM ,
} ;
static struct platform_device wgt634u_flash = {
2013-01-22 12:59:30 +01:00
. name = " physmap-flash " ,
. id = 0 ,
. dev = { . platform_data = & wgt634u_flash_data , } ,
2008-02-07 03:17:16 +01:00
. resource = & wgt634u_flash_resource ,
. num_resources = 1 ,
} ;
/* Platform devices */
static struct platform_device * wgt634u_devices [ ] __initdata = {
& wgt634u_flash ,
& wgt634u_gpio_leds ,
} ;
2008-10-14 11:44:43 +02:00
static irqreturn_t gpio_interrupt ( int irq , void * ignored )
{
int state ;
/* Interrupts are shared, check if the current one is
a GPIO interrupt . */
2011-07-23 01:20:12 +02:00
if ( ! ssb_chipco_irq_status ( & bcm47xx_bus . ssb . chipco ,
2008-10-14 11:44:43 +02:00
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 . */
2012-11-20 22:24:34 +00:00
ssb_gpio_polarity ( & bcm47xx_bus . ssb , 1 < < WGT634U_GPIO_RESET ,
state ? 1 < < WGT634U_GPIO_RESET : 0 ) ;
2008-10-14 11:44:43 +02:00
if ( ! state ) {
printk ( KERN_INFO " Reset button pressed " ) ;
ctrl_alt_del ( ) ;
}
return IRQ_HANDLED ;
}
2007-09-25 15:43:07 +02:00
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 : 5 b : xx : xx : xx and 00 : 0f : b5 : xx : xx : xx .
*/
2011-07-23 01:20:12 +02:00
u8 * et0mac ;
2007-09-25 15:43:07 +02:00
2011-07-23 01:20:12 +02:00
if ( bcm47xx_bus_type ! = BCM47XX_BUS_TYPE_SSB )
return - ENODEV ;
et0mac = bcm47xx_bus . ssb . sprom . et0mac ;
2007-09-25 15:43:07 +02:00
if ( et0mac [ 0 ] = = 0x00 & &
( ( et0mac [ 1 ] = = 0x09 & & et0mac [ 2 ] = = 0x5b ) | |
2008-02-07 03:17:16 +01:00
( et0mac [ 1 ] = = 0x0f & & et0mac [ 2 ] = = 0xb5 ) ) ) {
2011-07-23 01:20:12 +02:00
struct ssb_mipscore * mcore = & bcm47xx_bus . ssb . mipscore ;
2008-10-14 11:42:10 +02:00
printk ( KERN_INFO " WGT634U machine detected. \n " ) ;
2008-10-14 11:44:43 +02:00
if ( ! request_irq ( gpio_to_irq ( WGT634U_GPIO_RESET ) ,
gpio_interrupt , IRQF_SHARED ,
2011-07-23 01:20:12 +02:00
" WGT634U GPIO " , & bcm47xx_bus . ssb . chipco ) ) {
2008-10-14 11:44:43 +02:00
gpio_direction_input ( WGT634U_GPIO_RESET ) ;
2012-11-20 22:24:34 +00:00
ssb_gpio_intmask ( & bcm47xx_bus . ssb ,
1 < < WGT634U_GPIO_RESET ,
1 < < WGT634U_GPIO_RESET ) ;
2011-07-23 01:20:12 +02:00
ssb_chipco_irq_mask ( & bcm47xx_bus . ssb . chipco ,
2008-10-14 11:44:43 +02:00
SSB_CHIPCO_IRQ_GPIO ,
SSB_CHIPCO_IRQ_GPIO ) ;
}
2012-09-29 20:36:17 +02:00
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
2008-02-07 03:17:16 +01:00
- 1 ;
return platform_add_devices ( wgt634u_devices ,
ARRAY_SIZE ( wgt634u_devices ) ) ;
} else
2007-09-25 15:43:07 +02:00
return - ENODEV ;
}
module_init ( wgt634u_init ) ;