Hi,
Attached is the kernel patch to support Netgear WNR3500L. All changes are made under CONFIG_WNR3500L. I have used trunk source code of version number 21251 to create this kernel patch.

Regards,
Tathagata <tathag...@alumnux.com>


diff -Naur a/arch/mips/bcm47xx/irq.c b/arch/mips/bcm47xx/irq.c
--- a/arch/mips/bcm47xx/irq.c   2010-05-13 18:22:34.000000000 +0530
+++ b/arch/mips/bcm47xx/irq.c   2010-05-13 18:19:35.000000000 +0530
@@ -30,6 +30,9 @@
 #include <linux/irq.h>
 #include <linux/pci.h>
 #include <linux/ssb/ssb.h>
+#ifdef CONFIG_WNR3500L
+#include <linux/ssb/ssb_driver_mips.h>
+#endif
 
 #include <asm/irq_cpu.h>
 
@@ -37,7 +40,11 @@
 extern struct ssb_bus ssb_bcm47xx;
 
 
+#ifndef CONFIG_WNR3500L
 void plat_irq_dispatch(void)
+#else
+void asmlinkage plat_irq_dispatch(void)
+#endif
 {
        u32 cause;
 
@@ -61,5 +68,12 @@
 
 void __init arch_init_irq(void)
 {
+#ifdef CONFIG_WNR3500L
+       if (ssb_bcm47xx.mipscore.dev->id.coreid == SSB_DEV_MIPS_74K) { 
+               ssb_write32(ssb_bcm47xx.mipscore.dev, 
SSB_MIPS74K_INT_CONTROL(5), 1 << 31); 
+       } 
+       /* the kernel reads the timer irq from some register and beleave it's 
#5, but we route it to #7 */ 
+       cp0_compare_irq = 7; 
+#endif
        mips_cpu_irq_init();
 }
diff -Naur a/arch/mips/include/asm/r4kcache.h b/arch/mips/include/asm/r4kcache.h
--- a/arch/mips/include/asm/r4kcache.h  2010-05-13 18:22:34.000000000 +0530
+++ b/arch/mips/include/asm/r4kcache.h  2010-05-13 18:19:36.000000000 +0530
@@ -22,9 +22,15 @@
 #include <linux/ssb/ssb.h>
 #define BCM4710_DUMMY_RREG() bcm4710_dummy_rreg()
 
+#ifndef CONFIG_WNR3500L
 static inline unsigned long bcm4710_dummy_rreg(void) {
       return (*(volatile unsigned long *)(KSEG1ADDR(SSB_ENUM_BASE + 
SSB_IMSTATE)));
 }
+#else
+static inline unsigned long bcm4710_dummy_rreg(void) {
+      return (*(volatile unsigned long *)(KSEG1ADDR(SSB_ENUM_BASE)));
+}
+#endif
 
 #define BCM4710_FILL_TLB(addr) bcm4710_fill_tlb((void*)(addr))
 
diff -Naur a/arch/mips/Kconfig b/arch/mips/Kconfig
--- a/arch/mips/Kconfig 2010-05-13 18:22:35.000000000 +0530
+++ b/arch/mips/Kconfig 2010-05-13 18:19:37.000000000 +0530
@@ -9,6 +9,10 @@
        select EMBEDDED
        select RTC_LIB if !LEMOTE_FULOONG2E
 
+config WNR3500L
+       bool "Netgear WNR3500L"
+       default y
+
 mainmenu "Linux/MIPS Kernel Configuration"
 
 menu "Machine selection"
diff -Naur a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
--- a/drivers/mtd/devices/Kconfig       2010-05-13 18:23:09.000000000 +0530
+++ b/drivers/mtd/devices/Kconfig       2010-05-13 18:20:36.000000000 +0530
@@ -3,6 +3,9 @@
 menu "Self-contained MTD device drivers"
        depends on MTD!=n
 
+config MTD_SFLASH
+       bool "Broadcom Chipcommon Serial Flash support"
+
 config MTD_PMC551
        tristate "Ramix PMC551 PCI Mezzanine RAM card support"
        depends on PCI
diff -Naur a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
--- a/drivers/mtd/devices/Makefile      2010-05-13 18:23:09.000000000 +0530
+++ b/drivers/mtd/devices/Makefile      2010-05-13 18:20:36.000000000 +0530
@@ -2,6 +2,7 @@
 # linux/drivers/devices/Makefile
 #
 
+obj-$(CONFIG_MTD_SFLASH)   += sflash.o
 obj-$(CONFIG_MTD_DOC2000)      += doc2000.o
 obj-$(CONFIG_MTD_DOC2001)      += doc2001.o
 obj-$(CONFIG_MTD_DOC2001PLUS)  += doc2001plus.o
diff -Naur a/drivers/mtd/devices/sflash.c b/drivers/mtd/devices/sflash.c
--- a/drivers/mtd/devices/sflash.c      1970-01-01 05:30:00.000000000 +0530
+++ b/drivers/mtd/devices/sflash.c      2010-05-13 18:20:36.000000000 +0530
@@ -0,0 +1,925 @@
+/*
+ * Broadcom SiliconBackplane chipcommon serial flash interface
+ *
+ * Copyright 2007, Broadcom Corporation
+ * All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/mtd/compatmac.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <linux/ssb/ssb.h>
+#include <linux/ssb/ssb_embedded.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+
+extern struct ssb_bus ssb_bcm47xx;
+#ifdef CONFIG_MTD_PARTITIONS
+extern struct mtd_partition * init_mtd_partitions(struct mtd_info *mtd, size_t 
size);
+#endif
+
+struct sflash_mtd {
+       u32 *base_regs;
+       struct semaphore lock;
+       struct mtd_info mtd;
+       struct mtd_erase_region_info region;
+};
+
+struct sflash {
+   u32 blocksize;      /* Block size */
+   u32 numblocks;      /* Number of blocks */
+   u32 type;      /* Type */
+   u32 size;     /* Total size in bytes */
+};
+
+static struct sflash wnr3500l_sflash;
+
+/* Private global state */
+static struct sflash_mtd sflash;
+
+//extern unsigned long volatile __jiffy_data jiffies;
+
+#define CC_CORE_ID       0x800    /* chipcommon core */
+#define SB_FLASH2      0x1c000000  /* Flash Region 2 (region 1 shadowed here) 
*/
+#define CC_CAP_FLASH_MASK 0x00000700  /* Type of flash */
+#define SFLASH_START    0x80000000
+#define SFLASH_BUSY     SFLASH_START
+#define SFLASH_ST    0x100    /* ST serial flash */
+#define SFLASH_AT    0x200    /* Atmel serial flash */
+#define SFLASH_AT_STATUS         0x01d7
+#define SFLASH_ST_DP    0x00b9      /* Deep Power-down */
+#define SFLASH_ST_RES      0x03ab      /* Read Electronic Signature */
+#define SFLASH_ST_RDSR     0x0105      /* Read Status Register */
+#define SFLASH_ST_WIP      0x01     /* Write In Progress */
+#define SFLASH_AT_READY          0x80
+
+#define  OSL_UNCACHED(va)  ((void *)KSEG1ADDR(va))
+#define  OSL_CACHED(va)    ((void *)KSEG0ADDR(va))
+
+typedef unsigned long long int uintptr;
+
+/* Issue a serial flash command */
+static inline void sflash_cmd(u32 opcode)
+{
+       u32 *regs;
+
+       regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 0x40, 
SSB_CORE_SIZE);
+       writel(SFLASH_START | opcode, regs);
+       while ((readl(regs) & SFLASH_BUSY));
+
+       iounmap(regs);
+}
+
+int sflash_read(u32 offset, u32 len, unsigned char *buf)
+{
+       u8 *from, *to;
+       int cnt, i;
+
+       if (!len)
+               return 0;
+
+       if ((offset + len) > wnr3500l_sflash.size)
+               return -22;
+
+       if ((len >= 4) && (offset & 3))
+               cnt = 4 - (offset & 3);
+       else if ((len >= 4) && ((uintptr)buf & 3))
+               cnt = 4 - ((uintptr)buf & 3);
+       else
+               cnt = len;
+
+       if (ssb_bcm47xx.chipco.dev->id.revision == 12)
+               from = (u8 *)OSL_UNCACHED(SB_FLASH2 + offset);
+       else
+               from = (u8 *)OSL_CACHED(SB_FLASH2 + offset);
+       to = (u8 *)buf;
+
+       if (cnt < 4) {
+               for (i = 0; i < cnt; i ++) {
+                       /* Cannot use R_REG because in bigendian that will
+                        * xor the address and we don't want that here.
+                        */
+                       *to = *from;
+                       from ++;
+                       to ++;
+               }
+               return cnt;
+       }
+
+       while (cnt >= 4) {
+               *(u32 *)to = *(u32 *)from;
+               from += 4;
+               to += 4;
+               cnt -= 4;
+       }
+
+       return (len - cnt);
+}
+
+/* Poll for command completion. Returns zero when complete. */
+int sflash_poll(u32 offset)
+{
+       u32 *regs, val;
+
+       if (offset >= wnr3500l_sflash.size)
+               return -22;
+
+       switch (wnr3500l_sflash.type) {
+       case SFLASH_ST:
+               /* Check for ST Write In Progress bit */
+               sflash_cmd(SFLASH_ST_RDSR);
+               regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 0x48, 
SSB_CORE_SIZE);
+      val = readl(regs) & SFLASH_ST_WIP;
+      iounmap(regs);
+               return val;
+       case SFLASH_AT:
+               /* Check for Atmel Ready bit */
+               sflash_cmd(SFLASH_AT_STATUS);
+               regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 0x48, 
SSB_CORE_SIZE);
+      val = readl(regs) & SFLASH_AT_READY;
+      iounmap(regs);
+               return !val;
+       }
+
+       return 0;
+}
+
+#if 1
+#if 1 //Imran added
+#define BCM4712_CHIP_ID         0x4712          /* 4712 chipcommon chipid */
+
+/* flashcontrol action+opcodes for ST flashes */
+#define SFLASH_ST_WREN          0x0006          /* Write Enable */
+#define SFLASH_ST_WRDIS         0x0004          /* Write Disable */
+#define SFLASH_ST_RDSR          0x0105          /* Read Status Register */
+#define SFLASH_ST_WRSR          0x0101          /* Write Status Register */
+#define SFLASH_ST_READ          0x0303          /* Read Data Bytes */
+#define SFLASH_ST_PP            0x0302          /* Page Program */
+#define SFLASH_ST_SE            0x02d8          /* Sector Erase */
+#define SFLASH_ST_BE            0x00c7          /* Bulk Erase */
+#define SFLASH_ST_DP            0x00b9          /* Deep Power-down */
+#define SFLASH_ST_RES           0x03ab          /* Read Electronic Signature */
+#define SFLASH_ST_CSA           0x1000          /* Keep chip select asserted */
+
+/* flashcontrol action+opcodes for Atmel flashes */
+#define SFLASH_AT_READ                          0x07e8
+#define SFLASH_AT_PAGE_READ                     0x07d2
+#define SFLASH_AT_BUF1_READ
+#define SFLASH_AT_BUF2_READ
+#define SFLASH_AT_STATUS                        0x01d7
+#define SFLASH_AT_BUF1_WRITE                    0x0384
+#define SFLASH_AT_BUF2_WRITE                    0x0387
+#define SFLASH_AT_BUF1_ERASE_PROGRAM            0x0283
+#define SFLASH_AT_BUF2_ERASE_PROGRAM            0x0286
+#define SFLASH_AT_BUF1_PROGRAM                  0x0288
+#define SFLASH_AT_BUF2_PROGRAM                  0x0289
+#define SFLASH_AT_PAGE_ERASE                    0x0281
+#define SFLASH_AT_BLOCK_ERASE                   0x0250
+#define SFLASH_AT_BUF1_WRITE_ERASE_PROGRAM      0x0382
+#define SFLASH_AT_BUF2_WRITE_ERASE_PROGRAM      0x0385
+#define SFLASH_AT_BUF1_LOAD                     0x0253
+#define SFLASH_AT_BUF2_LOAD                     0x0255
+#define SFLASH_AT_BUF1_COMPARE                  0x0260
+#define SFLASH_AT_BUF2_COMPARE                  0x0261
+#define SFLASH_AT_BUF1_REPROGRAM                0x0258
+#define SFLASH_AT_BUF2_REPROGRAM                0x0259
+
+#ifndef MIN
+#define MIN(a, b)               (((a) < (b))?(a):(b))
+#endif /* MIN */
+
+/*
+ *  * Spin at most 'us' microseconds while 'exp' is true.
+ *   * Caller should explicitly test 'exp' when this completes
+ *    * and take appropriate error action if 'exp' is still true.
+ *     */
+#define SPINWAIT(exp, us) { \
+        uint countdown = (us) + 9; \
+        while ((exp) && (countdown >= 10)) {\
+                osl_delay(10); \
+                countdown -= 10; \
+        } \
+}
+
+#endif
+/* Write len bytes starting at offset into buf. Returns number of bytes
+ * written. Caller should poll for completion.
+ */
+#define        ST_RETRIES      3
+
+#define        GET_BYTE(ptr)   (*(u8 *)((u32)(ptr) ^ 7))
+
+void
+osl_delay(uint usec)
+{
+        uint d;
+
+        while (usec > 0) {
+                d = MIN(usec, 1000);
+                udelay(d);
+                usec -= d;
+        }
+}
+
+
+int sflash_write(u32 offset, u32 length, const unsigned char *buffer)
+{
+       struct sflash *sfl;
+       u32 off = offset, len = length;
+       const u8 *buf = buffer;
+       u8 data;
+       int ret = 0, ntry = 0;
+       bool is4712b0;
+       u32 page, byte, mask;
+       void *regs;
+
+       if (!len)
+               return 0;
+
+       sfl = &wnr3500l_sflash;
+       if ((off + len) > sfl->size)
+               return -22;
+
+       switch (sfl->type) {
+       case SFLASH_ST:
+               //is4712b0 = (ssb_bcm47xx.chipco.dev->id.chip_id == 
BCM4712_CHIP_ID) && (ssb_bcm47xx.chipco.dev->id.revision == 3);
+               is4712b0 = (ssb_bcm47xx.chip_id == BCM4712_CHIP_ID) && 
(ssb_bcm47xx.chipco.dev->id.revision == 3);
+               /* Enable writes */
+retry:         sflash_cmd(SFLASH_ST_WREN);
+               off = offset;
+               len = length;
+               buf = buffer;
+               ntry++;
+               if (is4712b0) {
+                       mask = 1 << 14;
+                       regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 
0x44, SSB_CORE_SIZE);
+                       writel(off, regs);
+                       iounmap(regs);
+                       data = GET_BYTE(buf);
+                       buf++;
+                       //W_REG(osh, &cc->flashdata, data);
+                       regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 
0x48, SSB_CORE_SIZE);
+                       writel(data, regs);
+                       iounmap(regs);
+                       /* Set chip select */
+                       //OR_REG(osh, &cc->gpioout, mask);
+                       regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 
0x64, SSB_CORE_SIZE);
+                       writel((mask | readl(regs)), regs);
+                       iounmap(regs);
+                       /* Issue a page program with the first byte */
+                       sflash_cmd(SFLASH_ST_PP);
+                       ret = 1;
+                       off++;
+                       len--;
+                       while (len > 0) {
+                               if ((off & 255) == 0) {
+                                       /* Page boundary, drop cs and return */
+                                       //AND_REG(osh, &cc->gpioout, ~mask);
+                                       regs = 
ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 0x64, SSB_CORE_SIZE);
+                                       writel((~mask & readl(regs)), regs);
+                                       iounmap(regs);
+                                       osl_delay(1);
+                                       if (!sflash_poll(off)) {
+                                               /* Flash rejected command */
+                                               if (ntry <= ST_RETRIES)
+                                                       goto retry;
+                                               else
+                                                       return -11;
+                                       }
+                                       return ret;
+                               } else {
+                                       /* Write single byte */
+                                       data = GET_BYTE(buf);
+                                       buf++;
+                                       sflash_cmd(data);
+                               }
+                               ret++;
+                               off++;
+                               len--;
+                       }
+                       /* All done, drop cs */
+                       //AND_REG(osh, &cc->gpioout, ~mask);
+                       regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 
0x64, SSB_CORE_SIZE);
+                       writel((~mask & readl(regs)), regs);
+                       iounmap(regs);
+                       osl_delay(1);
+                       if (!sflash_poll(off)) {
+                               /* Flash rejected command */
+                               if (ntry <= ST_RETRIES)
+                                       goto retry;
+                               else
+                                       return -12;
+                       }
+               } else if (ssb_bcm47xx.chipco.dev->id.revision >= 20) {
+                       //W_REG(osh, &cc->flashaddress, off);
+                       regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 
0x44, SSB_CORE_SIZE);
+                       writel(off, regs);
+                       iounmap(regs);
+                       data = GET_BYTE(buf);
+                       buf++;
+                       //W_REG(osh, &cc->flashdata, data);
+                       regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 
0x48, SSB_CORE_SIZE);
+                       writel(data, regs);
+                       iounmap(regs);
+                       /* Issue a page program with CSA bit set */
+                       sflash_cmd(SFLASH_ST_CSA | SFLASH_ST_PP);
+                       ret = 1;
+                       off++;
+                       len--;
+                       while (len > 0) {
+                               if ((off & 255) == 0) {
+                                       /* Page boundary, poll droping cs and 
return */
+                                       //W_REG(NULL, &cc->flashcontrol, 0);
+                                       regs = 
ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 0x40, SSB_CORE_SIZE);
+                                       writel(0, regs);
+                                       iounmap(regs);
+                                       osl_delay(1);
+                                       if (sflash_poll(off) == 0) {
+                                               /* Flash rejected command */
+                                               //SFL_MSG(("sflash: pp 
rejected, ntry: %d,"
+                                                 //       " off: %d/%d, len: 
%d/%d, ret:"
+                                                   //     "%d\n", ntry, off, 
offset, len,
+                                                     //   length, ret));
+                                               if (ntry <= ST_RETRIES)
+                                                       goto retry;
+                                               else
+                                                       return -11;
+                                       }
+                                       return ret;
+                               } else {
+                                       /* Write single byte */
+                                       data = GET_BYTE(buf);
+                                       buf++;
+                                       sflash_cmd(SFLASH_ST_CSA | data);
+                               }
+                               ret++;
+                               off++;
+                               len--;
+                       }
+                       /* All done, drop cs & poll */
+                       //W_REG(NULL, &cc->flashcontrol, 0);
+                       regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 
0x40, SSB_CORE_SIZE);
+                       writel(0, regs);
+                       iounmap(regs);
+                       osl_delay(1);
+                       if (sflash_poll(off) == 0) {
+                               /* Flash rejected command */
+                               //SFL_MSG(("sflash: pp rejected, ntry: %d, off: 
%d/%d,"
+                                 //       " len: %d/%d, ret: %d\n",
+                                   //     ntry, off, offset, len, length, 
ret));
+                               if (ntry <= ST_RETRIES)
+                                       goto retry;
+                               else
+                                       return -12;
+                       }
+               } else {
+                       ret = 1;
+                       //W_REG(osh, &cc->flashaddress, off);
+                       regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 
0x44, SSB_CORE_SIZE);
+                       writel(off, regs);
+                       iounmap(regs);
+                       data = GET_BYTE(buf);
+                       buf++;
+                       //W_REG(osh, &cc->flashdata, data);
+                       regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 
0x48, SSB_CORE_SIZE);
+                       writel(data, regs);
+                       iounmap(regs);
+                       /* Page program */
+                       sflash_cmd(SFLASH_ST_PP);
+               }
+               break;
+       case SFLASH_AT:
+               mask = sfl->blocksize - 1;
+               page = (off & ~mask) << 1;
+               byte = off & mask;
+               /* Read main memory page into buffer 1 */
+               if (byte || (len < sfl->blocksize)) {
+                       regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 
0x44, SSB_CORE_SIZE);
+                       writel(page, regs);
+                       iounmap(regs);
+                       sflash_cmd(SFLASH_AT_BUF1_LOAD);
+                       /* 250 us for AT45DB321B */
+                       SPINWAIT(sflash_poll(off), 1000);
+               }
+               /* Write into buffer 1 */
+               for (ret = 0; (ret < (int)len) && (byte < sfl->blocksize); 
ret++) {
+                       regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 
0x44, SSB_CORE_SIZE);
+                       writel(byte++, regs);
+                       iounmap(regs);
+                       regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 
0x48, SSB_CORE_SIZE);
+                       writel(*buf++, regs);
+                       iounmap(regs);
+                       sflash_cmd(SFLASH_AT_BUF1_WRITE);
+               }
+               /* Write buffer 1 into main memory page */
+               regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 0x44, 
SSB_CORE_SIZE);
+               writel(page, regs);
+               iounmap(regs);
+               sflash_cmd(SFLASH_AT_BUF1_PROGRAM);
+               break;
+       }
+
+       return ret;
+}
+
+/* Erase a region. Returns number of bytes scheduled for erasure.
+ * Caller should poll for completion.
+ */
+int
+//sflash_erase(sb_t *sbh, chipcregs_t *cc, uint offset)
+sflash_erase(uint offset)
+{
+       struct sflash *sfl;
+       //osl_t *osh;
+       void *regs;
+       //ASSERT(sbh);
+
+       //osh = sb_osh(sbh);
+
+       sfl = &sflash;
+       if (offset >= sfl->size)
+               return -22;
+
+       switch (sfl->type) {
+       case SFLASH_ST:
+               sflash_cmd(SFLASH_ST_WREN);
+               //W_REG(osh, &cc->flashaddress, offset);
+               regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 0x44, 
SSB_CORE_SIZE);
+               writel(offset, regs);
+               iounmap(regs);
+               sflash_cmd(SFLASH_ST_SE);
+               return sfl->blocksize;
+       case SFLASH_AT:
+               //W_REG(osh, &cc->flashaddress, offset << 1);
+               regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 0x44, 
SSB_CORE_SIZE);
+               writel(offset << 1, regs);
+               iounmap(regs);
+               sflash_cmd(SFLASH_AT_PAGE_ERASE);
+               return sfl->blocksize;
+       }
+
+       return 0;
+}
+
+/*
+ * writes the appropriate range of flash, a NULL buf simply erases
+ * the region of flash
+ */
+int
+//sflash_commit(sb_t *sbh, chipcregs_t *cc, uint offset, uint len, const uchar 
*buf)
+sflash_commit(uint offset, uint len, const u8 *buf)
+{
+       struct sflash *sfl;
+       u8 *block = NULL, *cur_ptr, *blk_ptr;
+       uint blocksize = 0, mask, cur_offset, cur_length, cur_retlen, remainder;
+       uint blk_offset, blk_len, copied;
+       int bytes, ret = 0;
+       //osl_t *osh;
+
+       //ASSERT(sbh);
+
+       //osh = sb_osh(sbh);
+
+       /* Check address range */
+       if (len <= 0)
+               return 0;
+
+       sfl = &sflash;
+       if ((offset + len) > sfl->size)
+               return -1;
+
+       blocksize = sfl->blocksize;
+       mask = blocksize - 1;
+
+       /* Allocate a block of mem */
+       //if (!(block = MALLOC(osh, blocksize)))
+       if (!(block = kmalloc(blocksize, GFP_ATOMIC)))
+               return -1;
+
+       while (len) {
+               /* Align offset */
+               cur_offset = offset & ~mask;
+               cur_length = blocksize;
+               cur_ptr = block;
+
+               remainder = blocksize - (offset & mask);
+               if (len < remainder)
+                       cur_retlen = len;
+               else
+                       cur_retlen = remainder;
+
+               /* buf == NULL means erase only */
+               if (buf) {
+                       /* Copy existing data into holding block if necessary */
+                       if ((offset & mask) || (len < blocksize)) {
+                               blk_offset = cur_offset;
+                               blk_len = cur_length;
+                               blk_ptr = cur_ptr;
+
+                               /* Copy entire block */
+                               while (blk_len) {
+                                       //copied = sflash_read(sbh, cc, 
blk_offset, blk_len, blk_ptr);
+                                       copied = sflash_read(blk_offset, 
blk_len, blk_ptr);
+                                       blk_offset += copied;
+                                       blk_len -= copied;
+                                       blk_ptr += copied;
+                               }
+                       }
+
+                       /* Copy input data into holding block */
+                       memcpy(cur_ptr + (offset & mask), buf, cur_retlen);
+               }
+
+               /* Erase block */
+               //if ((ret = sflash_erase(sbh, cc, (uint) cur_offset)) < 0)
+               if ((ret = sflash_erase((uint) cur_offset)) < 0)
+                       goto done;
+               //while (sflash_poll(sbh, cc, (uint) cur_offset));
+               while (sflash_poll((uint) cur_offset));
+
+               /* buf == NULL means erase only */
+               if (!buf) {
+                       offset += cur_retlen;
+                       len -= cur_retlen;
+                       continue;
+               }
+
+               /* Write holding block */
+               while (cur_length > 0) {
+                       if ((bytes = sflash_write((uint) cur_offset,
+                                                 (uint) cur_length,
+                                                 (u8 *) cur_ptr)) < 0) {
+                               ret = bytes;
+                               goto done;
+                       }
+                       //while (sflash_poll(sbh, cc, (uint) cur_offset));
+                       while (sflash_poll((uint) cur_offset));
+                       cur_offset += bytes;
+                       cur_length -= bytes;
+                       cur_ptr += bytes;
+               }
+
+               offset += cur_retlen;
+               len -= cur_retlen;
+               buf += cur_retlen;
+       }
+
+       ret = len;
+done:
+       if (block)
+               //MFREE(osh, block, blocksize);
+               kfree(block);
+       return ret;
+}
+#endif
+
+static int
+sflash_mtd_poll(struct sflash_mtd *sflash, unsigned int offset, int timeout)
+{
+       int now = jiffies;
+       int ret = 0;
+
+       for (;;) {
+               if (!sflash_poll(offset)) {
+                       ret = 0;
+                       break;
+               }
+               if (time_after((unsigned long)jiffies, (unsigned long)(now + 
timeout))) {
+                       printk(KERN_ERR "sflash: timeout\n");
+                       ret = -ETIMEDOUT;
+                       break;
+               }
+               udelay(1);
+       }
+
+       return ret;
+}
+
+static int
+sflash_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, 
u_char *buf)
+{
+       struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv;
+       int bytes, ret = 0;
+
+       if (retlen)
+               *retlen = 0;
+
+       /* Check address range */
+       if (!len)
+               return 0;
+       if ((from + len) > mtd->size)
+               return -EINVAL;
+
+       down(&sflash->lock);
+
+       while (len) {
+               if ((bytes = sflash_read((u32) from, len, buf)) < 0) {
+                       ret = bytes;
+                       break;
+               }
+               from += (loff_t) bytes;
+               len -= bytes;
+               buf += bytes;
+               if (retlen)
+                       *retlen += bytes;
+       }
+
+       up(&sflash->lock);
+
+       return ret;
+}
+
+static int
+sflash_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, 
const u_char *buf)
+{
+       struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv;
+       int bytes, ret = 0;
+
+       if (retlen)
+               *retlen = 0;
+
+       /* Check address range */
+       if (!len)
+               return 0;
+       if ((to + len) > mtd->size)
+               return -EINVAL;
+
+       down(&sflash->lock);
+
+       while (len) {
+               if ((bytes = sflash_write((u32) to, len, buf)) < 0) {
+                       ret = bytes;
+                       break;
+               }
+               if ((ret = sflash_mtd_poll(sflash, (unsigned int) to, HZ / 10)))
+                       break;
+               to += (loff_t) bytes;
+               len -= bytes;
+               buf += bytes;
+               if (retlen)
+                       *retlen += bytes;
+       }
+
+       up(&sflash->lock);
+
+       return ret;
+}
+
+static int
+sflash_mtd_erase(struct mtd_info *mtd, struct erase_info *erase)
+{
+       struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv;
+       int i, j, ret = 0;
+       unsigned int addr, len;
+
+       /* Check address range */
+       if (!erase->len)
+               return 0;
+       if ((erase->addr + erase->len) > mtd->size)
+               return -EINVAL;
+
+       addr = erase->addr;
+       len = erase->len;
+
+       down(&sflash->lock);
+
+       /* Ensure that requested region is aligned */
+       for (i = 0; i < mtd->numeraseregions; i++) {
+               for (j = 0; j < mtd->eraseregions[i].numblocks; j++) {
+                       if (addr == mtd->eraseregions[i].offset + 
mtd->eraseregions[i].erasesize * j && len >= mtd->eraseregions[i].erasesize) {
+#if 1 /* Tatha */
+                               //if ((ret = sflash_erase(sflash->sbh, 
sflash->cc, addr)) < 0)
+                               if ((ret = sflash_erase(addr)) < 0)
+                                       break;
+#endif
+                               if ((ret = sflash_mtd_poll(sflash, addr, 10 * 
HZ)))
+                                       break;
+                               addr += mtd->eraseregions[i].erasesize;
+                               len -= mtd->eraseregions[i].erasesize;
+                       }
+               }
+               if (ret)
+                       break;
+       }
+
+       up(&sflash->lock);
+
+       /* Set erase status */
+       if (ret)
+               erase->state = MTD_ERASE_FAILED;
+       else 
+               erase->state = MTD_ERASE_DONE;
+
+       /* Call erase callback */
+       if (erase->callback)
+               erase->callback(erase);
+
+       return ret;
+}
+
+u32 sflash_init(void)
+{
+       u32 id, id2;
+       u32 *regs;
+
+       memset(&wnr3500l_sflash, 0, sizeof(wnr3500l_sflash));
+
+       wnr3500l_sflash.type = ssb_bcm47xx.chipco.capabilities & 
CC_CAP_FLASH_MASK;
+
+       switch (wnr3500l_sflash.type) {
+               case SFLASH_ST:
+               /* Probe for ST chips */
+               sflash_cmd(SFLASH_ST_DP);
+               sflash_cmd(SFLASH_ST_RES);
+               regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 0x48, 
SSB_CORE_SIZE);
+               id = readl(regs);
+               iounmap(regs);
+               switch (id) {
+                       case 0x11:
+                       /* ST M25P20 2 Mbit Serial Flash */
+                       wnr3500l_sflash.blocksize = 64 * 1024;
+                       wnr3500l_sflash.numblocks = 4;
+                       break;
+               case 0x12:
+                       /* ST M25P40 4 Mbit Serial Flash */
+                       wnr3500l_sflash.blocksize = 64 * 1024;
+                       wnr3500l_sflash.numblocks = 8;
+                       break;
+               case 0x13:
+                       /* ST M25P80 8 Mbit Serial Flash */
+                       wnr3500l_sflash.blocksize = 64 * 1024;
+                       wnr3500l_sflash.numblocks = 16;
+                       break;
+               case 0x14:
+                       /* ST M25P16 16 Mbit Serial Flash */
+                       wnr3500l_sflash.blocksize = 64 * 1024;
+                       wnr3500l_sflash.numblocks = 32;
+                       break;
+               case 0x15:
+                       /* ST M25P32 32 Mbit Serial Flash */
+                       wnr3500l_sflash.blocksize = 64 * 1024;
+                       wnr3500l_sflash.numblocks = 64;
+                       break;
+               case 0x16:
+                       /* ST M25P64 64 Mbit Serial Flash */
+                       wnr3500l_sflash.blocksize = 64 * 1024;
+                       wnr3500l_sflash.numblocks = 128;
+                       break;
+               case 0xbf:
+                       regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 
0x44, SSB_CORE_SIZE);
+                       writel(1, regs);
+                       iounmap(regs);
+                       sflash_cmd(SFLASH_ST_RES);
+                       regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 
0x48, SSB_CORE_SIZE);
+                       id2 = readl(regs);
+                       iounmap(regs);
+                       if (id2 == 0x44) {
+                               /* SST M25VF80 4 Mbit Serial Flash */
+                               wnr3500l_sflash.blocksize = 64 * 1024;
+                               wnr3500l_sflash.numblocks = 8;
+                       }
+                       break;
+               }
+               break;
+
+               case SFLASH_AT:
+               /* Probe for Atmel chips */
+               sflash_cmd(SFLASH_AT_STATUS);
+               regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 0x48, 
SSB_CORE_SIZE);
+               id = readl(regs) & 0x3C;
+               iounmap(regs);
+               switch (id) {
+                       case 0xc:
+                       /* Atmel AT45DB011 1Mbit Serial Flash */
+                       wnr3500l_sflash.blocksize = 256;
+                       wnr3500l_sflash.numblocks = 512;
+                       break;
+                       case 0x14:
+                       /* Atmel AT45DB021 2Mbit Serial Flash */
+                       wnr3500l_sflash.blocksize = 256;
+                       wnr3500l_sflash.numblocks = 1024;
+                       break;
+                       case 0x1c:
+                       /* Atmel AT45DB041 4Mbit Serial Flash */
+                       wnr3500l_sflash.blocksize = 256;
+                       wnr3500l_sflash.numblocks = 2048;
+                       break;
+                       case 0x24:
+                       /* Atmel AT45DB081 8Mbit Serial Flash */
+                       wnr3500l_sflash.blocksize = 256;
+                       wnr3500l_sflash.numblocks = 4096;
+                       break;
+                       case 0x2c:
+                       /* Atmel AT45DB161 16Mbit Serial Flash */
+                       wnr3500l_sflash.blocksize = 512;
+                       wnr3500l_sflash.numblocks = 4096;
+                       break;
+                       case 0x34:
+                       /* Atmel AT45DB321 32Mbit Serial Flash */
+                       wnr3500l_sflash.blocksize = 512;
+                       wnr3500l_sflash.numblocks = 8192;
+                       break;
+                       case 0x3c:
+                       /* Atmel AT45DB642 64Mbit Serial Flash */
+                       wnr3500l_sflash.blocksize = 1024;
+                       wnr3500l_sflash.numblocks = 8192;
+                       break;
+               }
+               break;
+       }
+
+       wnr3500l_sflash.size = wnr3500l_sflash.blocksize * 
wnr3500l_sflash.numblocks;
+       return wnr3500l_sflash.size;
+}
+       
+int __init sflash_mtd_init(void)
+{
+       int ret = 0;
+       u32 i;
+#ifdef CONFIG_MTD_PARTITIONS
+       struct mtd_partition *parts;
+#endif
+
+       memset(&sflash, 0, sizeof(struct sflash_mtd));
+       init_MUTEX(&sflash.lock);
+
+       sflash.base_regs = ioremap(SSB_ENUM_BASE, SSB_CORE_SIZE);
+       if (sflash.base_regs == NULL) {
+               printk(KERN_ERR "sflash: error mapping registers\n");
+               ret = -EIO;
+               goto fail;
+       }
+
+       /* Initialize serial flash access */
+       if (0 == sflash_init()) {
+               printk(KERN_ERR "sflash: found no supported devices\n");
+               ret = -ENODEV;
+               goto fail;
+       }
+
+       /* Setup region info */
+       sflash.region.offset = 0;
+       sflash.region.erasesize = wnr3500l_sflash.blocksize;
+       sflash.region.numblocks = wnr3500l_sflash.numblocks;
+       if (sflash.region.erasesize > sflash.mtd.erasesize)
+               sflash.mtd.erasesize = sflash.region.erasesize;
+       sflash.mtd.size = wnr3500l_sflash.size;
+       sflash.mtd.numeraseregions = 1;
+
+       /* Register with MTD */
+       sflash.mtd.name = "sflash";
+       sflash.mtd.type = MTD_NORFLASH;
+       sflash.mtd.flags = MTD_CAP_NORFLASH;
+       sflash.mtd.eraseregions = &sflash.region;
+       sflash.mtd.erase = sflash_mtd_erase;
+       sflash.mtd.read = sflash_mtd_read;
+       sflash.mtd.write = sflash_mtd_write;
+       sflash.mtd.writesize = 1;
+       sflash.mtd.priv = &sflash;
+   sflash.mtd.owner = THIS_MODULE;
+
+#ifdef CONFIG_MTD_PARTITIONS
+       parts = init_mtd_partitions(&sflash.mtd, sflash.mtd.size);
+       for (i = 0; parts[i].name; i++);
+       ret = add_mtd_partitions(&sflash.mtd, parts, i);
+#else
+       ret = add_mtd_device(&sflash.mtd);
+#endif
+       if (ret) {
+               printk(KERN_ERR "sflash: add_mtd failed\n");
+               goto fail;
+       }
+
+       return 0;
+
+ fail:
+       if (sflash.base_regs)
+               iounmap((void *) sflash.base_regs);
+       return ret;
+}
+
+void __exit sflash_mtd_exit(void)
+{
+#ifdef CONFIG_MTD_PARTITIONS
+       del_mtd_partitions(&sflash.mtd);
+#else
+       del_mtd_device(&sflash.mtd);
+#endif
+       iounmap((void *) sflash.base_regs);
+}
+
+module_init(sflash_mtd_init);
+module_exit(sflash_mtd_exit);
diff -Naur a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c
--- a/drivers/ssb/driver_chipcommon.c   2010-05-13 18:23:29.000000000 +0530
+++ b/drivers/ssb/driver_chipcommon.c   2010-05-13 18:21:04.000000000 +0530
@@ -258,8 +258,10 @@
 void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc,
                              u32 *plltype, u32 *n, u32 *m)
 {
+#ifndef CONFIG_WNR3500L
        if ((chipco_read32(cc, SSB_CHIPCO_CHIPID) & SSB_CHIPCO_IDMASK) == 
0x5354)
                return;
+#endif
        *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N);
        *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
        switch (*plltype) {
@@ -283,8 +285,10 @@
 void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc,
                                 u32 *plltype, u32 *n, u32 *m)
 {
+#ifndef CONFIG_WNR3500L
        if ((chipco_read32(cc, SSB_CHIPCO_CHIPID) & SSB_CHIPCO_IDMASK) == 
0x5354)
                return;
+#endif
        *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N);
        *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
        switch (*plltype) {
@@ -407,6 +411,7 @@
                                                chipco_read32(cc, 
SSB_CHIPCO_CLOCK_M2));
                div = 1;
        } else {
+#ifndef CONFIG_WNR3500L
                if (ccrev == 20) {
                        /* BCM5354 uses constant 25MHz clock */
                        baud_base = 25000000;
@@ -439,7 +444,18 @@
                                               chipco_read32(cc, 
SSB_CHIPCO_CORECTL)
                                               | SSB_CHIPCO_CORECTL_UARTCLKEN);
                        }
-               } else if (ccrev >= 3) {
+               }
+#else
+               if ((ccrev >= 11) && (ccrev != 15)) {
+                       baud_base = 20000000;
+                       div = 1;
+                       if (ccrev >= 21) {
+                               /* Re-enable the UART clock. */
+                               chipco_write32(cc, SSB_CHIPCO_CORECTL, 
chipco_read32(cc, SSB_CHIPCO_CORECTL) | SSB_CHIPCO_CORECTL_UARTCLKEN);
+         }
+               }
+#endif 
+               else if (ccrev >= 3) {
                        /* Internal backplane clock */
                        baud_base = ssb_clockspeed(bus);
                        div = chipco_read32(cc, SSB_CHIPCO_CLKDIV)
diff -Naur a/drivers/ssb/driver_chipcommon_pmu.c 
b/drivers/ssb/driver_chipcommon_pmu.c
--- a/drivers/ssb/driver_chipcommon_pmu.c       2010-05-13 18:23:29.000000000 
+0530
+++ b/drivers/ssb/driver_chipcommon_pmu.c       2010-05-13 18:21:04.000000000 
+0530
@@ -508,7 +508,7 @@
 
        ssb_dprintk(KERN_DEBUG PFX "Found rev %u PMU (capabilities 0x%08X)\n",
                    cc->pmu.rev, pmucap);
-
+#ifndef CONFIG_WNR3500L
        if (cc->pmu.rev >= 1) {
                if ((bus->chip_id == 0x4325) && (bus->chip_rev < 2)) {
                        chipco_mask32(cc, SSB_CHIPCO_PMU_CTL,
@@ -518,6 +518,13 @@
                                     SSB_CHIPCO_PMU_CTL_NOILPONW);
                }
        }
+#else
+       if (cc->pmu.rev == 1) {
+                       chipco_mask32(cc, SSB_CHIPCO_PMU_CTL, 
~SSB_CHIPCO_PMU_CTL_NOILPONW);
+       } else {
+                       chipco_set32(cc, SSB_CHIPCO_PMU_CTL, 
SSB_CHIPCO_PMU_CTL_NOILPONW);
+       }
+#endif
        ssb_pmu_pll_init(cc);
        ssb_pmu_resources_init(cc);
 }
diff -Naur a/drivers/ssb/driver_mipscore.c b/drivers/ssb/driver_mipscore.c
--- a/drivers/ssb/driver_mipscore.c     2010-05-13 18:23:29.000000000 +0530
+++ b/drivers/ssb/driver_mipscore.c     2010-05-14 12:02:40.000000000 +0530
@@ -49,12 +49,20 @@
 
 static inline u32 ssb_irqflag(struct ssb_device *dev)
 {
+#ifdef CONFIG_WNR3500L
+       if (dev->bus->is_ai_bus) { 
+               return (ssb_ai_read32(dev, SSB_AI_oobselouta30) & 0x1f); 
+       } else { 
+#endif
        u32 tpsflag = ssb_read32(dev, SSB_TPSFLAG);
        if (tpsflag)
                return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG;
        else
                /* not irq supported */
                return 0x3f;
+#ifdef CONFIG_WNR3500L
+       }
+#endif
 }
 
 static struct ssb_device *find_device(struct ssb_device *rdev, int irqflag)
@@ -85,6 +93,16 @@
        unsigned int irq;
 
        irqflag = ssb_irqflag(dev);
+#ifdef CONFIG_WNR3500L
+       if (mdev->id.coreid == SSB_DEV_MIPS_74K) { 
+               for (irq = 1; irq <= 4; irq++) { 
+                       if (ssb_read32(mdev, SSB_MIPS74K_INT_CONTROL(irq)) & (1 
<< irqflag)) 
+                               break; 
+                       } 
+                       if (irq == 5) 
+                               irq = 0; 
+       } else {
+#endif
        if (irqflag == 0x3f)
                return 6;
        ipsflag = ssb_read32(bus->mipscore.dev, SSB_IPSFLAG);
@@ -97,15 +115,32 @@
                if ((1 << irqflag) & ssb_read32(mdev, SSB_INTVEC))
                        irq = 0;
        }
+#ifdef CONFIG_WNR3500L
+       }
+#endif
 
        return irq;
 }
 
+#ifndef CONFIG_WNR3500L
 static void clear_irq(struct ssb_bus *bus, unsigned int irq)
+#else
+static void clear_irq(struct ssb_bus *bus, unsigned int irq, u32 irqflag)
+#endif
 {
        struct ssb_device *dev = bus->mipscore.dev;
 
        /* Clear the IRQ in the MIPScore backplane registers */
+#ifdef CONFIG_WNR3500L
+       if (dev->id.coreid == SSB_DEV_MIPS_74K) { 
+               if (irq == 5)
+                       return;
+               if (irq == 0) 
+                       ssb_write32(dev, SSB_MIPS74K_INT_CONTROL(0), 
ssb_read32(dev, SSB_MIPS74K_INT_CONTROL(0)) & ~(1 << irqflag)); 
+               else 
+                       ssb_write32(dev, SSB_MIPS74K_INT_CONTROL(irq), 0); 
+       } else {
+#endif
        if (irq == 0) {
                ssb_write32(dev, SSB_INTVEC, 0);
        } else {
@@ -113,6 +148,9 @@
                            ssb_read32(dev, SSB_IPSFLAG) |
                            ipsflag_irq_mask[irq]);
        }
+#ifdef CONFIG_WNR3500L
+       }
+#endif
 }
 
 static void set_irq(struct ssb_device *dev, unsigned int irq)
@@ -126,11 +164,38 @@
 
        dev->irq = irq + 2;
 
+#ifndef CONFIG_WNR3500L
        /* clear the old irq */
        if (oldirq == 0)
                ssb_write32(mdev, SSB_INTVEC, (~(1 << irqflag) & 
ssb_read32(mdev, SSB_INTVEC)));
        else if (oldirq != 5)
                clear_irq(bus, oldirq);
+#else
+       if (irq == oldirq) 
+               return; 
+
+       clear_irq(bus, irq, irqflag); 
+
+       /* make sure, the new irq is unused */ 
+       if (irq != 0) { 
+               int i; 
+               for (i = 0; i < bus->nr_devices; i++) { 
+                       struct ssb_device *olddev = &(bus->devices[i]); 
+                       if (ssb_mips_irq(olddev) == irq) {
+                               set_irq(olddev, 0); 
+                               break; 
+                       } 
+               } 
+       } 
+
+       /* set new irq */ 
+       if (mdev->id.coreid == SSB_DEV_MIPS_74K) { 
+               if (irq == 0) 
+                       ssb_write32(mdev, SSB_MIPS74K_INT_CONTROL(0), 
ssb_read32(mdev,SSB_MIPS74K_INT_CONTROL(0)) | 1 << irqflag); 
+               else 
+                       ssb_write32(mdev, SSB_MIPS74K_INT_CONTROL(irq), 1 << 
irqflag); 
+       } else {
+#endif
 
        /* assign the new one */
        if (irq == 0) {
@@ -147,6 +212,9 @@
                irqflag |= (ipsflag & ~ipsflag_irq_mask[irq]);
                ssb_write32(mdev, SSB_IPSFLAG, irqflag);
        }
+#ifdef CONFIG_WNR3500L
+       }
+#endif
        ssb_dprintk(KERN_INFO PFX
                    "set_irq: core 0x%04x, irq %d => %d\n",
                    dev->id.coreid, oldirq+2, irq+2);
@@ -208,6 +276,19 @@
        struct ssb_bus *bus = mcore->dev->bus;
        u32 pll_type, n, m, rate = 0;
 
+#ifdef CONFIG_WNR3500L
+       switch (bus->chip_id) {
+               case 0x5365:
+                       return 200000000;
+               case 0x5354:
+                       return 240000000;
+               case 0x4716:
+                       rate = ai_pmu_clock_rate(SSB_ENUM_BASE, 
SSB_PMU4716_MAINPLL_PLL0, SSB_PMU5_MAINPLL_SI);
+                       printk("rate: %d\n", rate);
+                       return rate;
+       }
+#endif
+
        if (bus->extif.dev) {
                ssb_extif_get_clockcontrol(&bus->extif, &pll_type, &n, &m);
        } else if (bus->chipco.dev) {
@@ -254,7 +335,17 @@
                ssb_chipco_timing_init(&bus->chipco, ns);
 
        /* Assign IRQs to all cores on the bus, start with irq line 2, because 
serial usually takes 1 */
-       for (irq = 2, i = 0; i < bus->nr_devices; i++) {
+#ifndef CONFIG_WNR3500L
+       for (irq = 2, i = 0; i < bus->nr_devices; i++) 
+#else
+       if (bus->chip_id == 0x4716) 
+               irq = 1; 
+       else 
+               irq = 2;
+           
+       for (i = 0; i < bus->nr_devices; i++) 
+#endif
+       {
                int mips_irq;
                dev = &(bus->devices[i]);
                mips_irq = ssb_mips_irq(dev);
@@ -277,6 +368,9 @@
                case SSB_DEV_ETHERNET_GBIT:
                case SSB_DEV_80211:
                case SSB_DEV_USB20_HOST:
+#ifdef CONFIG_WNR3500L
+               case SSB_DEV_ETHERNET_GBIT2:
+#endif
                        /* These devices get their own IRQ line if available, 
the rest goes on IRQ0 */
                        if (irq <= 4) {
                                set_irq(dev, irq++);
diff -Naur a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c
--- a/drivers/ssb/driver_pcicore.c      2010-05-13 18:23:29.000000000 +0530
+++ b/drivers/ssb/driver_pcicore.c      2010-05-13 18:21:04.000000000 +0530
@@ -412,6 +412,10 @@
 {
        /* Disable PCI interrupts. */
        ssb_write32(pc->dev, SSB_INTVEC, 0);
+
+#ifdef CONFIG_WNR3500L
+       ssb_device_disable(pc->dev, 0);
+#endif
 }
 
 void ssb_pcicore_init(struct ssb_pcicore *pc)
@@ -427,6 +431,12 @@
 
 #ifdef CONFIG_SSB_PCICORE_HOSTMODE
        pc->hostmode = pcicore_is_in_hostmode(pc);
+#ifdef CONFIG_WNR3500L
+       if (pc->hostmode && pc->dev->id.coreid == SSB_DEV_PCIE) { 
+               printk(KERN_WARNING "Disabling SSB PCI-E host due to code 
brokeness\n"); 
+               pc->hostmode = 0; 
+       } 
+#endif
        if (pc->hostmode)
                ssb_pcicore_init_hostmode(pc);
 #endif /* CONFIG_SSB_PCICORE_HOSTMODE */
diff -Naur a/drivers/ssb/main.c b/drivers/ssb/main.c
--- a/drivers/ssb/main.c        2010-05-13 18:23:29.000000000 +0530
+++ b/drivers/ssb/main.c        2010-05-13 18:21:04.000000000 +0530
@@ -570,7 +570,10 @@
                err = ssb_bus_powerup(bus, 0);
                if (err)
                        goto error;
+               printk("[%s:%s:%d] TODO: Need to initialize pci core\n", 
__FILE__, __func__, __LINE__);
+#ifndef CONFIG_WNR3500L
                ssb_pcicore_init(&bus->pcicore);
+#endif
                ssb_bus_may_powerdown(bus);
 
                err = ssb_devices_register(bus);
@@ -746,6 +749,24 @@
 #endif
 };
 
+#ifdef CONFIG_WNR3500L
+void ssb_ai_write32(struct ssb_device *dev, u16 offset, u32 value) 
+{ 
+       struct ssb_bus *bus = dev->bus; 
+
+       offset += dev->core_index * SSB_CORE_SIZE; 
+       return writel(value, bus->ai_mmio + offset); 
+} 
+
+u32 ssb_ai_read32(struct ssb_device *dev, u16 offset) 
+{ 
+       struct ssb_bus *bus = dev->bus; 
+
+       offset += dev->core_index * SSB_CORE_SIZE; 
+       return readl(bus->ai_mmio + offset); 
+} 
+#endif
+
 static int ssb_fetch_invariants(struct ssb_bus *bus,
                                ssb_invariants_func_t get_invariants)
 {
@@ -1077,6 +1098,42 @@
        return 0;
 }
 
+#ifdef CONFIG_WNR3500L
+u32 ai_pmu_clock_rate(u32 baseaddr, u32 pll0, u32 m)
+{
+       u32 tmp, div, ndiv, p1, p2, fc, *tmp_mmio, rate;
+       u32 pllcontrol_addr = 0x660/sizeof(u32), pllcontrol_data = 
0x664/sizeof(u32);
+
+       tmp_mmio = ioremap(baseaddr, SSB_CORE_SIZE);
+       writel(pll0 + SSB_PMU5_PLL_P1P2_OFF, tmp_mmio + pllcontrol_addr);
+       (void)readl(tmp_mmio + pllcontrol_addr);
+       tmp = readl(tmp_mmio + pllcontrol_data);
+       p1 = (tmp & SSB_PMU5_PLL_P1_MASK) >> SSB_PMU5_PLL_P1_SHIFT;
+       p2 = (tmp & SSB_PMU5_PLL_P2_MASK) >> SSB_PMU5_PLL_P2_SHIFT;
+
+       writel(pll0 + SSB_PMU5_PLL_M14_OFF, tmp_mmio + pllcontrol_addr);
+       (void)readl(tmp_mmio + pllcontrol_addr);
+       tmp = readl(tmp_mmio + pllcontrol_data);
+       div = (tmp >> ((m - 1) * SSB_PMU5_PLL_MDIV_WIDTH)) & 
SSB_PMU5_PLL_MDIV_MASK;
+
+       writel(pll0 + SSB_PMU5_PLL_NM5_OFF, tmp_mmio + pllcontrol_addr);
+       (void)readl(tmp_mmio + pllcontrol_addr);
+       tmp = readl(tmp_mmio + pllcontrol_data);
+       ndiv = (tmp & SSB_PMU5_PLL_NDIV_MASK) >> SSB_PMU5_PLL_NDIV_SHIFT;
+
+       iounmap(tmp_mmio);
+
+       /* Do calculation in Mhz */
+       fc = (20000 * 1000) / 1000000;
+       fc = (p1 * ndiv * fc) / p2;
+
+       /* Return clock in Hertz */
+       rate = (fc / div) * 1000000;
+
+       return rate;
+}
+#endif
+
 /* Get the current speed the backplane is running at */
 u32 ssb_clockspeed(struct ssb_bus *bus)
 {
@@ -1084,6 +1141,19 @@
        u32 plltype;
        u32 clkctl_n, clkctl_m;
 
+#ifdef CONFIG_WNR3500L
+       switch (bus->chip_id) { 
+               case 0x5365: 
+                       return 100000000; 
+               case 0x5354: 
+                       return 120000000; 
+               case 0x4716: 
+                       rate = ai_pmu_clock_rate(SSB_ENUM_BASE, 
SSB_PMU4716_MAINPLL_PLL0, SSB_PMU5_MAINPLL_SI);
+                       printk("rate: %d\n", rate);
+                       return rate;
+} 
+#endif
+
        if (ssb_extif_available(&bus->extif))
                ssb_extif_get_clockcontrol(&bus->extif, &plltype,
                                           &clkctl_n, &clkctl_m);
@@ -1132,6 +1202,11 @@
 
 int ssb_device_is_enabled(struct ssb_device *dev)
 {
+#ifdef CONFIG_WNR3500L
+       if (dev->bus->is_ai_bus) { 
+               return (ssb_ai_read32(dev, SSB_AI_RESETCTRL) & 
SSB_AI_RESETCTRL_RESET) == 0; 
+       } else {
+#endif
        u32 val;
        u32 reject;
 
@@ -1140,9 +1215,23 @@
        val &= SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET | reject;
 
        return (val == SSB_TMSLOW_CLOCK);
+#ifdef CONFIG_WNR3500L
+       }
+#endif
 }
 EXPORT_SYMBOL(ssb_device_is_enabled);
 
+#ifdef CONFIG_WNR3500L
+static void ssb_ai_ioctl_write(struct ssb_device *dev, u32 flags) 
+{ 
+       u32 dummy; 
+
+       ssb_ai_write32(dev, SSB_AI_IOCTRL, flags); 
+       dummy = ssb_ai_read32(dev, SSB_AI_IOCTRL); 
+       udelay(1); 
+} 
+#endif
+
 static void ssb_flush_tmslow(struct ssb_device *dev)
 {
        /* Make _really_ sure the device has finished the TMSLOW
@@ -1160,6 +1249,15 @@
        u32 val;
 
        ssb_device_disable(dev, core_specific_flags);
+#ifdef CONFIG_WNR3500L
+       if (dev->bus->is_ai_bus) { 
+               ssb_ai_ioctl_write(dev, core_specific_flags | SSB_CF_FGC | 
SSB_CF_CLOCK_EN); 
+               ssb_ai_write32(dev, SSB_AI_RESETCTRL, 0); 
+               udelay(1); 
+
+               ssb_ai_ioctl_write(dev, core_specific_flags | SSB_CF_CLOCK_EN); 
+       } else {
+#endif
        ssb_write32(dev, SSB_TMSLOW,
                    SSB_TMSLOW_RESET | SSB_TMSLOW_CLOCK |
                    SSB_TMSLOW_FGC | core_specific_flags);
@@ -1183,6 +1281,9 @@
        ssb_write32(dev, SSB_TMSLOW, SSB_TMSLOW_CLOCK |
                    core_specific_flags);
        ssb_flush_tmslow(dev);
+#ifdef CONFIG_WNR3500L
+       }
+#endif
 }
 EXPORT_SYMBOL(ssb_device_enable);
 
diff -Naur a/drivers/ssb/scan.c b/drivers/ssb/scan.c
--- a/drivers/ssb/scan.c        2010-05-13 18:23:29.000000000 +0530
+++ b/drivers/ssb/scan.c        2010-05-13 18:21:04.000000000 +0530
@@ -216,6 +216,10 @@
        case SSB_BUSTYPE_SSB:
        case SSB_BUSTYPE_PCMCIA:
                iounmap(bus->mmio);
+#ifdef CONFIG_WNR3500L
+               if (bus->ai_mmio) 
+                       iounmap(bus->ai_mmio); 
+#endif
                break;
        case SSB_BUSTYPE_PCI:
 #ifdef CONFIG_SSB_PCIHOST
@@ -276,15 +280,75 @@
        return 0;
 }
 
+#ifdef CONFIG_WNR3500L
+static u32 
+get_erom_ent(struct ssb_bus *bus, u32 **eromptr, u32 mask, u32 match) 
+{ 
+       u32 ent; 
+
+       while (1) { 
+               ent = readl(*eromptr); 
+               (*eromptr)++; 
+
+               if (mask == 0) 
+                       break; 
+
+               if ((ent & SSB_EROM_VALID) == 0) 
+                       continue; 
+
+               if (ent == (SSB_EROM_END | SSB_EROM_VALID)) 
+                       break; 
+
+               if ((ent & mask) == match) 
+                       break; 
+       } 
+       return ent; 
+}
+ 
+static u32 
+get_adress_space_descriptor(struct ssb_bus *bus, u32 **eromptr, uint st, u32 
*addrl, u32 *sizel) 
+{ 
+       u32 asd, sz, szd, expect; 
+
+       expect = SSB_EROM_ASD | st; 
+       if (st == SSB_EROM_ASD_ST_SWRAP) 
+               expect |= 1 << SSB_EROM_ASD_SP_SHIFT; 
+
+       asd = get_erom_ent(bus, eromptr, SSB_EROM_ASD_SP_MASK | SSB_EROM_TAG | 
SSB_EROM_ASD_ST_MASK, expect); 
+
+       *addrl = asd & SSB_EROM_ASD_ADDR_MASK; 
+
+       BUG_ON(asd & SSB_EROM_ASD_AG32); 
+
+       sz = asd & SSB_EROM_ASD_SZ_MASK; 
+       if (sz == SSB_EROM_ASD_SZ_SZD) { 
+               szd = get_erom_ent(bus, eromptr, 0, 0); 
+               *sizel = szd & SSB_EROM_ASD_SZ_MASK; 
+       } else 
+               *sizel = SSB_EROM_ASD_SZ_BASE << (sz >> SSB_EROM_ASD_SZ_SHIFT); 
+
+       return asd; 
+} 
+#endif
+
 int ssb_bus_scan(struct ssb_bus *bus,
                 unsigned long baseaddr)
 {
        int err = -ENOMEM;
        void __iomem *mmio;
+#ifndef CONFIG_WNR3500L
        u32 idhi, cc, rev, tmp;
+#else
+       u32 idhi, tmp;
+#endif
        int dev_i, i;
        struct ssb_device *dev;
        int nr_80211_cores = 0;
+#ifdef CONFIG_WNR3500L
+       bool have_chipcommon = true; 
+       u32 __iomem *eromptr = NULL; 
+       u32 __iomem *eromend = (void *) -1; 
+#endif
 
        mmio = ssb_ioremap(bus, baseaddr);
        if (!mmio)
@@ -295,13 +359,29 @@
        if (err)
                goto err_unmap;
 
+#ifndef CONFIG_WNR3500L
        idhi = scan_read32(bus, 0, SSB_IDHIGH);
        cc = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT;
        rev = (idhi & SSB_IDHIGH_RCLO);
        rev |= (idhi & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT;
+#else
+       if (bus->bustype != SSB_BUSTYPE_SSB) { 
+               idhi = scan_read32(bus, 0, SSB_IDHIGH); 
+               if (((idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT) != 
SSB_DEV_CHIPCOMMON) 
+                       have_chipcommon = false; 
+       }
+#endif
 
        bus->nr_devices = 0;
-       if (cc == SSB_DEV_CHIPCOMMON) {
+#ifndef CONFIG_WNR3500L
+       if (cc == SSB_DEV_CHIPCOMMON)
+#else
+       /* this may break, if the first core isn't a chipcommon core, 
+       * but we need to know, if this is an ai bus or not. It should 
+       * only fail for older SDIOs (?) */ 
+       if (have_chipcommon)
+#endif
+       {
                tmp = scan_read32(bus, 0, SSB_CHIPCO_CHIPID);
 
                bus->chip_id = (tmp & SSB_CHIPCO_IDMASK);
@@ -309,7 +389,13 @@
                                SSB_CHIPCO_REVSHIFT;
                bus->chip_package = (tmp & SSB_CHIPCO_PACKMASK) >>
                                    SSB_CHIPCO_PACKSHIFT;
-               if (rev >= 4) {
+#ifndef CONFIG_WNR3500L
+               if (rev >= 4)
+#else
+               bus->is_ai_bus = !!(tmp & SSB_CHIPCO_TYPE_MASK); 
+               if (bus->chip_rev >= 4)
+#endif
+               {
                        bus->nr_devices = (tmp & SSB_CHIPCO_NRCORESMASK) >>
                                          SSB_CHIPCO_NRCORESSHIFT;
                }
@@ -339,7 +425,9 @@
                /* Now that we know the number of cores,
                 * remap the whole IO space for all cores.
                 */
+#ifndef CONFIG_WNR3500L
                err = -ENOMEM;
+#endif
                iounmap(mmio);
                mmio = ioremap(baseaddr, SSB_CORE_SIZE * bus->nr_devices);
                if (!mmio)
@@ -347,27 +435,119 @@
                bus->mmio = mmio;
        }
 
+#ifdef CONFIG_WNR3500L
+       if (bus->is_ai_bus) { 
+               mmio = ioremap(SSB_AI_BASE, SSB_CORE_SIZE * bus->nr_devices); 
+               if (!mmio) 
+                       goto err_unmap; 
+               bus->ai_mmio = mmio; 
+ 
+               eromptr = ioremap(scan_read32(bus, 0, SSB_CHIPCO_EROM), 
SSB_CORE_SIZE); 
+               if (!eromptr) 
+                       goto err_unmap; 
+ 
+               eromend = eromptr + SSB_CORE_SIZE / sizeof(u32); 
+       } 
+
+       err = -EIO; 
+#endif
+
        /* Fetch basic information about each core/device */
-       for (i = 0, dev_i = 0; i < bus->nr_devices; i++) {
+#ifndef CONFIG_WNR3500L
+       for (i = 0, dev_i = 0; i < bus->nr_devices; i++)
+#else
+       i = 0; 
+       dev_i = 0; 
+       while ((i < bus->nr_devices) && (eromptr < eromend))
+#endif
+       {
                err = scan_switchcore(bus, i);
                if (err)
                        goto err_unmap;
                dev = &(bus->devices[dev_i]);
 
+#ifdef CONFIG_WNR3500L
+               if (bus->is_ai_bus) { 
+                       u32 cia, cib, asd, sizel, addrl, nmw; 
+
+                       cia = get_erom_ent(bus, &eromptr, SSB_EROM_TAG, 
SSB_EROM_CI); 
+                       if (cia == (SSB_EROM_END | SSB_EROM_VALID)) { 
+                               ssb_dprintk(KERN_INFO PFX "Found END of erom 
after %d cores\n", dev_i); 
+                               if (dev_i != bus->nr_devices) { 
+                                       ssb_printk(KERN_WARNING PFX "Expected 
%d cores but got %d\n", bus->nr_devices, dev_i); 
+                               } 
+                               break; 
+                       }
+                       cib = get_erom_ent(bus, &eromptr, 0, 0); 
+                       if ((cib & SSB_EROM_TAG) != SSB_EROM_CI) { 
+                               ssb_printk(KERN_ERR PFX "CIA not followed by 
CIB\n"); 
+                               goto error;
+                       } 
+
+                       dev->id.coreid = (cia & SSB_EROM_CIA_CID_MASK) >> 
SSB_EROM_CIA_CID_SHIFT; 
+                       dev->id.vendor = (cia & SSB_EROM_CIA_MFG_MASK) >> 
SSB_EROM_CIA_MFG_SHIFT; 
+                       dev->id.revision = (cib & SSB_EROM_CIB_REV_MASK) >> 
SSB_EROM_CIB_REV_SHIFT; 
+                       dev->core_index = dev_i; 
+
+                       nmw = cib & SSB_EROM_CIB_NMW_MASK; 
+                       if (((dev->id.coreid == SSB_DEV_DEFAULT) && 
(dev->id.vendor == SSB_VENDOR_ARM)) || 
+                                       (nmw == 0 && (cib & 
SSB_EROM_CIB_NSW_MASK) == 0) || ((cib & SSB_EROM_CIB_NSP_MASK) == 0)) { 
+                               continue; 
+                       } 
+
+                       /* see if it is a bridge */ 
+                       if ((SSB_EROM_ASD_ST_MASK & get_erom_ent(bus, &eromptr, 
SSB_EROM_TAG, SSB_EROM_ASD)) == SSB_EROM_ASD_ST_BRIDGE) 
+                               continue;/* don't record bridges */ 
+                       else
+                               eromptr--; 
+                       /* First Slave Address Descriptor should be port 0: 
+                       * the main register space for the core 
+                       */ 
+                       asd = get_adress_space_descriptor(bus, &eromptr, 
SSB_EROM_ASD_ST_SLAVE, &addrl, &sizel); 
+                       if (sizel != SSB_CORE_SIZE || addrl != SSB_ENUM_BASE + 
SSB_CORE_SIZE * dev_i) { 
+                               ssb_printk(KERN_ERR PFX "Malformed or 
unsupported register address space descriptor for core %d:\n" 
+                                       "\texpected 0x%x, got 0x%x, size 
0x%x\n", dev_i, SSB_ENUM_BASE + SSB_CORE_SIZE * dev_i, addrl, sizel); 
+                               goto error; 
+                       }
+                       dev->dev_baseaddr = addrl;
+                       dev->dev_baseaddr_size = sizel;
+
+                       if (nmw) 
+                               asd = get_adress_space_descriptor(bus, 
&eromptr, SSB_EROM_ASD_ST_MWRAP, &addrl, &sizel); 
+                       else 
+                               asd = get_adress_space_descriptor(bus, 
&eromptr, SSB_EROM_ASD_ST_SWRAP, &addrl, &sizel); 
+
+                       if (sizel != SSB_CORE_SIZE || addrl != SSB_AI_BASE + 
SSB_CORE_SIZE * dev_i) { 
+                               ssb_printk(KERN_ERR PFX "Malformed or 
unsupported ai address space descriptor for core %d:\n" 
+                                       "\texpected 0x%x, got 0x%x, size 
0x%x\n", dev_i, SSB_AI_BASE + SSB_CORE_SIZE * dev_i, addrl, sizel); 
+                               goto error; 
+                       } 
+               } else { 
+#endif
                idhi = scan_read32(bus, i, SSB_IDHIGH);
                dev->id.coreid = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT;
                dev->id.revision = (idhi & SSB_IDHIGH_RCLO);
                dev->id.revision |= (idhi & SSB_IDHIGH_RCHI) >> 
SSB_IDHIGH_RCHI_SHIFT;
                dev->id.vendor = (idhi & SSB_IDHIGH_VC) >> SSB_IDHIGH_VC_SHIFT;
                dev->core_index = i;
+               i++;
+#ifdef CONFIG_WNR3500L
+               }
+
                dev->bus = bus;
                dev->ops = bus->ops;
-
+               ssb_printk(KERN_INFO PFX
+                               "Core %d found: %s "
+                               "(cc 0x%03X, rev 0x%02X, vendor 0x%04X)\n",
+                               dev->core_index, ssb_core_name(dev->id.coreid),
+                               dev->id.coreid, dev->id.revision, 
dev->id.vendor);
+#else
                ssb_dprintk(KERN_INFO PFX
                            "Core %d found: %s "
                            "(cc 0x%03X, rev 0x%02X, vendor 0x%04X)\n",
                            i, ssb_core_name(dev->id.coreid),
                            dev->id.coreid, dev->id.revision, dev->id.vendor);
+#endif
 
                switch (dev->id.coreid) {
                case SSB_DEV_80211:
@@ -400,6 +580,9 @@
                        break;
                case SSB_DEV_MIPS:
                case SSB_DEV_MIPS_3302:
+#ifdef CONFIG_WNR3500L
+               case SSB_DEV_MIPS_74K:
+#endif
 #ifdef CONFIG_SSB_DRIVER_MIPS
                        if (bus->mipscore.dev) {
                                ssb_printk(KERN_WARNING PFX
@@ -439,10 +622,23 @@
        }
        bus->nr_devices = dev_i;
 
+#ifdef CONFIG_WNR3500L
+       if (bus->is_ai_bus && eromptr >= eromend) 
+               ssb_printk(KERN_ERR PFX "Reached end of erom without finding 
END");
+#endif
+
        err = 0;
 out:
        return err;
+#ifdef CONFIG_WNR3500L
+error: 
+       bus->nr_devices = 0;
+#endif
 err_unmap:
        ssb_iounmap(bus);
+#ifndef CONFIG_WNR3500L
        goto out;
+#else
+       return err;
+#endif
 }
diff -Naur a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h
--- a/drivers/ssb/ssb_private.h 2010-05-13 18:23:29.000000000 +0530
+++ b/drivers/ssb/ssb_private.h 2010-05-13 18:21:04.000000000 +0530
@@ -29,6 +29,14 @@
 # define SSB_BUG_ON(x)         __ssb_do_nothing(unlikely(!!(x)))
 #endif
 
+#ifdef CONFIG_WNR3500L
+u32 ai_pmu_clock_rate(u32 baseaddr, u32 pll0, u32 m);
+#define SSB_PMU5_MAINPLL_SBB    3 
+#define SSB_PMU5_MAINPLL_CPU    1 
+   
+void ssb_ai_write32(struct ssb_device *dev, u16 offset, u32 value); 
+u32 ssb_ai_read32(struct ssb_device *dev, u16 offset); 
+#endif
 
 /* pci.c */
 #ifdef CONFIG_SSB_PCIHOST
diff -Naur a/include/linux/ssb/ssb_driver_chipcommon.h 
b/include/linux/ssb/ssb_driver_chipcommon.h
--- a/include/linux/ssb/ssb_driver_chipcommon.h 2010-05-13 18:23:48.000000000 
+0530
+++ b/include/linux/ssb/ssb_driver_chipcommon.h 2010-05-13 18:21:36.000000000 
+0530
@@ -549,6 +549,34 @@
 #define        SSB_CHIPCO_OTP_SIGNATURE        0x578A
 #define        SSB_CHIPCO_OTP_MAGIC            0x4E56
 
+#ifdef CONFIG_WNR3500L
+#define SSB_CHIPCO_TYPE_MASK                   0xf0000000 
+#define SSB_CHIPCO_EROM                                        0xFC
+/* PMU rev 5 (& 6) */ 
+#define SSB_PMU5_PLL_P1P2_OFF                  0 
+#define SSB_PMU5_PLL_P1_MASK                   0x0f000000 
+#define SSB_PMU5_PLL_P1_SHIFT                  24 
+#define SSB_PMU5_PLL_P2_MASK                   0x00f00000 
+#define SSB_PMU5_PLL_P2_SHIFT                  20 
+#define SSB_PMU5_PLL_M14_OFF                   1 
+#define SSB_PMU5_PLL_MDIV_MASK         0x000000ff 
+#define SSB_PMU5_PLL_MDIV_WIDTH                8 
+#define SSB_PMU5_PLL_NM5_OFF                   2 
+#define SSB_PMU5_PLL_NDIV_MASK         0xfff00000 
+#define SSB_PMU5_PLL_NDIV_SHIFT                20 
+#define SSB_PMU5_PLL_FMAB_OFF                  3 
+#define SSB_PMU5_PLL_MRAT_MASK         0xf0000000 
+#define SSB_PMU5_PLL_MRAT_SHIFT                28 
+#define SSB_PMU5_PLL_ABRAT_MASK                0x08000000 
+#define SSB_PMU5_PLL_ABRAT_SHIFT               27 
+#define SSB_PMU5_PLL_FDIV_MASK         0x07ffffff 
+#define SSB_PMU5_PLL_PLLCTL_OFF                4 
+#define SSB_PMU5_PLL_PCHI_OFF                  5 
+#define SSB_PMU5_PLL_PCHI_MASK         0x0000003f 
+#define SSB_PMU4716_MAINPLL_PLL0               12
+#define SSB_PMU5_MAINPLL_SI                    3
+#endif
+
 
 struct ssb_device;
 struct ssb_serial_port;
diff -Naur a/include/linux/ssb/ssb_driver_mips.h 
b/include/linux/ssb/ssb_driver_mips.h
--- a/include/linux/ssb/ssb_driver_mips.h       2010-05-13 18:23:48.000000000 
+0530
+++ b/include/linux/ssb/ssb_driver_mips.h       2010-05-13 18:21:36.000000000 
+0530
@@ -30,6 +30,9 @@
 
 extern unsigned int ssb_mips_irq(struct ssb_device *dev);
 
+#ifdef CONFIG_WNR3500L
+#define SSB_MIPS74K_INT_CONTROL(int)    (0x14 + (int)*4)
+#endif
 
 #else /* CONFIG_SSB_DRIVER_MIPS */
 
diff -Naur a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
--- a/include/linux/ssb/ssb.h   2010-05-13 18:23:48.000000000 +0530
+++ b/include/linux/ssb/ssb.h   2010-05-13 18:21:36.000000000 +0530
@@ -185,6 +185,11 @@
        /* Internal-only stuff follows. */
        void *drvdata;          /* Per-device data */
        void *devtypedata;      /* Per-devicetype (eg 802.11) data */
+#ifdef CONFIG_WNR3500L
+       u32 dev_baseaddr;
+       u32 dev_baseaddr_size;
+       u32 wrapba;
+#endif
 };
 
 /* Go from struct device to struct ssb_device. */
@@ -273,6 +278,9 @@
 struct ssb_bus {
        /* The MMIO area. */
        void __iomem *mmio;
+#ifdef CONFIG_WNR3500L
+   void __iomem *ai_mmio;
+#endif
 
        const struct ssb_bus_ops *ops;
 
@@ -288,6 +296,10 @@
         * On PCMCIA-host busses this is used to protect the whole MMIO access. 
*/
        spinlock_t bar_lock;
 
+#ifdef CONFIG_WNR3500L
+       bool is_ai_bus;
+#endif
+
        /* The bus this backplane is running on. */
        enum ssb_bustype bustype;
        /* Pointer to the PCI bus (only valid if bustype == SSB_BUSTYPE_PCI). */
_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/mailman/listinfo/openwrt-devel

Reply via email to