FEATURES:=squashfs jffs2
DEFAULT_SUBTARGET:=danube
-LINUX_VERSION:=2.6.39.4
+LINUX_VERSION:=3.0.3
CFLAGS=-Os -pipe -mips32r2 -mtune=mips32r2 -fno-caller-saves
+++ /dev/null
-CONFIG_ADM6996_PHY=y
-CONFIG_AR8216_PHY=y
-# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set
-# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
-# CONFIG_ATH79 is not set
-CONFIG_GENERIC_ATOMIC64=y
-CONFIG_GENERIC_IRQ_SHOW=y
-CONFIG_HAVE_ARCH_JUMP_LABEL=y
-CONFIG_HAVE_C_RECORDMCOUNT=y
-CONFIG_HAVE_DMA_API_DEBUG=y
-CONFIG_HAVE_DMA_ATTRS=y
-CONFIG_HAVE_DYNAMIC_FTRACE=y
-CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
-CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
-CONFIG_HAVE_FUNCTION_TRACER=y
-CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
-CONFIG_HAVE_GENERIC_HARDIRQS=y
-CONFIG_HAVE_IRQ_WORK=y
-CONFIG_HAVE_PERF_EVENTS=y
-CONFIG_HW_HAS_PCI=y
-CONFIG_INPUT=y
-CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_GPIO_BUTTONS is not set
-CONFIG_INPUT_POLLDEV=y
-# CONFIG_ISDN is not set
-CONFIG_LANTIQ_ETOP=y
-# CONFIG_LANTIQ_MACH_ARV45XX is not set
-# CONFIG_LANTIQ_MACH_EASY50712 is not set
-CONFIG_LANTIQ_MACH_NETGEAR=y
-# CONFIG_LANTIQ_MACH_GIGASX76X is not set
-CONFIG_MACH_NO_WESTBRIDGE=y
-# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set
-CONFIG_NEED_DMA_MAP_STATE=y
-CONFIG_NEED_PER_CPU_KM=y
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-CONFIG_PERF_USE_VMALLOC=y
-# CONFIG_PREEMPT_RCU is not set
-# CONFIG_QUOTACTL is not set
-CONFIG_RTL8306_PHY=y
-# CONFIG_SOC_AMAZON_SE is not set
-# CONFIG_SOC_FALCON is not set
-CONFIG_SOC_TYPE_XWAY=y
-CONFIG_SOC_XWAY=y
-CONFIG_SPI=y
-CONFIG_SPI_BITBANG=y
-# CONFIG_SPI_GPIO is not set
-CONFIG_SPI_LANTIQ=y
-CONFIG_SPI_MASTER=y
-CONFIG_USB_SUPPORT=y
-CONFIG_XZ_DEC=y
# CONFIG_LANTIQ_MACH_ARV45XX is not set
# CONFIG_LANTIQ_MACH_EASY50712 is not set
CONFIG_LANTIQ_MACH_NETGEAR=y
-# CONFIG_LANTIQ_MACH_GIGASX76X is not set
CONFIG_LANTIQ_MACH_WBMR=y
+# CONFIG_LANTIQ_MACH_GIGASX76X is not set
CONFIG_MACH_NO_WESTBRIDGE=y
# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set
CONFIG_NEED_DMA_MAP_STATE=y
# CONFIG_QUOTACTL is not set
CONFIG_RTL8306_PHY=y
# CONFIG_SOC_AMAZON_SE is not set
+# CONFIG_SOC_VR9 is not set
# CONFIG_SOC_FALCON is not set
CONFIG_SOC_TYPE_XWAY=y
CONFIG_SOC_XWAY=y
CONFIG_SPI_MASTER=y
CONFIG_USB_SUPPORT=y
CONFIG_XZ_DEC=y
+CONFIG_SPI_XWAY=y
define Profile/WBMR
NAME:=WBMR - Buffalo WBMR-HP-G300H
PACKAGES:= kmod-usb-core kmod-usb-dwc-otg kmod-leds-gpio \
- kmod-ltq-dsl-firmware-b kmod-ledtrig-usbdev
+ kmod-ltq-dsl-firmware-b-ar9 kmod-ledtrig-usbdev
endef
define Profile/WBMR/Description
BOARDNAME:=AR9
FEATURES:=squashfs jffs2 atm
-DEFAULT_PACKAGES+=kmod-pppoa ppp-mod-pppoa linux-atm atm-tools br2684ctl kmod-ltq-dsl ltq-dsl-app swconfig
+DEFAULT_PACKAGES+=kmod-pppoa ppp-mod-pppoa linux-atm atm-tools br2684ctl kmod-ltq-dsl-ar9 ltq-dsl-app swconfig
define Target/Description
Lantiq XWAY (danube/twinpass/ar9)
+++ /dev/null
-# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set
-# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
-# CONFIG_ATH79 is not set
-CONFIG_GENERIC_ATOMIC64=y
-CONFIG_GENERIC_IRQ_SHOW=y
-CONFIG_HAVE_ARCH_JUMP_LABEL=y
-CONFIG_HAVE_C_RECORDMCOUNT=y
-CONFIG_HAVE_DMA_API_DEBUG=y
-CONFIG_HAVE_DMA_ATTRS=y
-CONFIG_HAVE_DYNAMIC_FTRACE=y
-CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
-CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
-CONFIG_HAVE_FUNCTION_TRACER=y
-CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
-CONFIG_HAVE_GENERIC_HARDIRQS=y
-CONFIG_HAVE_IRQ_WORK=y
-CONFIG_HAVE_PERF_EVENTS=y
-CONFIG_INPUT=y
-CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_GPIO_BUTTONS is not set
-CONFIG_INPUT_POLLDEV=y
-# CONFIG_ISDN is not set
-CONFIG_LANTIQ_ETOP=y
-CONFIG_LANTIQ_MACH_EASY50601=y
-CONFIG_MACH_NO_WESTBRIDGE=y
-# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set
-# CONFIG_MTD_LATCH_ADDR is not set
-CONFIG_NEED_DMA_MAP_STATE=y
-CONFIG_NEED_PER_CPU_KM=y
-CONFIG_PERF_USE_VMALLOC=y
-# CONFIG_PREEMPT_RCU is not set
-# CONFIG_QUOTACTL is not set
-CONFIG_SOC_AMAZON_SE=y
-# CONFIG_SOC_FALCON is not set
-CONFIG_SOC_TYPE_XWAY=y
-# CONFIG_SOC_XWAY is not set
-CONFIG_XZ_DEC=y
# CONFIG_PREEMPT_RCU is not set
# CONFIG_QUOTACTL is not set
CONFIG_SOC_AMAZON_SE=y
+# CONFIG_SOC_VR9 is not set
# CONFIG_SOC_FALCON is not set
CONFIG_SOC_TYPE_XWAY=y
# CONFIG_SOC_XWAY is not set
CONFIG_XZ_DEC=y
+CONFIG_SPI_XWAY=y
BOARDNAME:=Amazon-SE
FEATURES:=squashfs jffs2 atm
-DEFAULT_PACKAGES+=kmod-pppoa ppp-mod-pppoa linux-atm atm-tools br2684ctl kmod-ltq-dsl ltq-dsl-app
+DEFAULT_PACKAGES+=kmod-pppoa ppp-mod-pppoa linux-atm atm-tools br2684ctl kmod-ltq-dsl-ase ltq-dsl-app
define Target/Description
Lantiq ASE
+++ /dev/null
-# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set
-# CONFIG_ARCH_HAS_ILOG2_U32 is not set
-# CONFIG_ARCH_HAS_ILOG2_U64 is not set
-CONFIG_ARCH_HIBERNATION_POSSIBLE=y
-# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
-CONFIG_ARCH_POPULATES_NODE_MAP=y
-CONFIG_ARCH_REQUIRE_GPIOLIB=y
-# CONFIG_ARCH_SUPPORTS_MSI is not set
-CONFIG_ARCH_SUPPORTS_OPROFILE=y
-CONFIG_ARCH_SUSPEND_POSSIBLE=y
-# CONFIG_ATH79 is not set
-CONFIG_BCMA_POSSIBLE=y
-# CONFIG_BRCMUTIL is not set
-CONFIG_CEVT_R4K=y
-CONFIG_CEVT_R4K_LIB=y
-CONFIG_CPU_BIG_ENDIAN=y
-CONFIG_CPU_HAS_PREFETCH=y
-CONFIG_CPU_HAS_SYNC=y
-CONFIG_CPU_MIPS32=y
-# CONFIG_CPU_MIPS32_R1 is not set
-CONFIG_CPU_MIPS32_R2=y
-CONFIG_CPU_MIPSR2=y
-CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_HIGHMEM=y
-CONFIG_CSRC_R4K=y
-CONFIG_CSRC_R4K_LIB=y
-CONFIG_DECOMPRESS_LZMA=y
-CONFIG_DMA_NONCOHERENT=y
-CONFIG_EARLY_PRINTK=y
-# CONFIG_FSNOTIFY is not set
-CONFIG_GENERIC_ATOMIC64=y
-CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
-CONFIG_GENERIC_CMOS_UPDATE=y
-CONFIG_GENERIC_GPIO=y
-CONFIG_GENERIC_IRQ_SHOW=y
-CONFIG_GPIOLIB=y
-CONFIG_GPIO_SYSFS=y
-CONFIG_HARDWARE_WATCHPOINTS=y
-CONFIG_HAS_DMA=y
-CONFIG_HAS_IOMEM=y
-CONFIG_HAS_IOPORT=y
-CONFIG_HAVE_ARCH_JUMP_LABEL=y
-CONFIG_HAVE_ARCH_KGDB=y
-CONFIG_HAVE_CLK=y
-CONFIG_HAVE_C_RECORDMCOUNT=y
-CONFIG_HAVE_DMA_API_DEBUG=y
-CONFIG_HAVE_DMA_ATTRS=y
-CONFIG_HAVE_DYNAMIC_FTRACE=y
-CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
-CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
-CONFIG_HAVE_FUNCTION_TRACER=y
-CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
-CONFIG_HAVE_GENERIC_DMA_COHERENT=y
-CONFIG_HAVE_GENERIC_HARDIRQS=y
-CONFIG_HAVE_IDE=y
-CONFIG_HAVE_IRQ_WORK=y
-CONFIG_HAVE_OPROFILE=y
-CONFIG_HAVE_PERF_EVENTS=y
-CONFIG_HW_RANDOM=y
-CONFIG_HZ=250
-# CONFIG_HZ_100 is not set
-CONFIG_HZ_250=y
-CONFIG_IFX_UDP_REDIRECT=y
-CONFIG_IMAGE_CMDLINE_HACK=y
-CONFIG_INITRAMFS_SOURCE=""
-CONFIG_IRQ_CPU=y
-CONFIG_LANTIQ=y
-CONFIG_LANTIQ_MACH_95C3AM1=y
-CONFIG_LANTIQ_MACH_EASY98000=y
-CONFIG_LANTIQ_MACH_EASY98020=y
-CONFIG_LANTIQ_WDT=y
-CONFIG_LEDS_GPIO=y
-CONFIG_MACH_NO_WESTBRIDGE=y
-# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set
-CONFIG_MIPS=y
-CONFIG_MIPS_L1_CACHE_SHIFT=5
-CONFIG_MIPS_MACHINE=y
-CONFIG_MIPS_MT_DISABLED=y
-# CONFIG_MIPS_MT_SMP is not set
-# CONFIG_MIPS_MT_SMTC is not set
-# CONFIG_MIPS_VPE_LOADER is not set
-CONFIG_MTD_CFI_ADV_OPTIONS=y
-CONFIG_MTD_CFI_GEOMETRY=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_LANTIQ=y
-CONFIG_MTD_UIMAGE_SPLIT=y
-CONFIG_NEED_DMA_MAP_STATE=y
-CONFIG_NEED_PER_CPU_KM=y
-CONFIG_NLS=y
-CONFIG_PAGEFLAGS_EXTENDED=y
-CONFIG_PERF_USE_VMALLOC=y
-CONFIG_PHYLIB=y
-# CONFIG_PREEMPT_RCU is not set
-# CONFIG_QUOTACTL is not set
-# CONFIG_RTC_CLASS is not set
-CONFIG_RTL8366RB_PHY=y
-CONFIG_RTL8366_SMI=y
-# CONFIG_SCSI_DMA is not set
-# CONFIG_SERIAL_8250 is not set
-CONFIG_SERIAL_LANTIQ=y
-CONFIG_SWAP_IO_SPACE=y
-CONFIG_SWCONFIG=y
-CONFIG_SYS_HAS_CPU_MIPS32_R1=y
-CONFIG_SYS_HAS_CPU_MIPS32_R2=y
-CONFIG_SYS_HAS_EARLY_PRINTK=y
-CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
-CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
-CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
-CONFIG_SYS_SUPPORTS_MULTITHREADING=y
-CONFIG_XZ_DEC=y
-CONFIG_ZONE_DMA_FLAG=0
-# CONFIG_64BIT is not set
+# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
# CONFIG_ARCH_SUPPORTS_MSI is not set
CONFIG_ARCH_SUPPORTS_OPROFILE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_ATH79 is not set
+CONFIG_BCMA_POSSIBLE=y
+# CONFIG_BRCMUTIL is not set
CONFIG_CEVT_R4K=y
CONFIG_CEVT_R4K_LIB=y
-CONFIG_CFG80211_DEFAULT_PS_VALUE=0
CONFIG_CPU_BIG_ENDIAN=y
-# CONFIG_CPU_CAVIUM_OCTEON is not set
CONFIG_CPU_HAS_PREFETCH=y
CONFIG_CPU_HAS_SYNC=y
-# CONFIG_CPU_LITTLE_ENDIAN is not set
-# CONFIG_CPU_LOONGSON2E is not set
CONFIG_CPU_MIPS32=y
# CONFIG_CPU_MIPS32_R1 is not set
CONFIG_CPU_MIPS32_R2=y
-# CONFIG_CPU_MIPS64_R1 is not set
-# CONFIG_CPU_MIPS64_R2 is not set
CONFIG_CPU_MIPSR2=y
-# CONFIG_CPU_NEVADA is not set
-# CONFIG_CPU_R10000 is not set
-# CONFIG_CPU_R3000 is not set
-# CONFIG_CPU_R4300 is not set
-# CONFIG_CPU_R4X00 is not set
-# CONFIG_CPU_R5000 is not set
-# CONFIG_CPU_R5432 is not set
-# CONFIG_CPU_R5500 is not set
-# CONFIG_CPU_R6000 is not set
-# CONFIG_CPU_R8000 is not set
-# CONFIG_CPU_RM7000 is not set
-# CONFIG_CPU_RM9000 is not set
-# CONFIG_CPU_SB1 is not set
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_HIGHMEM=y
-# CONFIG_CPU_TX39XX is not set
-# CONFIG_CPU_TX49XX is not set
-# CONFIG_CPU_VR41XX is not set
CONFIG_CSRC_R4K=y
CONFIG_CSRC_R4K_LIB=y
CONFIG_DECOMPRESS_LZMA=y
-CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_DMA_NONCOHERENT=y
CONFIG_EARLY_PRINTK=y
# CONFIG_FSNOTIFY is not set
+CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
CONFIG_GENERIC_CMOS_UPDATE=y
-CONFIG_GENERIC_FIND_LAST_BIT=y
-CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_GPIO=y
-CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
CONFIG_HARDWARE_WATCHPOINTS=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_HAVE_CLK=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HAVE_GENERIC_HARDIRQS=y
CONFIG_HAVE_IDE=y
+CONFIG_HAVE_IRQ_WORK=y
CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_PERF_EVENTS=y
CONFIG_HW_RANDOM=y
CONFIG_HZ=250
# CONFIG_HZ_100 is not set
CONFIG_INITRAMFS_SOURCE=""
CONFIG_IRQ_CPU=y
CONFIG_LANTIQ=y
+CONFIG_LANTIQ_MACH_95C3AM1=y
+CONFIG_LANTIQ_MACH_EASY98000=y
+CONFIG_LANTIQ_MACH_EASY98020=y
CONFIG_LANTIQ_WDT=y
CONFIG_LEDS_GPIO=y
-# CONFIG_MACH_ALCHEMY is not set
+CONFIG_MACH_NO_WESTBRIDGE=y
+# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set
CONFIG_MIPS=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
CONFIG_MIPS_MACHINE=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_LANTIQ=y
CONFIG_MTD_UIMAGE_SPLIT=y
-CONFIG_NLS=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_PER_CPU_KM=y
CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_PERF_USE_VMALLOC=y
CONFIG_PHYLIB=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_QUOTACTL is not set
+CONFIG_RTL8366RB_PHY=y
+CONFIG_RTL8366_SMI=y
# CONFIG_SCSI_DMA is not set
# CONFIG_SERIAL_8250 is not set
CONFIG_SERIAL_LANTIQ=y
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
CONFIG_SYS_SUPPORTS_MULTITHREADING=y
-CONFIG_TREE_RCU=y
+CONFIG_XZ_DEC=y
CONFIG_ZONE_DMA_FLAG=0
+++ /dev/null
-CONFIG_ADM6996_PHY=y
-CONFIG_AR8216_PHY=y
-# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set
-# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
-# CONFIG_ATH79 is not set
-CONFIG_GENERIC_ATOMIC64=y
-CONFIG_GENERIC_IRQ_SHOW=y
-CONFIG_HAVE_ARCH_JUMP_LABEL=y
-CONFIG_HAVE_C_RECORDMCOUNT=y
-CONFIG_HAVE_DMA_API_DEBUG=y
-CONFIG_HAVE_DMA_ATTRS=y
-CONFIG_HAVE_DYNAMIC_FTRACE=y
-CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
-CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
-CONFIG_HAVE_FUNCTION_TRACER=y
-CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
-CONFIG_HAVE_GENERIC_HARDIRQS=y
-CONFIG_HAVE_IRQ_WORK=y
-CONFIG_HAVE_PERF_EVENTS=y
-CONFIG_HW_HAS_PCI=y
-CONFIG_INPUT=y
-CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_GPIO_BUTTONS is not set
-CONFIG_INPUT_POLLDEV=y
-# CONFIG_ISDN is not set
-CONFIG_LANTIQ_ETOP=y
-CONFIG_LANTIQ_MACH_ARV45XX=y
-CONFIG_LANTIQ_MACH_EASY50712=y
-# CONFIG_LANTIQ_MACH_NETGEAR is not set
-CONFIG_LANTIQ_MACH_GIGASX76X=y
-CONFIG_MACH_NO_WESTBRIDGE=y
-# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set
-CONFIG_NEED_DMA_MAP_STATE=y
-CONFIG_NEED_PER_CPU_KM=y
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-CONFIG_PERF_USE_VMALLOC=y
-# CONFIG_PREEMPT_RCU is not set
-# CONFIG_QUOTACTL is not set
-CONFIG_RTL8306_PHY=y
-# CONFIG_SOC_AMAZON_SE is not set
-# CONFIG_SOC_FALCON is not set
-CONFIG_SOC_TYPE_XWAY=y
-CONFIG_SOC_XWAY=y
-CONFIG_SPI=y
-CONFIG_SPI_BITBANG=y
-# CONFIG_SPI_GPIO is not set
-CONFIG_SPI_LANTIQ=y
-CONFIG_SPI_MASTER=y
-CONFIG_USB_SUPPORT=y
-CONFIG_XZ_DEC=y
CONFIG_LANTIQ_MACH_ARV45XX=y
CONFIG_LANTIQ_MACH_EASY50712=y
# CONFIG_LANTIQ_MACH_NETGEAR is not set
-CONFIG_LANTIQ_MACH_GIGASX76X=y
# CONFIG_LANTIQ_MACH_WBMR is not set
+CONFIG_LANTIQ_MACH_GIGASX76X=y
CONFIG_MACH_NO_WESTBRIDGE=y
# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_RTL8306_PHY=y
# CONFIG_SOC_AMAZON_SE is not set
# CONFIG_SOC_FALCON is not set
+# CONFIG_SOC_VR9 is not set
CONFIG_SOC_TYPE_XWAY=y
CONFIG_SOC_XWAY=y
CONFIG_SPI=y
CONFIG_SPI_MASTER=y
CONFIG_USB_SUPPORT=y
CONFIG_XZ_DEC=y
+CONFIG_SPI_XWAY=y
define Profile/ARV3527P
NAME:=ARV3527P - Arcor Easybox 401
- PACKAGES:=kmod-ledtrig-netdev kmod-leds-gpio kmod-button-hotplug kmod-ltq-dsl-firmware-b
+ PACKAGES:=kmod-ledtrig-netdev kmod-leds-gpio kmod-button-hotplug kmod-ltq-dsl-firmware-b-danube
endef
define Profile/ARV3527P/Description
NAME:=ARV4510PW - Wippies Homebox
PACKAGES:= kmod-usb-core \
kmod-ledtrig-netdev kmod-ledtrig-usbdev kmod-leds-gpio kmod-button-hotplug \
- kmod-rt61-pci wpad-mini kmod-ltq-dsl-firmware-a
+ kmod-rt61-pci wpad-mini kmod-ltq-dsl-firmware-a-danube
endef
define Profile/ARV4510PW/Description
NAME:=ARV4518PW - SMC7908A
PACKAGES:= kmod-usb-core kmod-usb-dwc-otg \
kmod-ledtrig-netdev kmod-ledtrig-usbdev kmod-leds-gpio kmod-button-hotplug \
- kmod-madwifi wpad-mini kmod-ltq-dsl-firmware-a
+ kmod-madwifi wpad-mini kmod-ltq-dsl-firmware-a-danube
endef
define Profile/ARV4518PW/Description
NAME:=ARV4520PW - Arcor Easybox 800
PACKAGES:= kmod-usb-core kmod-usb-dwc-otg \
kmod-ledtrig-netdev kmod-ledtrig-usbdev kmod-leds-gpio kmod-button-hotplug \
- kmod-rt61-pci wpad-mini kmod-ltq-dsl-firmware-b
+ kmod-rt61-pci wpad-mini kmod-ltq-dsl-firmware-b-danube
endef
define Profile/ARV4520PW/Description
NAME:=ARV4525PW - Speedport W502V
PACKAGES:= kmod-usb-core kmod-usb-dwc-otg \
kmod-ledtrig-netdev kmod-ledtrig-usbdev kmod-leds-gpio kmod-button-hotplug \
- kmod-madwifi wpad-mini kmod-ltq-dsl-firmware-b
+ kmod-madwifi wpad-mini kmod-ltq-dsl-firmware-b-danube
endef
define Profile/ARV4525PW/Description
NAME:=ARV7525PW - Speedport W303V Typ A
PACKAGES:= kmod-usb-core kmod-usb-dwc-otg \
kmod-ledtrig-netdev kmod-ledtrig-usbdev kmod-leds-gpio kmod-button-hotplug \
- kmod-rt2800-pci wpad-mini kmod-ltq-dsl-firmware-b
+ kmod-rt2800-pci wpad-mini kmod-ltq-dsl-firmware-b-danube
endef
define Profile/ARV4525PW/Description
NAME:=ARV452CPW - Arcor Easybox 801
PACKAGES:= kmod-usb-core kmod-usb-dwc-otg \
kmod-ledtrig-netdev kmod-ledtrig-usbdev kmod-leds-gpio kmod-button-hotplug \
- kmod-madwifi wpad-mini kmod-ltq-dsl-firmware-b
+ kmod-madwifi wpad-mini kmod-ltq-dsl-firmware-b-danube
endef
define Profile/ARV452CPW/Description
NAME:=ARV752DPW - Arcor Easybox 802
PACKAGES:= kmod-usb-core kmod-usb-dwc-otg \
kmod-ledtrig-netdev kmod-ledtrig-usbdev kmod-leds-gpio kmod-button-hotplug \
- kmod-rt2800-pci kmod-ltq-dsl-firmware-b
+ kmod-rt2800-pci kmod-ltq-dsl-firmware-b-danube
endef
define Profile/ARV752DPW/Description
NAME:=ARV752DPW22 - Arcor Easybox 803
PACKAGES:= kmod-usb-core kmod-usb2 kmod-usb-uhci kmod-usb-dwc-otg \
kmod-ledtrig-netdev kmod-ledtrig-usbdev kmod-leds-gpio kmod-button-hotplug \
- kmod-ltq-dsl-firmware-b
+ kmod-ltq-dsl-firmware-b-danube
endef
define Profile/ARV752DPW22/Description
define Profile/GIGASX76X
NAME:=GIGASX76X - Gigaset SX761,SX762,SX763
PACKAGES:= kmod-usb-core kmod-usb-dwc-otg kmod-leds-gpio \
- kmod-ltq-dsl-firmware-b kmod-ledtrig-usbdev
+ kmod-ltq-dsl-firmware-b-danube kmod-ledtrig-usbdev
endef
define Profile/GIGASX76X/Description
BOARDNAME:=Danube
FEATURES:=squashfs jffs2 atm
-DEFAULT_PACKAGES+=kmod-pppoa ppp-mod-pppoa linux-atm atm-tools br2684ctl kmod-ltq-dsl ltq-dsl-app swconfig
+DEFAULT_PACKAGES+=kmod-pppoa ppp-mod-pppoa linux-atm atm-tools br2684ctl kmod-ltq-dsl-danube ltq-dsl-app swconfig
define Target/Description
Lantiq Danube/Twinpass
+++ /dev/null
-CONFIG_CPU_MIPSR2_IRQ_EI=y
-CONFIG_CPU_MIPSR2_IRQ_VI=y
-CONFIG_IFX_VPE_CACHE_SPLIT=y
-CONFIG_IFX_VPE_EXT=y
-CONFIG_M25PXX_USE_FAST_READ=y
-CONFIG_MIPS_MT=y
-# CONFIG_MIPS_VPE_APSP_API is not set
-CONFIG_MIPS_VPE_LOADER=y
-CONFIG_MIPS_VPE_LOADER_TOM=y
-CONFIG_MTD_M25P80=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_ECC=y
-CONFIG_MTD_NAND_PLATFORM=y
-# CONFIG_MTD_SM_COMMON is not set
-CONFIG_MTSCHED=y
-# CONFIG_PERFCTRS is not set
-# CONFIG_SOC_AMAZON_SE is not set
-CONFIG_SOC_FALCON=y
-# CONFIG_SOC_TYPE_XWAY is not set
-# CONFIG_SOC_XWAY is not set
-CONFIG_SPI=y
-# CONFIG_SPI_BITBANG is not set
-CONFIG_SPI_FALCON=y
-# CONFIG_SPI_GPIO is not set
-CONFIG_SPI_MASTER=y
-# CONFIG_I2C_DESIGNWARE is not set
-
-# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set
-# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
-# CONFIG_ATH79 is not set
CONFIG_CPU_MIPSR2_IRQ_EI=y
CONFIG_CPU_MIPSR2_IRQ_VI=y
-CONFIG_GENERIC_ATOMIC64=y
-CONFIG_GENERIC_IRQ_SHOW=y
-CONFIG_HAVE_ARCH_JUMP_LABEL=y
-CONFIG_HAVE_C_RECORDMCOUNT=y
-CONFIG_HAVE_DMA_API_DEBUG=y
-CONFIG_HAVE_DMA_ATTRS=y
-CONFIG_HAVE_DYNAMIC_FTRACE=y
-CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
-CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
-CONFIG_HAVE_FUNCTION_TRACER=y
-CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
-CONFIG_HAVE_GENERIC_HARDIRQS=y
-CONFIG_HAVE_IRQ_WORK=y
-CONFIG_HAVE_PERF_EVENTS=y
CONFIG_IFX_VPE_CACHE_SPLIT=y
CONFIG_IFX_VPE_EXT=y
-CONFIG_LANTIQ_MACH_95C3AM1=y
-CONFIG_LANTIQ_MACH_EASY98000=y
-CONFIG_LANTIQ_MACH_EASY98020=y
CONFIG_M25PXX_USE_FAST_READ=y
-CONFIG_MACH_NO_WESTBRIDGE=y
-# CONFIG_MFD_MAX8997 is not set
-# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set
CONFIG_MIPS_MT=y
# CONFIG_MIPS_VPE_APSP_API is not set
CONFIG_MIPS_VPE_LOADER=y
CONFIG_MTD_M25P80=y
CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_ECC=y
-# CONFIG_MTD_NAND_ECC_BCH is not set
CONFIG_MTD_NAND_PLATFORM=y
# CONFIG_MTD_SM_COMMON is not set
CONFIG_MTSCHED=y
-CONFIG_NEED_DMA_MAP_STATE=y
-CONFIG_NEED_PER_CPU_KM=y
# CONFIG_PERFCTRS is not set
-CONFIG_PERF_USE_VMALLOC=y
-# CONFIG_PREEMPT_RCU is not set
-# CONFIG_QUOTACTL is not set
# CONFIG_SOC_AMAZON_SE is not set
CONFIG_SOC_FALCON=y
# CONFIG_SOC_TYPE_XWAY is not set
# CONFIG_SOC_XWAY is not set
+# CONFIG_SOC_VR9 is not set
CONFIG_SPI=y
# CONFIG_SPI_BITBANG is not set
CONFIG_SPI_FALCON=y
# CONFIG_SPI_GPIO is not set
CONFIG_SPI_MASTER=y
-CONFIG_XZ_DEC=y
# CONFIG_I2C_DESIGNWARE is not set
+
--- /dev/null
+/*
+ * Lantiq GPIO LED device support
+ *
+ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#ifndef _LANTIQ_DEV_LEDS_GPIO_H
+#define _LANTIQ_DEV_LEDS_GPIO_H
+
+#include <linux/leds.h>
+
+void ltq_add_device_leds_gpio(int id,
+ unsigned num_leds,
+ struct gpio_led *leds) __init;
+
+#endif /* _LANTIQ_DEV_LEDS_GPIO_H */
--- /dev/null
+/*
+ * Lantiq GPIO button support
+ *
+ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include "linux/init.h"
+#include "linux/slab.h"
+#include <linux/platform_device.h>
+
+#include "dev-gpio-buttons.h"
+
+void __init ltq_register_gpio_keys_polled(int id,
+ unsigned poll_interval,
+ unsigned nbuttons,
+ struct gpio_keys_button *buttons)
+{
+ struct platform_device *pdev;
+ struct gpio_keys_platform_data pdata;
+ struct gpio_keys_button *p;
+ int err;
+
+ p = kmalloc(nbuttons * sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return;
+
+ memcpy(p, buttons, nbuttons * sizeof(*p));
+
+ pdev = platform_device_alloc("gpio-keys-polled", id);
+ if (!pdev)
+ goto err_free_buttons;
+
+ memset(&pdata, 0, sizeof(pdata));
+ pdata.poll_interval = poll_interval;
+ pdata.nbuttons = nbuttons;
+ pdata.buttons = p;
+
+ err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
+ if (err)
+ goto err_put_pdev;
+
+ err = platform_device_add(pdev);
+ if (err)
+ goto err_put_pdev;
+
+ return;
+
+err_put_pdev:
+ platform_device_put(pdev);
+
+err_free_buttons:
+ kfree(p);
+}
--- /dev/null
+/*
+ * Lantiq GPIO button support
+ *
+ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#ifndef _LANTIQ_DEV_GPIO_BUTTONS_H
+#define _LANTIQ_DEV_GPIO_BUTTONS_H
+
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+
+#define LTQ_KEYS_POLL_INTERVAL 20 /* msecs */
+#define LTQ_KEYS_DEBOUNCE_INTERVAL (3 * LTQ_KEYS_POLL_INTERVAL)
+
+void ltq_register_gpio_keys_polled(int id,
+ unsigned poll_interval,
+ unsigned nbuttons,
+ struct gpio_keys_button *buttons);
+
+#endif /* _LANTIQ_DEV_GPIO_BUTTONS_H */
--- /dev/null
+/*
+ * Lantiq GPIO LED device support
+ *
+ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * Parts of this file are based on Atheros' 2.6.15 BSP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#include "dev-leds-gpio.h"
+
+void __init ltq_add_device_leds_gpio(int id, unsigned num_leds,
+ struct gpio_led *leds)
+{
+ struct platform_device *pdev;
+ struct gpio_led_platform_data pdata;
+ struct gpio_led *p;
+ int err;
+
+ p = kmalloc(num_leds * sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return;
+
+ memcpy(p, leds, num_leds * sizeof(*p));
+
+ pdev = platform_device_alloc("leds-gpio", id);
+ if (!pdev)
+ goto err_free_leds;
+
+ memset(&pdata, 0, sizeof(pdata));
+ pdata.num_leds = num_leds;
+ pdata.leds = p;
+
+ err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
+ if (err)
+ goto err_put_pdev;
+
+ err = platform_device_add(pdev);
+ if (err)
+ goto err_put_pdev;
+
+ return;
+
+err_put_pdev:
+ platform_device_put(pdev);
+
+err_free_leds:
+ kfree(p);
+}
--- /dev/null
+/*
+ * EASY98000 CPLD Addon driver
+ *
+ * Copyright (C) 2011 Thomas Langer <thomas.langer@lantiq.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+struct easy98000_reg_cpld {
+ u16 cmdreg1; /* 0x1 */
+ u16 cmdreg0; /* 0x0 */
+ u16 idreg0; /* 0x3 */
+ u16 resreg; /* 0x2 */
+ u16 intreg; /* 0x5 */
+ u16 idreg1; /* 0x4 */
+ u16 ledreg; /* 0x7 */
+ u16 pcmconconfig; /* 0x6 */
+ u16 res0; /* 0x9 */
+ u16 ethledreg; /* 0x8 */
+ u16 res1[4]; /* 0xa-0xd */
+ u16 cpld1v; /* 0xf */
+ u16 cpld2v; /* 0xe */
+};
+static struct easy98000_reg_cpld * const cpld =
+ (struct easy98000_reg_cpld *)(KSEG1 | 0x17c00000);
+#define cpld_r8(reg) (__raw_readw(&cpld->reg) & 0xFF)
+#define cpld_w8(val, reg) __raw_writew((val) & 0xFF, &cpld->reg)
+
+int easy98000_addon_has_dm9000(void)
+{
+ if ((cpld_r8(idreg0) & 0xF) == 1)
+ return 1;
+ return 0;
+}
+
+#if defined(CONFIG_PROC_FS)
+typedef void (*cpld_dump) (struct seq_file *s);
+struct proc_entry {
+ char *name;
+ void *callback;
+};
+
+static int cpld_proc_show ( struct seq_file *s, void *p )
+{
+ cpld_dump dump = s->private;
+
+ if ( dump != NULL )
+ dump(s);
+
+ return 0;
+}
+
+static int cpld_proc_open ( struct inode *inode, struct file *file )
+{
+ return single_open ( file, cpld_proc_show, PDE(inode)->data );
+}
+
+static void cpld_versions_get ( struct seq_file *s )
+{
+ seq_printf(s, "CPLD1: V%d\n", cpld_r8(cpld1v));
+ seq_printf(s, "CPLD2: V%d\n", cpld_r8(cpld2v));
+}
+
+static void cpld_ebu_module_get ( struct seq_file *s )
+{
+ u8 addon_id;
+
+ addon_id = cpld_r8(idreg0) & 0xF;
+ switch (addon_id) {
+ case 0xF: /* nothing connected */
+ break;
+ case 1:
+ seq_printf(s, "Ethernet Controller module (dm9000)\n");
+ break;
+ default:
+ seq_printf(s, "Unknown EBU module (EBU_ID=0x%02X)\n", addon_id);
+ break;
+ }
+}
+
+static void cpld_xmii_module_get ( struct seq_file *s )
+{
+ u8 addon_id;
+ char *mod = NULL;
+
+ addon_id = cpld_r8(idreg1) & 0xF;
+ switch (addon_id) {
+ case 0xF:
+ mod = "no module";
+ break;
+ case 0x1:
+ mod = "RGMII module";
+ break;
+ case 0x4:
+ mod = "GMII MAC Mode (XWAY TANTOS-3G)";
+ break;
+ case 0x6:
+ mod = "TMII MAC Mode (XWAY TANTOS-3G)";
+ break;
+ case 0x8:
+ mod = "GMII PHY module";
+ break;
+ case 0x9:
+ mod = "MII PHY module";
+ break;
+ case 0xA:
+ mod = "RMII PHY module";
+ break;
+ default:
+ break;
+ }
+ if (mod)
+ seq_printf(s, "%s\n", mod);
+ else
+ seq_printf(s, "unknown xMII module (xMII_ID=0x%02X)\n", addon_id);
+}
+
+static struct proc_entry proc_entries[] = {
+ {"versions", cpld_versions_get},
+ {"ebu", cpld_ebu_module_get},
+ {"xmii", cpld_xmii_module_get},
+};
+
+static struct file_operations ops = {
+ .owner = THIS_MODULE,
+ .open = cpld_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void cpld_proc_entry_create(struct proc_dir_entry *parent_node,
+ struct proc_entry *proc_entry)
+{
+ proc_create_data ( proc_entry->name, (S_IFREG | S_IRUGO), parent_node,
+ &ops, proc_entry->callback);
+}
+
+static int cpld_proc_install(void)
+{
+ struct proc_dir_entry *driver_proc_node;
+
+ driver_proc_node = proc_mkdir("cpld", NULL);
+ if (driver_proc_node != NULL) {
+ int i;
+ for (i = 0; i < ARRAY_SIZE(proc_entries); i++)
+ cpld_proc_entry_create(driver_proc_node,
+ &proc_entries[i]);
+ } else {
+ printk("cannot create proc entry");
+ return -1;
+ }
+ return 0;
+}
+#else
+static inline int cpld_proc_install(void) {}
+#endif
+
+static int easy98000_addon_probe(struct platform_device *pdev)
+{
+ return cpld_proc_install();
+}
+
+static int easy98000_addon_remove(struct platform_device *pdev)
+{
+#if defined(CONFIG_PROC_FS)
+ char buf[64];
+ int i;
+
+ for (i = 0; i < sizeof(proc_entries) / sizeof(proc_entries[0]); i++) {
+ sprintf(buf, "cpld/%s", proc_entries[i].name);
+ remove_proc_entry(buf, 0);
+ }
+ remove_proc_entry("cpld", 0);
+#endif
+ return 0;
+}
+
+static struct platform_driver easy98000_addon_driver = {
+ .probe = easy98000_addon_probe,
+ .remove = __devexit_p(easy98000_addon_remove),
+ .driver = {
+ .name = "easy98000_addon",
+ .owner = THIS_MODULE,
+ },
+};
+
+int __init easy98000_addon_init(void)
+{
+ return platform_driver_register(&easy98000_addon_driver);
+}
+
+void __exit easy98000_addon_exit(void)
+{
+ platform_driver_unregister(&easy98000_addon_driver);
+}
+
+module_init(easy98000_addon_init);
+module_exit(easy98000_addon_exit);
--- /dev/null
+/*
+ * EASY98000 CPLD LED driver
+ *
+ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
+
+#include "dev-leds-easy98000-cpld.h"
+
+const char *led_name[8] = {
+ "ge0_act",
+ "ge0_link",
+ "ge1_act",
+ "ge1_link",
+ "fe2_act",
+ "fe2_link",
+ "fe3_act",
+ "fe3_link"
+};
+
+#define cpld_base7 ((u16 *)(KSEG1 | 0x17c0000c))
+#define cpld_base8 ((u16 *)(KSEG1 | 0x17c00012))
+
+#define ltq_r16(reg) __raw_readw(reg)
+#define ltq_w16(val, reg) __raw_writew(val, reg)
+
+struct cpld_led_dev {
+ struct led_classdev cdev;
+ u8 mask;
+ u16 *base;
+};
+
+struct cpld_led_drvdata {
+ struct cpld_led_dev *led_devs;
+ int num_leds;
+};
+
+void led_set(u8 mask, u16 *base)
+{
+ ltq_w16(ltq_r16(base) | mask, base);
+}
+
+void led_clear(u8 mask, u16 *base)
+{
+ ltq_w16(ltq_r16(base) & (~mask), base);
+}
+
+void led_blink_clear(u8 mask, u16 *base)
+{
+ led_clear(mask, base);
+}
+
+static void led_brightness(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct cpld_led_dev *led_dev =
+ container_of(led_cdev, struct cpld_led_dev, cdev);
+
+ if (value)
+ led_set(led_dev->mask, led_dev->base);
+ else
+ led_clear(led_dev->mask, led_dev->base);
+}
+
+static int led_probe(struct platform_device *pdev)
+{
+ int i;
+ char name[32];
+ struct cpld_led_drvdata *drvdata;
+ int ret = 0;
+
+ drvdata = kzalloc(sizeof(struct cpld_led_drvdata) +
+ sizeof(struct cpld_led_dev) * MAX_LED,
+ GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ drvdata->led_devs = (struct cpld_led_dev *) &drvdata[1];
+
+ for (i = 0; i < MAX_LED; i++) {
+ struct cpld_led_dev *led_dev = &drvdata->led_devs[i];
+ led_dev->cdev.brightness_set = led_brightness;
+ led_dev->cdev.default_trigger = NULL;
+ led_dev->mask = 1 << (i % 8);
+ if(i < 8) {
+ sprintf(name, "easy98000-cpld:%s", led_name[i]);
+ led_dev->base = cpld_base8;
+ } else {
+ sprintf(name, "easy98000-cpld:red:%d", i-8);
+ led_dev->base = cpld_base7;
+ }
+ led_dev->cdev.name = name;
+ ret = led_classdev_register(&pdev->dev, &led_dev->cdev);
+ if (ret)
+ goto err;
+ }
+ platform_set_drvdata(pdev, drvdata);
+ return 0;
+
+err:
+ printk("led_probe: 3\n");
+ for (i = i - 1; i >= 0; i--)
+ led_classdev_unregister(&drvdata->led_devs[i].cdev);
+
+ kfree(drvdata);
+ return ret;
+}
+
+static int led_remove(struct platform_device *pdev)
+{
+ int i;
+ struct cpld_led_drvdata *drvdata = platform_get_drvdata(pdev);
+ for (i = 0; i < MAX_LED; i++)
+ led_classdev_unregister(&drvdata->led_devs[i].cdev);
+ kfree(drvdata);
+ return 0;
+}
+
+static struct platform_driver led_driver = {
+ .probe = led_probe,
+ .remove = __devexit_p(led_remove),
+ .driver = {
+ .name = LED_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+int __init easy98000_cpld_led_init(void)
+{
+ pr_info(LED_DESC ", Version " LED_VERSION
+ " (c) Copyright 2011, Lantiq Deutschland GmbH\n");
+ return platform_driver_register(&led_driver);
+}
+
+void __exit easy98000_cpld_led_exit(void)
+{
+ platform_driver_unregister(&led_driver);
+}
+
+module_init(easy98000_cpld_led_init);
+module_exit(easy98000_cpld_led_exit);
+
+MODULE_DESCRIPTION(LED_NAME);
+MODULE_DESCRIPTION(LED_DESC);
+MODULE_AUTHOR("Ralph Hempel <ralph.hempel@lantiq.com>");
+MODULE_LICENSE("GPL v2");
+
--- /dev/null
+/*
+ * EASY98000 CPLD LED driver
+ *
+ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+#ifndef _INCLUDE_EASY98000_CPLD_LED_H_
+#define _INCLUDE_EASY98000_CPLD_LED_H_
+
+#define LED_NAME "easy98000_cpld_led"
+#define LED_DESC "EASY98000 LED driver"
+#define LED_VERSION "1.0.0"
+
+#define MAX_LED 16
+
+#endif /* _INCLUDE_EASY98000_CPLD_LED_H_ */
--- /dev/null
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/i2c-gpio.h>
+#include "../machtypes.h"
+
+#include "devices.h"
+#include "dev-leds-gpio.h"
+
+#define BOARD_95C3AM1_GPIO_LED_0 10
+#define BOARD_95C3AM1_GPIO_LED_1 11
+#define BOARD_95C3AM1_GPIO_LED_2 12
+#define BOARD_95C3AM1_GPIO_LED_3 13
+
+extern unsigned char ltq_ethaddr[6];
+
+static struct mtd_partition board_95C3AM1_partitions[] =
+{
+ {
+ .name = "uboot",
+ .offset = 0x0,
+ .size = 0x40000,
+ },
+ {
+ .name = "uboot_env",
+ .offset = 0x40000,
+ .size = 0x40000, /* 2 sectors for redundant env. */
+ },
+ {
+ .name = "linux",
+ .offset = 0x80000,
+ .size = 0xF80000, /* map only 16 MiB */
+ },
+};
+
+static struct flash_platform_data board_95C3AM1_flash_platform_data = {
+ .name = "sflash",
+ .parts = board_95C3AM1_partitions,
+ .nr_parts = ARRAY_SIZE(board_95C3AM1_partitions)
+};
+
+static struct spi_board_info board_95C3AM1_flash_data __initdata = {
+ .modalias = "m25p80",
+ .bus_num = 0,
+ .chip_select = 0,
+ .max_speed_hz = 10 * 1000 * 1000,
+ .mode = SPI_MODE_3,
+ .platform_data = &board_95C3AM1_flash_platform_data
+};
+
+static struct gpio_led board_95C3AM1_leds_gpio[] __initdata = {
+ {
+ .name = "power",
+ .gpio = BOARD_95C3AM1_GPIO_LED_0,
+ .active_low = 0,
+ }, {
+ .name = "optical",
+ .gpio = BOARD_95C3AM1_GPIO_LED_1,
+ .active_low = 0,
+ }, {
+ .name = "lan",
+ .gpio = BOARD_95C3AM1_GPIO_LED_2,
+ .active_low = 0,
+ }, {
+ .name = "update",
+ .gpio = BOARD_95C3AM1_GPIO_LED_3,
+ .active_low = 0,
+ }
+};
+
+static struct i2c_gpio_platform_data board_95C3AM1_i2c_gpio_data = {
+ .sda_pin = 107,
+ .scl_pin = 108,
+};
+
+static struct platform_device board_95C3AM1_i2c_gpio_device = {
+ .name = "i2c-gpio",
+ .id = 0,
+ .dev = {
+ .platform_data = &board_95C3AM1_i2c_gpio_data,
+ }
+};
+
+static void __init board_95C3AM1_init(void)
+{
+ falcon_register_i2c();
+ falcon_register_spi_flash(&board_95C3AM1_flash_data);
+ platform_device_register(&board_95C3AM1_i2c_gpio_device);
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(board_95C3AM1_leds_gpio),
+ board_95C3AM1_leds_gpio);
+}
+
+MIPS_MACHINE(LANTIQ_MACH_95C3AM1,
+ "95C3AM1",
+ "95C3AM1 Board",
+ board_95C3AM1_init);
--- /dev/null
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include <linux/gpio_buttons.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+
+#include "../machtypes.h"
+#include "devices.h"
+#include "dev-leds-gpio.h"
+
+#define EASY98020_GPIO_LED_0 9
+#define EASY98020_GPIO_LED_1 10
+#define EASY98020_GPIO_LED_2 11
+#define EASY98020_GPIO_LED_3 12
+#define EASY98020_GPIO_LED_GE0_ACT 110
+#define EASY98020_GPIO_LED_GE0_LINK 109
+#define EASY98020_GPIO_LED_GE1_ACT 106
+#define EASY98020_GPIO_LED_GE1_LINK 105
+
+extern unsigned char ltq_ethaddr[6];
+
+static struct mtd_partition easy98020_spi_partitions[] =
+{
+ {
+ .name = "uboot",
+ .offset = 0x0,
+ .size = 0x40000,
+ },
+ {
+ .name = "uboot_env",
+ .offset = 0x40000,
+ .size = 0x40000, /* 2 sectors for redundant env. */
+ },
+ {
+ .name = "linux",
+ .offset = 0x80000,
+ .size = 0xF80000, /* map only 16 MiB */
+ },
+};
+
+static struct flash_platform_data easy98020_spi_flash_platform_data = {
+ .name = "sflash",
+ .parts = easy98020_spi_partitions,
+ .nr_parts = ARRAY_SIZE(easy98020_spi_partitions)
+};
+
+static struct spi_board_info easy98020_spi_flash_data __initdata = {
+ .modalias = "m25p80",
+ .bus_num = 0,
+ .chip_select = 0,
+ .max_speed_hz = 10 * 1000 * 1000,
+ .mode = SPI_MODE_3,
+ .platform_data = &easy98020_spi_flash_platform_data
+};
+
+static struct gpio_led easy98020_leds_gpio[] __initdata = {
+ {
+ .name = "easy98020:green:0",
+ .gpio = EASY98020_GPIO_LED_0,
+ .active_low = 0,
+ }, {
+ .name = "easy98020:green:1",
+ .gpio = EASY98020_GPIO_LED_1,
+ .active_low = 0,
+ }, {
+ .name = "easy98020:green:2",
+ .gpio = EASY98020_GPIO_LED_2,
+ .active_low = 0,
+ }, {
+ .name = "easy98020:green:3",
+ .gpio = EASY98020_GPIO_LED_3,
+ .active_low = 0,
+ }, {
+ .name = "easy98020:ge0_act",
+ .gpio = EASY98020_GPIO_LED_GE0_ACT,
+ .active_low = 0,
+ }, {
+ .name = "easy98020:ge0_link",
+ .gpio = EASY98020_GPIO_LED_GE0_LINK,
+ .active_low = 0,
+ }, {
+ .name = "easy98020:ge1_act",
+ .gpio = EASY98020_GPIO_LED_GE1_ACT,
+ .active_low = 0,
+ }, {
+ .name = "easy98020:ge1_link",
+ .gpio = EASY98020_GPIO_LED_GE1_LINK,
+ .active_low = 0,
+ }
+};
+
+static void __init easy98020_init(void)
+{
+ falcon_register_i2c();
+ falcon_register_spi_flash(&easy98020_spi_flash_data);
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(easy98020_leds_gpio),
+ easy98020_leds_gpio);
+}
+
+MIPS_MACHINE(LANTIQ_MACH_EASY98020,
+ "EASY98020",
+ "EASY98020 Eval Board",
+ easy98020_init);
+
+MIPS_MACHINE(LANTIQ_MACH_EASY98020_1LAN,
+ "EASY98020_1LAN",
+ "EASY98020 Eval Board (1 LAN port)",
+ easy98020_init);
+
+MIPS_MACHINE(LANTIQ_MACH_EASY98020_2LAN,
+ "EASY98020_2LAN",
+ "EASY98020 Eval Board (2 LAN ports)",
+ easy98020_init);
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/mtd/physmap.h>
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/etherdevice.h>
+#include <linux/reboot.h>
+#include <linux/time.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+
+#include <lantiq_soc.h>
+#include <lantiq_irq.h>
+#include <lantiq_platform.h>
+
+#define LTQ_USB_IOMEM_BASE 0x1e101000
+#define LTQ_USB_IOMEM_SIZE 0x00001000
+
+static struct resource resources[] =
+{
+ [0] = {
+ .name = "dwc_otg_membase",
+ .start = LTQ_USB_IOMEM_BASE,
+ .end = LTQ_USB_IOMEM_BASE + LTQ_USB_IOMEM_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "dwc_otg_irq",
+ .start = LTQ_USB_INT,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 dwc_dmamask = (u32)0x1fffffff;
+
+static struct platform_device platform_dev = {
+ .name = "dwc_otg",
+ .dev = {
+ .dma_mask = &dwc_dmamask,
+ },
+ .resource = resources,
+ .num_resources = ARRAY_SIZE(resources),
+};
+
+int __init
+xway_register_dwc(int pin)
+{
+ struct irq_data d;
+ d.irq = resources[1].start;
+ ltq_enable_irq(&d);
+ platform_dev.dev.platform_data = (void*) pin;
+ return platform_device_register(&platform_dev);
+}
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LTQ_DEV_DWC_H__
+#define _LTQ_DEV_DWC_H__
+
+#include <lantiq_platform.h>
+
+extern void __init xway_register_dwc(int pin);
+
+#endif
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include <linux/gpio_buttons.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/input.h>
+#include <linux/etherdevice.h>
+#include <linux/ath5k_platform.h>
+#include <linux/pci.h>
+
+#include <lantiq_soc.h>
+#include <lantiq_platform.h>
+
+#include "../machtypes.h"
+#include "../dev-leds-gpio.h"
+#include "devices.h"
+#include "dev-dwc_otg.h"
+
+static struct mtd_partition arv4510_partitions[] =
+{
+ {
+ .name = "uboot",
+ .offset = 0x0,
+ .size = 0x20000,
+ },
+ {
+ .name = "uboot_env",
+ .offset = 0x20000,
+ .size = 0x120000,
+ },
+ {
+ .name = "linux",
+ .offset = 0x40000,
+ .size = 0xfa0000,
+ },
+ {
+ .name = "board_config",
+ .offset = 0xfe0000,
+ .size = 0x20000,
+ },
+};
+
+static struct mtd_partition arv45xx_partitions[] =
+{
+ {
+ .name = "uboot",
+ .offset = 0x0,
+ .size = 0x20000,
+ },
+ {
+ .name = "uboot_env",
+ .offset = 0x20000,
+ .size = 0x10000,
+ },
+ {
+ .name = "linux",
+ .offset = 0x30000,
+ .size = 0x3c0000,
+ },
+ {
+ .name = "board_config",
+ .offset = 0x3f0000,
+ .size = 0x10000,
+ },
+};
+
+static struct mtd_partition arv75xx_partitions[] =
+{
+ {
+ .name = "uboot",
+ .offset = 0x0,
+ .size = 0x10000,
+ },
+ {
+ .name = "uboot_env",
+ .offset = 0x10000,
+ .size = 0x10000,
+ },
+ {
+ .name = "linux",
+ .offset = 0x20000,
+ .size = 0x7d0000,
+ },
+ {
+ .name = "board_config",
+ .offset = 0x7f0000,
+ .size = 0x10000,
+ },
+};
+
+static struct physmap_flash_data arv4510_flash_data = {
+ .nr_parts = ARRAY_SIZE(arv4510_partitions),
+ .parts = arv4510_partitions,
+};
+
+static struct physmap_flash_data arv45xx_flash_data = {
+ .nr_parts = ARRAY_SIZE(arv45xx_partitions),
+ .parts = arv45xx_partitions,
+};
+
+static struct physmap_flash_data arv75xx_flash_data = {
+ .nr_parts = ARRAY_SIZE(arv75xx_partitions),
+ .parts = arv75xx_partitions,
+};
+
+static struct ltq_pci_data ltq_pci_data = {
+ .clock = PCI_CLOCK_EXT,
+ .gpio = PCI_GNT1 | PCI_REQ1,
+ .irq = {
+ [14] = INT_NUM_IM0_IRL0 + 22,
+ },
+};
+
+static struct ltq_eth_data ltq_eth_data = {
+ .mii_mode = PHY_INTERFACE_MODE_RMII,
+};
+
+static struct gpio_led
+arv4510pw_leds_gpio[] __initdata = {
+ { .name = "soc:green:foo", .gpio = 4, .active_low = 1, },
+};
+
+static struct gpio_led
+arv4518pw_leds_gpio[] __initdata = {
+ { .name = "soc:green:power", .gpio = 3, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:adsl", .gpio = 4, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:internet", .gpio = 5, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:wlan", .gpio = 6, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:yellow:wps", .gpio = 7, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:fail", .gpio = 8, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:usb", .gpio = 19, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:voip", .gpio = 100, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:fxs1", .gpio = 101, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:fxs2", .gpio = 102, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:fxo", .gpio = 103, .active_low = 1, .default_trigger = "default-on" },
+};
+
+static struct gpio_button
+arv4518pw_gpio_buttons[] __initdata = {
+ { .desc = "wlan", .type = EV_KEY, .code = BTN_0, .threshold = 3, .gpio = 28, .active_low = 1, },
+ { .desc = "wps", .type = EV_KEY, .code = BTN_1, .threshold = 3, .gpio = 29, .active_low = 1, },
+ { .desc = "reset", .type = EV_KEY, .code = BTN_2, .threshold = 3, .gpio = 30, .active_low = 1, },
+};
+
+static struct gpio_led
+arv4520pw_leds_gpio[] __initdata = {
+ { .name = "soc:blue:power", .gpio = 3, .active_low = 1, },
+ { .name = "soc:blue:adsl", .gpio = 4, .active_low = 1, },
+ { .name = "soc:blue:internet", .gpio = 5, .active_low = 1, },
+ { .name = "soc:red:power", .gpio = 6, .active_low = 1, },
+ { .name = "soc:yellow:wps", .gpio = 7, .active_low = 1, },
+ { .name = "soc:red:wps", .gpio = 9, .active_low = 1, },
+ { .name = "soc:blue:voip", .gpio = 100, .active_low = 1, },
+ { .name = "soc:blue:fxs1", .gpio = 101, .active_low = 1, },
+ { .name = "soc:blue:fxs2", .gpio = 102, .active_low = 1, },
+ { .name = "soc:blue:fxo", .gpio = 103, .active_low = 1, },
+ { .name = "soc:blue:voice", .gpio = 104, .active_low = 1, },
+ { .name = "soc:blue:usb", .gpio = 105, .active_low = 1, },
+ { .name = "soc:blue:wlan", .gpio = 106, .active_low = 1, },
+};
+
+static struct gpio_led
+arv452cpw_leds_gpio[] __initdata = {
+ { .name = "soc:blue:power", .gpio = 3, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:adsl", .gpio = 4, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:isdn", .gpio = 5, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:power", .gpio = 6, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:yellow:wps", .gpio = 7, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:wps", .gpio = 9, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:fxs1", .gpio = 100, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:fxs2", .gpio = 101, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:wps", .gpio = 102, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:fxo", .gpio = 103, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:voice", .gpio = 104, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:usb", .gpio = 105, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:wlan", .gpio = 106, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:internet", .gpio = 108, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:internet", .gpio = 109, .active_low = 1, .default_trigger = "default-on" },
+};
+
+static struct gpio_led
+arv4525pw_leds_gpio[] __initdata = {
+ { .name = "soc:green:festnetz", .gpio = 4, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:internet", .gpio = 5, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:dsl", .gpio = 6, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:wlan", .gpio = 8, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:online", .gpio = 9, .active_low = 1, .default_trigger = "default-on" },
+};
+
+static struct gpio_led
+arv752dpw22_leds_gpio[] __initdata = {
+ { .name = "soc:blue:power", .gpio = 3, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:internet", .gpio = 5, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:power", .gpio = 6, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:wps", .gpio = 8, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:fxo", .gpio = 103, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:voice", .gpio = 104, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:usb", .gpio = 105, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:wlan", .gpio = 106, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:wlan1", .gpio = 107, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:wlan", .gpio = 108, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:wlan1", .gpio = 109, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:eth1", .gpio = 111, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:eth2", .gpio = 112, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:eth3", .gpio = 113, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:eth4", .gpio = 114, .active_low = 1, .default_trigger = "default-on", },
+};
+
+static struct gpio_button
+arv752dpw22_gpio_buttons[] __initdata = {
+ { .desc = "btn0", .type = EV_KEY, .code = BTN_0, .threshold = 3, .gpio = 12, .active_low = 1, },
+ { .desc = "btn1", .type = EV_KEY, .code = BTN_1, .threshold = 3, .gpio = 13, .active_low = 1, },
+ { .desc = "btn2", .type = EV_KEY, .code = BTN_2, .threshold = 3, .gpio = 28, .active_low = 1, },
+};
+
+static struct gpio_led
+arv7518pw_leds_gpio[] __initdata = {
+ { .name = "soc:green:power", .gpio = 2, .active_low = 1, },
+ { .name = "soc:green:adsl", .gpio = 4, .active_low = 1, },
+ { .name = "soc:green:internet", .gpio = 5, .active_low = 1, },
+ { .name = "soc:green:wlan", .gpio = 6, .active_low = 1, },
+ { .name = "soc:red:internet", .gpio = 8, .active_low = 1, },
+ { .name = "soc:green:usb", .gpio = 19, .active_low = 1, },
+};
+
+static struct gpio_button
+arv7518pw_gpio_buttons[] __initdata = {
+ { .desc = "reset", .type = EV_KEY, .code = BTN_0, .threshold = 3, .gpio = 23, .active_low = 1, },
+ { .desc = "wlan", .type = EV_KEY, .code = BTN_1, .threshold = 3, .gpio = 25, .active_low = 1, },
+};
+
+static void
+arv45xx_register_ethernet(void)
+{
+#define ARV45XX_BRN_MAC 0x3f0016
+ memcpy_fromio(<q_eth_data.mac.sa_data,
+ (void *)KSEG1ADDR(LTQ_FLASH_START + ARV45XX_BRN_MAC), 6);
+ ltq_register_etop(<q_eth_data);
+}
+
+static void
+arv75xx_register_ethernet(void)
+{
+#define ARV75XX_BRN_MAC 0x7f0016
+ memcpy_fromio(<q_eth_data.mac.sa_data,
+ (void *)KSEG1ADDR(LTQ_FLASH_START + ARV75XX_BRN_MAC), 6);
+ ltq_register_etop(<q_eth_data);
+}
+
+static void
+bewan_register_ethernet(void)
+{
+#define BEWAN_BRN_MAC 0x3f0014
+ memcpy_fromio(<q_eth_data.mac.sa_data,
+ (void *)KSEG1ADDR(LTQ_FLASH_START + BEWAN_BRN_MAC), 6);
+ ltq_register_etop(<q_eth_data);
+}
+
+static u16 arv45xx_ath5k_eeprom_data[ATH5K_PLAT_EEP_MAX_WORDS];
+static struct ath5k_platform_data arv45xx_ath5k_platform_data;
+
+/*static int arv45xx_pci_plat_dev_init(struct pci_dev *dev)
+{
+ dev->dev.platform_data = &arv45xx_ath5k_platform_data;
+ return 0;
+}
+*/
+void __init
+arv45xx_register_ath5k(void)
+{
+#define ARV45XX_BRN_ATH 0x3f0478
+ int i;
+ unsigned char eeprom_mac[6];
+ static u16 eeprom_data[ATH5K_PLAT_EEP_MAX_WORDS];
+ u32 *p = (u32*)arv45xx_ath5k_eeprom_data;
+
+ memcpy_fromio(eeprom_mac,
+ (void *)KSEG1ADDR(LTQ_FLASH_START + ARV45XX_BRN_MAC), 6);
+ eeprom_mac[5]++;
+ memcpy_fromio(arv45xx_ath5k_eeprom_data,
+ (void *)KSEG1ADDR(LTQ_FLASH_START + ARV45XX_BRN_ATH), ATH5K_PLAT_EEP_MAX_WORDS);
+ // swap eeprom bytes
+ for (i = 0; i < ATH5K_PLAT_EEP_MAX_WORDS>>1; i++){
+ //arv4518_ath5k_eeprom_data[i] = ((eeprom_data[i]&0xff)<<8)|((eeprom_data[i]&0xff00)>>8);
+ p[i] = ((eeprom_data[(i<<1)+1]&0xff)<<24)|((eeprom_data[(i<<1)+1]&0xff00)<<8)|((eeprom_data[i<<1]&0xff)<<8)|((eeprom_data[i<<1]&0xff00)>>8);
+ if (i == 0xbf>>1){
+ // printk ("regdomain: 0x%x --> 0x%x\n", p[i], (p[i] & 0xffff0000)|0x67);
+ /* regdomain is invalid?? how did original fw convert
+ * value to 0x82d4 ??
+ * for now, force to 0x67 */
+ p[i] &= 0xffff0000;
+ p[i] |= 0x67;
+ }
+ }
+ arv45xx_ath5k_platform_data.eeprom_data = arv45xx_ath5k_eeprom_data;
+ arv45xx_ath5k_platform_data.macaddr = eeprom_mac;
+ //lqpci_plat_dev_init = arv45xx_pci_plat_dev_init;
+}
+
+static void __init
+arv3527p_init(void)
+{
+ ltq_register_gpio_stp();
+ //ltq_add_device_leds_gpio(arv3527p_leds_gpio, ARRAY_SIZE(arv3527p_leds_gpio));
+ ltq_register_nor(&arv45xx_flash_data);
+ arv45xx_register_ethernet();
+}
+
+MIPS_MACHINE(LANTIQ_MACH_ARV3527P,
+ "ARV3527P",
+ "ARV3527P - Arcor Easybox 401",
+ arv3527p_init);
+
+static void __init
+arv4510pw_init(void)
+{
+ ltq_register_gpio_stp();
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv4510pw_leds_gpio), arv4510pw_leds_gpio);
+ ltq_register_nor(&arv4510_flash_data);
+ ltq_pci_data.irq[12] = (INT_NUM_IM2_IRL0 + 31);
+ ltq_pci_data.irq[15] = (INT_NUM_IM0_IRL0 + 26);
+ ltq_pci_data.gpio |= PCI_EXIN2 | PCI_REQ2;
+ ltq_register_pci(<q_pci_data);
+ bewan_register_ethernet();
+}
+
+MIPS_MACHINE(LANTIQ_MACH_ARV4510PW,
+ "ARV4510PW",
+ "ARV4510PW - Wippies Homebox",
+ arv4510pw_init);
+
+static void __init
+arv4518pw_init(void)
+{
+#define ARV4518PW_EBU 0
+#define ARV4518PW_USB 14
+#define ARV4518PW_SWITCH_RESET 13
+
+ ltq_register_gpio_ebu(ARV4518PW_EBU);
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv4518pw_leds_gpio), arv4518pw_leds_gpio);
+ ltq_register_gpio_buttons(arv4518pw_gpio_buttons, ARRAY_SIZE(arv4518pw_gpio_buttons));
+ ltq_register_nor(&arv45xx_flash_data);
+ ltq_pci_data.gpio = PCI_GNT2 | PCI_REQ2;
+ ltq_register_pci(<q_pci_data);
+ ltq_register_madwifi_eep();
+ xway_register_dwc(ARV4518PW_USB);
+ arv45xx_register_ethernet();
+ arv45xx_register_ath5k();
+
+ gpio_request(ARV4518PW_SWITCH_RESET, "switch");
+ gpio_direction_output(ARV4518PW_SWITCH_RESET, 1);
+ gpio_export(ARV4518PW_SWITCH_RESET, 0);
+}
+
+MIPS_MACHINE(LANTIQ_MACH_ARV4518PW,
+ "ARV4518PW",
+ "ARV4518PW - SMC7908A-ISP, Airties WAV-221",
+ arv4518pw_init);
+
+static void __init
+arv4520pw_init(void)
+{
+#define ARV4520PW_EBU 0x400
+#define ARV4520PW_USB 28
+#define ARV4520PW_SWITCH_RESET 110
+
+ ltq_register_gpio_ebu(ARV4520PW_EBU);
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv4520pw_leds_gpio), arv4520pw_leds_gpio);
+ ltq_register_nor(&arv45xx_flash_data);
+ ltq_register_pci(<q_pci_data);
+ ltq_register_tapi();
+ arv45xx_register_ethernet();
+ xway_register_dwc(ARV4520PW_USB);
+
+ gpio_request(ARV4520PW_SWITCH_RESET, "switch");
+ gpio_set_value(ARV4520PW_SWITCH_RESET, 1);
+}
+
+MIPS_MACHINE(LANTIQ_MACH_ARV4520PW,
+ "ARV4520PW",
+ "ARV4520PW - Airties WAV-281, Arcor A800",
+ arv4520pw_init);
+
+static void __init
+arv452Cpw_init(void)
+{
+#define ARV452CPW_EBU 0x77f
+#define ARV452CPW_USB 28
+#define ARV452CPW_RELAY1 31
+#define ARV452CPW_RELAY2 107
+#define ARV452CPW_SWITCH_RESET 110
+
+ ltq_register_gpio_ebu(ARV452CPW_EBU);
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv452cpw_leds_gpio), arv452cpw_leds_gpio);
+ ltq_register_nor(&arv45xx_flash_data);
+ ltq_register_pci(<q_pci_data);
+ ltq_register_madwifi_eep();
+ xway_register_dwc(ARV452CPW_USB);
+ arv45xx_register_ethernet();
+ arv45xx_register_ath5k();
+
+ gpio_request(ARV452CPW_SWITCH_RESET, "switch");
+ gpio_set_value(ARV452CPW_SWITCH_RESET, 1);
+ gpio_export(ARV452CPW_SWITCH_RESET, 0);
+
+ gpio_request(ARV452CPW_RELAY1, "relay1");
+ gpio_direction_output(ARV452CPW_RELAY1, 1);
+ gpio_export(ARV452CPW_RELAY1, 0);
+
+ gpio_request(ARV452CPW_RELAY2, "relay2");
+ gpio_set_value(ARV452CPW_RELAY2, 1);
+ gpio_export(ARV452CPW_RELAY2, 0);
+}
+
+MIPS_MACHINE(LANTIQ_MACH_ARV452CPW,
+ "ARV452CPW",
+ "ARV452CPW - Arcor A801",
+ arv452Cpw_init);
+
+static void __init
+arv4525pw_init(void)
+{
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv4525pw_leds_gpio), arv4525pw_leds_gpio);
+ ltq_register_nor(&arv45xx_flash_data);
+ ltq_pci_data.clock = PCI_CLOCK_INT;
+ ltq_register_pci(<q_pci_data);
+ ltq_register_madwifi_eep();
+ ltq_eth_data.mii_mode = PHY_INTERFACE_MODE_MII;
+ arv45xx_register_ethernet();
+}
+
+MIPS_MACHINE(LANTIQ_MACH_ARV4525PW,
+ "ARV4525PW",
+ "ARV4525PW - Speedport W502V",
+ arv4525pw_init);
+
+static void __init
+arv7518pw_init(void)
+{
+#define ARV7518PW_EBU 0x2
+#define ARV7518PW_USB 14
+
+ ltq_register_gpio_ebu(ARV7518PW_EBU);
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv7518pw_leds_gpio), arv7518pw_leds_gpio);
+ ltq_register_gpio_buttons(arv7518pw_gpio_buttons, ARRAY_SIZE(arv7518pw_gpio_buttons));
+ ltq_register_nor(&arv75xx_flash_data);
+ ltq_register_pci(<q_pci_data);
+ ltq_register_tapi();
+ xway_register_dwc(ARV7518PW_USB);
+ arv75xx_register_ethernet();
+ //arv7518_register_ath9k(mac);
+}
+
+MIPS_MACHINE(LANTIQ_MACH_ARV7518PW,
+ "ARV7518PW",
+ "ARV7518PW - ASTORIA",
+ arv7518pw_init);
+
+static void __init
+arv752dpw22_init(void)
+{
+#define ARV752DPW22_EBU 0x2
+#define ARV752DPW22_USB 100
+#define ARV752DPW22_RELAY 101
+
+ ltq_register_gpio_ebu(ARV752DPW22_EBU);
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv752dpw22_leds_gpio), arv752dpw22_leds_gpio);
+ ltq_register_gpio_buttons(arv752dpw22_gpio_buttons, ARRAY_SIZE(arv752dpw22_gpio_buttons));
+ ltq_register_nor(&arv75xx_flash_data);
+ ltq_pci_data.irq[15] = (INT_NUM_IM3_IRL0 + 31);
+ ltq_pci_data.gpio |= PCI_EXIN1 | PCI_REQ2;
+ ltq_register_pci(<q_pci_data);
+ xway_register_dwc(ARV752DPW22_USB);
+ arv75xx_register_ethernet();
+
+ gpio_request(ARV752DPW22_RELAY, "relay");
+ gpio_set_value(ARV752DPW22_RELAY, 1);
+ gpio_export(ARV752DPW22_RELAY, 0);
+}
+
+MIPS_MACHINE(LANTIQ_MACH_ARV752DPW22,
+ "ARV752DPW22",
+ "ARV752DPW22 - Arcor A803",
+ arv752dpw22_init);
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/input.h>
+
+#include <lantiq.h>
+
+#include "../machtypes.h"
+#include "devices.h"
+
+static struct mtd_partition easy50601_partitions[] = {
+ {
+ .name = "uboot",
+ .offset = 0x0,
+ .size = 0x10000,
+ },
+ {
+ .name = "uboot_env",
+ .offset = 0x10000,
+ .size = 0x10000,
+ },
+ {
+ .name = "linux",
+ .offset = 0x20000,
+ .size = 0x3d0000,
+ },
+};
+
+static struct physmap_flash_data easy50601_flash_data = {
+ .nr_parts = ARRAY_SIZE(easy50601_partitions),
+ .parts = easy50601_partitions,
+};
+
+static struct ltq_eth_data ltq_eth_data = {
+ .mii_mode = -1, /* use EPHY */
+};
+
+static void __init easy50601_init(void)
+{
+ ltq_register_nor(&easy50601_flash_data);
+ ltq_register_etop(<q_eth_data);
+}
+
+MIPS_MACHINE(LTQ_MACH_EASY50601,
+ "EASY50601",
+ "EASY50601 Eval Board",
+ easy50601_init);
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/input.h>
+#include <linux/phy.h>
+
+#include <lantiq_soc.h>
+#include <irq.h>
+
+#include "../machtypes.h"
+#include "devices.h"
+
+static struct mtd_partition easy50712_partitions[] = {
+ {
+ .name = "uboot",
+ .offset = 0x0,
+ .size = 0x10000,
+ },
+ {
+ .name = "uboot_env",
+ .offset = 0x10000,
+ .size = 0x10000,
+ },
+ {
+ .name = "linux",
+ .offset = 0x20000,
+ .size = 0x3d0000,
+ },
+};
+
+static struct physmap_flash_data easy50712_flash_data = {
+ .nr_parts = ARRAY_SIZE(easy50712_partitions),
+ .parts = easy50712_partitions,
+};
+
+static struct ltq_pci_data ltq_pci_data = {
+ .clock = PCI_CLOCK_INT,
+ .gpio = PCI_GNT1 | PCI_REQ1,
+ .irq = {
+ [14] = INT_NUM_IM0_IRL0 + 22,
+ },
+};
+
+static struct ltq_eth_data ltq_eth_data = {
+ .mii_mode = PHY_INTERFACE_MODE_MII,
+};
+
+static void __init easy50712_init(void)
+{
+ ltq_register_gpio_stp();
+ ltq_register_nor(&easy50712_flash_data);
+ ltq_register_pci(<q_pci_data);
+ ltq_register_etop(<q_eth_data);
+ ltq_register_tapi();
+}
+
+MIPS_MACHINE(LTQ_MACH_EASY50712,
+ "EASY50712",
+ "EASY50712 Eval Board",
+ easy50712_init);
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/input.h>
+#include <linux/phy.h>
+
+#include <lantiq_soc.h>
+#include <irq.h>
+
+#include "../machtypes.h"
+#include "devices.h"
+
+/*static struct mtd_partition fritz3370_partitions[] = {
+ {
+ .name = "uboot",
+ .offset = 0x0,
+ .size = 0x10000,
+ },
+ {
+ .name = "uboot_env",
+ .offset = 0x10000,
+ .size = 0x10000,
+ },
+ {
+ .name = "linux",
+ .offset = 0x20000,
+ .size = 0xe0000,
+ },
+ {
+ .name = "rootfs",
+ .offset = 0x100000,
+ .size = 0x300000,
+ },
+};
+
+static struct physmap_flash_data fritz3370_flash_data = {
+ .nr_parts = ARRAY_SIZE(fritz3370_partitions),
+ .parts = fritz3370_partitions,
+};
+
+static struct ltq_pci_data ltq_pci_data = {
+ .clock = PCI_CLOCK_INT,
+ .gpio = PCI_GNT1 | PCI_REQ1,
+ .irq = {
+ [14] = INT_NUM_IM0_IRL0 + 22,
+ },
+};
+*/
+static struct ltq_eth_data ltq_eth_data = {
+ .mii_mode = PHY_INTERFACE_MODE_MII,
+};
+
+extern void xway_register_nand(void);
+
+static void __init fritz3370_init(void)
+{
+// ltq_register_gpio_stp();
+// ltq_register_nor(&fritz3370_flash_data);
+// ltq_register_pci(<q_pci_data);
+ ltq_register_etop(<q_eth_data);
+ xway_register_nand();
+}
+
+MIPS_MACHINE(LANTIQ_MACH_FRITZ3370,
+ "FRITZ3370",
+ "FRITZ!BOX 3370",
+ fritz3370_init);
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * Copyright (C) 2011 Andrej Vlašić
+ * Copyright (C) 2011 Luka Perkov
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include <linux/gpio_buttons.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/input.h>
+#include <linux/ath5k_platform.h>
+#include <linux/pci.h>
+#include <linux/phy.h>
+
+#include <irq.h>
+
+#include <lantiq_soc.h>
+#include <lantiq_platform.h>
+
+#include "../machtypes.h"
+#include "../dev-leds-gpio.h"
+#include "devices.h"
+#include "dev-dwc_otg.h"
+
+static struct mtd_partition gigasx76x_partitions[] =
+{
+ {
+ .name = "secondary_env",
+ .offset = 0xe000,
+ .size = 0x2000,
+ },
+ {
+ .name = "secondary_boot",
+ .offset = 0x10000,
+ .size = 0x10000,
+ },
+ {
+ .name = "uboot",
+ .offset = 0x20000,
+ .size = 0x30000,
+ },
+ {
+ .name = "linux",
+ .offset = 0x50000,
+ .size = 0x7a0000,
+ },
+ {
+ .name = "board_config",
+ .offset = 0x7f0000,
+ .size = 0x10000,
+ },
+};
+
+static struct gpio_led
+gigasx76x_leds_gpio[] __initdata = {
+ { .name = "soc:green:usb", .gpio = 202, },
+ { .name = "soc:green:wlan", .gpio = 203, },
+ { .name = "soc:green:phone2", .gpio = 204, },
+ { .name = "soc:green:phone1", .gpio = 205, },
+ { .name = "soc:green:line", .gpio = 206, },
+ { .name = "soc:green:online", .gpio = 207, },
+};
+
+
+static struct physmap_flash_data gigasx76x_flash_data = {
+ .nr_parts = ARRAY_SIZE(gigasx76x_partitions),
+ .parts = gigasx76x_partitions,
+};
+
+static struct ltq_pci_data ltq_pci_data = {
+ .clock = PCI_CLOCK_INT,
+ .gpio = PCI_GNT1 | PCI_REQ1,
+ .irq = {
+ [14] = INT_NUM_IM0_IRL0 + 22,
+ },
+};
+
+static struct ltq_eth_data ltq_eth_data = {
+ .mii_mode = PHY_INTERFACE_MODE_MII,
+};
+
+static void __init
+gigasx76x_init(void)
+{
+#define GIGASX76X_USB 29
+
+ ltq_register_gpio_stp();
+ ltq_register_nor(&gigasx76x_flash_data);
+ ltq_register_pci(<q_pci_data);
+ ltq_register_etop(<q_eth_data);
+ xway_register_dwc(GIGASX76X_USB);
+ ltq_register_tapi();
+ ltq_register_madwifi_eep();
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(gigasx76x_leds_gpio), gigasx76x_leds_gpio);
+}
+
+MIPS_MACHINE(LANTIQ_MACH_GIGASX76X,
+ "GIGASX76X",
+ "GIGASX76X - Gigaset SX761,SX762,SX763",
+ gigasx76x_init);
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/input.h>
+#include <linux/phy.h>
+#include <linux/spi/spi.h>
+
+#include <lantiq_soc.h>
+#include <irq.h>
+
+#include "../machtypes.h"
+#include "devices.h"
+
+static struct ltq_pci_data ltq_pci_data = {
+ .clock = PCI_CLOCK_INT,
+ .gpio = PCI_GNT1 | PCI_REQ1,
+ .irq = {
+ [14] = INT_NUM_IM0_IRL0 + 22,
+ },
+};
+
+static struct ltq_eth_data ltq_eth_data = {
+ .mii_mode = PHY_INTERFACE_MODE_MII,
+};
+
+struct spi_board_info spi_info = {
+ .bus_num = 0,
+ .chip_select = 3,
+ .max_speed_hz = 25000000,
+ .modalias = "mx25l12805d",
+};
+
+struct ltq_spi_platform_data ltq_spi_data = {
+ .num_chipselect = 4,
+};
+
+static void __init dgn3500_init(void)
+{
+ ltq_register_pci(<q_pci_data);
+ ltq_register_etop(<q_eth_data);
+ ltq_register_spi(<q_spi_data, &spi_info, 1);
+}
+
+MIPS_MACHINE(LANTIQ_MACH_DGN3500B,
+ "DGN3500B",
+ "Netgear DGN3500B",
+ dgn3500_init);
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include <linux/gpio_buttons.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/input.h>
+
+#include <lantiq_soc.h>
+#include <irq.h>
+
+#include "../machtypes.h"
+#include "../dev-leds-gpio.h"
+#include "../dev-gpio-buttons.h"
+#include "devices.h"
+#include "dev-dwc_otg.h"
+
+static struct mtd_partition wbmr_partitions[] =
+{
+ {
+ .name = "uboot",
+ .offset = 0x0,
+ .size = 0x40000,
+ },
+ {
+ .name = "uboot-env",
+ .offset = 0x40000,
+ .size = 0x20000,
+ },
+ {
+ .name = "linux",
+ .offset = 0x60000,
+ .size = 0x1f20000,
+ },
+ {
+ .name = "calibration",
+ .offset = 0x1fe0000,
+ .size = 0x20000,
+ },
+};
+
+static struct physmap_flash_data wbmr_flash_data = {
+ .nr_parts = ARRAY_SIZE(wbmr_partitions),
+ .parts = wbmr_partitions,
+};
+
+static struct gpio_led
+wbmr_leds_gpio[] __initdata = {
+ { .name = "soc:blue:movie", .gpio = 20, .active_low = 1, },
+ { .name = "soc:red:internet", .gpio = 18, .active_low = 1, },
+ { .name = "soc:green:internet", .gpio = 17, .active_low = 1, },
+ { .name = "soc:green:adsl", .gpio = 16, .active_low = 1, },
+ { .name = "soc:green:wlan", .gpio = 15, .active_low = 1, },
+ { .name = "soc:red:security", .gpio = 14, .active_low = 1, },
+ { .name = "soc:green:power", .gpio = 1, .active_low = 1, },
+ { .name = "soc:red:power", .gpio = 5, .active_low = 1, },
+ { .name = "soc:green:usb", .gpio = 28, .active_low = 1, },
+};
+
+static struct gpio_keys_button
+wbmr_gpio_keys[] __initdata = {
+ {
+ .desc = "aoss",
+ .type = EV_KEY,
+ .code = BTN_0,
+ .debounce_interval = LTQ_KEYS_DEBOUNCE_INTERVAL,
+ .gpio = 0,
+ .active_low = 1,
+ },
+ {
+ .desc = "reset",
+ .type = EV_KEY,
+ .code = BTN_1,
+ .debounce_interval = LTQ_KEYS_DEBOUNCE_INTERVAL,
+ .gpio = 37,
+ .active_low = 1,
+ },
+};
+
+static struct ltq_pci_data ltq_pci_data = {
+ .clock = PCI_CLOCK_INT,
+ .gpio = PCI_GNT1 | PCI_REQ1,
+ .irq = {
+ [14] = INT_NUM_IM0_IRL0 + 22,
+ },
+};
+
+static struct ltq_eth_data ltq_eth_data = {
+ .mii_mode = PHY_INTERFACE_MODE_RGMII,
+};
+
+static void __init
+wbmr_init(void)
+{
+#define WMBR_BRN_MAC 0x1fd0024
+
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(wbmr_leds_gpio), wbmr_leds_gpio);
+ ltq_register_gpio_keys_polled(-1, LTQ_KEYS_POLL_INTERVAL, ARRAY_SIZE(wbmr_gpio_keys), wbmr_gpio_keys);
+ ltq_register_nor(&wbmr_flash_data);
+ ltq_register_pci(<q_pci_data);
+ memcpy_fromio(<q_eth_data.mac.sa_data,
+ (void *)KSEG1ADDR(LTQ_FLASH_START + WMBR_BRN_MAC), 6);
+ ltq_register_etop(<q_eth_data);
+ xway_register_dwc(36);
+}
+
+MIPS_MACHINE(LANTIQ_MACH_WBMR,
+ "WBMR",
+ "WBMR",
+ wbmr_init);
define KernelPackage/usb-dwc-otg
TITLE:=Synopsis DWC_OTG support
SUBMENU:=$(USB_MENU)
- DEPENDS+=@TARGET_lantiq_danube +kmod-usb-core
+ DEPENDS+=@(TARGET_lantiq_danube||TARGET_lantiq_ar9||TARGET_lantiq_vr9) +kmod-usb-core
KCONFIG:=CONFIG_DWC_OTG \
CONFIG_DWC_OTG_DEBUG=n \
CONFIG_DWC_OTG_LANTIQ=y \
define KernelPackage/i2c-falcon-lantiq
TITLE:=Falcon I2C controller
$(call i2c_defaults,$(I2C_FALCON_MODULES),52)
- DEPENDS:=kmod-i2c-core @TARGET_lantiq
+ DEPENDS:=kmod-i2c-core @(TARGET_lantiq_falcon||TARGET_lantiq_falcon_stable)
endef
define KernelPackage/i2c-falcon-lantiq/description
+++ /dev/null
---- a/arch/mips/lantiq/xway/gpio_ebu.c
-+++ b/arch/mips/lantiq/xway/gpio_ebu.c
-@@ -63,7 +63,6 @@ static struct gpio_chip ltq_ebu_chip = {
- .set = ltq_ebu_set,
- .base = 72,
- .ngpio = 16,
-- .can_sleep = 1,
- .owner = THIS_MODULE,
- };
-
---- a/arch/mips/lantiq/xway/gpio_stp.c
-+++ b/arch/mips/lantiq/xway/gpio_stp.c
-@@ -72,7 +72,6 @@ static struct gpio_chip ltq_stp_chip = {
- .set = ltq_stp_set,
- .base = 48,
- .ngpio = 24,
-- .can_sleep = 1,
- .owner = THIS_MODULE,
- };
-
--- /dev/null
+From 91f8d0c8fbb9ea70bf78a291e312157177be8ee3 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sat, 20 Aug 2011 18:55:13 +0200
+Subject: [PATCH 01/24] MIPS: lantiq: fix early printk
+
+The code was using a 32bit write operation in the early_printk code. This
+resulted in 3 zero bytes also being written to the serial port. Change the
+memory access to 8bit.
+
+Signed-off-by: Thomas Langer <thomas.langer@lantiq.com>
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Cc: linux-mips@linux-mips.org
+---
+ .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 4 ++++
+ arch/mips/lantiq/early_printk.c | 14 ++++++++------
+ 2 files changed, 12 insertions(+), 6 deletions(-)
+
+diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
+index 8a3c6be..e6d1ca0 100644
+--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
+@@ -34,6 +34,10 @@
+ #define LTQ_ASC1_BASE_ADDR 0x1E100C00
+ #define LTQ_ASC_SIZE 0x400
+
++/* during early_printk no ioremap is possible
++ lets use KSEG1 instead */
++#define LTQ_EARLY_ASC KSEG1ADDR(LTQ_ASC1_BASE_ADDR)
++
+ /* RCU - reset control unit */
+ #define LTQ_RCU_BASE_ADDR 0x1F203000
+ #define LTQ_RCU_SIZE 0x1000
+diff --git a/arch/mips/lantiq/early_printk.c b/arch/mips/lantiq/early_printk.c
+index 972e05f..5089075 100644
+--- a/arch/mips/lantiq/early_printk.c
++++ b/arch/mips/lantiq/early_printk.c
+@@ -12,11 +12,13 @@
+ #include <lantiq.h>
+ #include <lantiq_soc.h>
+
+-/* no ioremap possible at this early stage, lets use KSEG1 instead */
+-#define LTQ_ASC_BASE KSEG1ADDR(LTQ_ASC1_BASE_ADDR)
+ #define ASC_BUF 1024
+-#define LTQ_ASC_FSTAT ((u32 *)(LTQ_ASC_BASE + 0x0048))
+-#define LTQ_ASC_TBUF ((u32 *)(LTQ_ASC_BASE + 0x0020))
++#define LTQ_ASC_FSTAT ((u32 *)(LTQ_EARLY_ASC + 0x0048))
++#ifdef __BIG_ENDIAN
++#define LTQ_ASC_TBUF ((u32 *)(LTQ_EARLY_ASC + 0x0020 + 3))
++#else
++#define LTQ_ASC_TBUF ((u32 *)(LTQ_EARLY_ASC + 0x0020))
++#endif
+ #define TXMASK 0x3F00
+ #define TXOFFSET 8
+
+@@ -27,7 +29,7 @@ void prom_putchar(char c)
+ local_irq_save(flags);
+ do { } while ((ltq_r32(LTQ_ASC_FSTAT) & TXMASK) >> TXOFFSET);
+ if (c == '\n')
+- ltq_w32('\r', LTQ_ASC_TBUF);
+- ltq_w32(c, LTQ_ASC_TBUF);
++ ltq_w8('\r', LTQ_ASC_TBUF);
++ ltq_w8(c, LTQ_ASC_TBUF);
+ local_irq_restore(flags);
+ }
+--
+1.7.5.4
+
--- /dev/null
+From b85d5204f2fe8c3b5e6172f7cc1741ad6e849334 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Fri, 12 Aug 2011 16:27:38 +0200
+Subject: [PATCH 02/24] MIPS: lantiq: fix cmdline parsing
+
+The code tested if the KSEG1 mapped address of argv was != 0. We need to use
+CPHYSADDR instead to make the conditional actually work.
+
+Signed-off-by: Thomas Langer <thomas.langer@lantiq.com>
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Cc: linux-mips@linux-mips.org
+---
+ arch/mips/lantiq/prom.c | 6 ++++--
+ 1 files changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c
+index 56ba007..5035c10 100644
+--- a/arch/mips/lantiq/prom.c
++++ b/arch/mips/lantiq/prom.c
+@@ -45,10 +45,12 @@ static void __init prom_init_cmdline(void)
+ char **argv = (char **) KSEG1ADDR(fw_arg1);
+ int i;
+
++ arcs_cmdline[0] = '\0';
++
+ for (i = 0; i < argc; i++) {
+- char *p = (char *) KSEG1ADDR(argv[i]);
++ char *p = (char *) KSEG1ADDR(argv[i]);
+
+- if (p && *p) {
++ if (CPHYSADDR(p) && *p) {
+ strlcat(arcs_cmdline, p, sizeof(arcs_cmdline));
+ strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline));
+ }
+--
+1.7.5.4
+
--- /dev/null
+From 14ea48a5f5702ddc97425cbe520600e187e14e4a Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Thu, 11 Aug 2011 13:58:39 +0200
+Subject: [PATCH 03/24] MIPS: lantiq: fix watchdogs timeout handling
+
+The enable function was using the global timeout variable for local operations.
+This resulted in the value of the global variable being corrupted, thus
+breaking the code.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Signed-off-by: Thomas Langer <thomas.langer@lantiq.com>
+Cc: linux-watchdog@vger.kernel.org
+Cc: linux-mips@linux-mips.org
+---
+ drivers/watchdog/lantiq_wdt.c | 8 ++++----
+ 1 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c
+index 7d82ada..102aed0 100644
+--- a/drivers/watchdog/lantiq_wdt.c
++++ b/drivers/watchdog/lantiq_wdt.c
+@@ -51,16 +51,16 @@ static int ltq_wdt_ok_to_close;
+ static void
+ ltq_wdt_enable(void)
+ {
+- ltq_wdt_timeout = ltq_wdt_timeout *
++ unsigned long int timeout = ltq_wdt_timeout *
+ (ltq_io_region_clk_rate / LTQ_WDT_DIVIDER) + 0x1000;
+- if (ltq_wdt_timeout > LTQ_MAX_TIMEOUT)
+- ltq_wdt_timeout = LTQ_MAX_TIMEOUT;
++ if (timeout > LTQ_MAX_TIMEOUT)
++ timeout = LTQ_MAX_TIMEOUT;
+
+ /* write the first password magic */
+ ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR);
+ /* write the second magic plus the configuration and new timeout */
+ ltq_w32(LTQ_WDT_SR_EN | LTQ_WDT_SR_PWD | LTQ_WDT_SR_CLKDIV |
+- LTQ_WDT_PW2 | ltq_wdt_timeout, ltq_wdt_membase + LTQ_WDT_CR);
++ LTQ_WDT_PW2 | timeout, ltq_wdt_membase + LTQ_WDT_CR);
+ }
+
+ static void
+--
+1.7.5.4
+
--- /dev/null
+From d90739a8962b541969b4c5f7ef1df8fec9c7f153 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Wed, 10 Aug 2011 14:57:04 +0200
+Subject: [PATCH 04/24] MIPS: lantiq: reorganize xway code
+
+Inside the folder arch/mips/lantiq/xway, there were alot of small files with
+lots of duplicated code. This patch adds a wrapper function for inserting and
+requesting resources and unifies the small files into one bigger file.
+
+This patch makes the xway code consistent with the falcon support added later
+in this series.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Signed-off-by: Thomas Langer <thomas.langer@lantiq.com>
+Cc: linux-mips@linux-mips.org
+---
+ arch/mips/include/asm/mach-lantiq/lantiq.h | 14 +---
+ .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 14 ++++
+ arch/mips/lantiq/clk.c | 25 +------
+ arch/mips/lantiq/devices.c | 30 ++------
+ arch/mips/lantiq/devices.h | 4 +
+ arch/mips/lantiq/prom.c | 50 +++++++++++--
+ arch/mips/lantiq/prom.h | 4 +
+ arch/mips/lantiq/xway/Makefile | 6 +-
+ arch/mips/lantiq/xway/devices.c | 42 ++---------
+ arch/mips/lantiq/xway/dma.c | 21 ++----
+ arch/mips/lantiq/xway/ebu.c | 53 --------------
+ arch/mips/lantiq/xway/pmu.c | 70 ------------------
+ arch/mips/lantiq/xway/prom-ase.c | 9 +++
+ arch/mips/lantiq/xway/prom-xway.c | 10 +++
+ arch/mips/lantiq/xway/reset.c | 21 ++----
+ arch/mips/lantiq/xway/setup-ase.c | 19 -----
+ arch/mips/lantiq/xway/setup-xway.c | 20 -----
+ arch/mips/lantiq/xway/sysctrl.c | 77 ++++++++++++++++++++
+ drivers/watchdog/lantiq_wdt.c | 2 +-
+ 19 files changed, 197 insertions(+), 294 deletions(-)
+ delete mode 100644 arch/mips/lantiq/xway/ebu.c
+ delete mode 100644 arch/mips/lantiq/xway/pmu.c
+ delete mode 100644 arch/mips/lantiq/xway/setup-ase.c
+ delete mode 100644 arch/mips/lantiq/xway/setup-xway.c
+ create mode 100644 arch/mips/lantiq/xway/sysctrl.c
+
+diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h
+index ce2f029..66d7300 100644
+--- a/arch/mips/include/asm/mach-lantiq/lantiq.h
++++ b/arch/mips/include/asm/mach-lantiq/lantiq.h
+@@ -9,6 +9,7 @@
+ #define _LANTIQ_H__
+
+ #include <linux/irq.h>
++#include <linux/ioport.h>
+
+ /* generic reg access functions */
+ #define ltq_r32(reg) __raw_readl(reg)
+@@ -18,15 +19,6 @@
+ #define ltq_r8(reg) __raw_readb(reg)
+ #define ltq_w8(val, reg) __raw_writeb(val, reg)
+
+-/* register access macros for EBU and CGU */
+-#define ltq_ebu_w32(x, y) ltq_w32((x), ltq_ebu_membase + (y))
+-#define ltq_ebu_r32(x) ltq_r32(ltq_ebu_membase + (x))
+-#define ltq_cgu_w32(x, y) ltq_w32((x), ltq_cgu_membase + (y))
+-#define ltq_cgu_r32(x) ltq_r32(ltq_cgu_membase + (x))
+-
+-extern __iomem void *ltq_ebu_membase;
+-extern __iomem void *ltq_cgu_membase;
+-
+ extern unsigned int ltq_get_cpu_ver(void);
+ extern unsigned int ltq_get_soc_type(void);
+
+@@ -51,7 +43,9 @@ extern void ltq_enable_irq(struct irq_data *data);
+
+ /* find out what caused the last cpu reset */
+ extern int ltq_reset_cause(void);
+-#define LTQ_RST_CAUSE_WDTRST 0x20
++
++/* helper for requesting and remapping resources */
++extern void __iomem *ltq_remap_resource(struct resource *res);
+
+ #define IOPORT_RESOURCE_START 0x10000000
+ #define IOPORT_RESOURCE_END 0xffffffff
+diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
+index e6d1ca0..da8ff95 100644
+--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
+@@ -65,6 +65,8 @@
+ #define LTQ_CGU_BASE_ADDR 0x1F103000
+ #define LTQ_CGU_SIZE 0x1000
+
++#define CGU_EPHY 0x10
++
+ /* ICU - interrupt control unit */
+ #define LTQ_ICU_BASE_ADDR 0x1F880200
+ #define LTQ_ICU_SIZE 0x100
+@@ -101,6 +103,8 @@
+ #define LTQ_WDT_BASE_ADDR 0x1F8803F0
+ #define LTQ_WDT_SIZE 0x10
+
++#define LTQ_RST_CAUSE_WDTRST 0x20
++
+ /* STP - serial to parallel conversion unit */
+ #define LTQ_STP_BASE_ADDR 0x1E100BB0
+ #define LTQ_STP_SIZE 0x40
+@@ -125,11 +129,21 @@
+ #define LTQ_MPS_BASE_ADDR (KSEG1 + 0x1F107000)
+ #define LTQ_MPS_CHIPID ((u32 *)(LTQ_MPS_BASE_ADDR + 0x0344))
+
++/* register access macros for EBU and CGU */
++#define ltq_ebu_w32(x, y) ltq_w32((x), ltq_ebu_membase + (y))
++#define ltq_ebu_r32(x) ltq_r32(ltq_ebu_membase + (x))
++#define ltq_cgu_w32(x, y) ltq_w32((x), ltq_cgu_membase + (y))
++#define ltq_cgu_r32(x) ltq_r32(ltq_cgu_membase + (x))
++
++extern __iomem void *ltq_ebu_membase;
++extern __iomem void *ltq_cgu_membase;
++
+ /* request a non-gpio and set the PIO config */
+ extern int ltq_gpio_request(unsigned int pin, unsigned int alt0,
+ unsigned int alt1, unsigned int dir, const char *name);
+ extern void ltq_pmu_enable(unsigned int module);
+ extern void ltq_pmu_disable(unsigned int module);
++extern void ltq_cgu_enable(unsigned int clk);
+
+ static inline int ltq_is_ar9(void)
+ {
+diff --git a/arch/mips/lantiq/clk.c b/arch/mips/lantiq/clk.c
+index 7e9c0ff..4254f08 100644
+--- a/arch/mips/lantiq/clk.c
++++ b/arch/mips/lantiq/clk.c
+@@ -22,6 +22,7 @@
+ #include <lantiq_soc.h>
+
+ #include "clk.h"
++#include "prom.h"
+
+ struct clk {
+ const char *name;
+@@ -46,16 +47,6 @@ static struct clk cpu_clk_generic[] = {
+ },
+ };
+
+-static struct resource ltq_cgu_resource = {
+- .name = "cgu",
+- .start = LTQ_CGU_BASE_ADDR,
+- .end = LTQ_CGU_BASE_ADDR + LTQ_CGU_SIZE - 1,
+- .flags = IORESOURCE_MEM,
+-};
+-
+-/* remapped clock register range */
+-void __iomem *ltq_cgu_membase;
+-
+ void clk_init(void)
+ {
+ cpu_clk = cpu_clk_generic;
+@@ -133,21 +124,11 @@ void __init plat_time_init(void)
+ {
+ struct clk *clk;
+
+- if (insert_resource(&iomem_resource, <q_cgu_resource) < 0)
+- panic("Failed to insert cgu memory\n");
+-
+- if (request_mem_region(ltq_cgu_resource.start,
+- resource_size(<q_cgu_resource), "cgu") < 0)
+- panic("Failed to request cgu memory\n");
++ ltq_soc_init();
+
+- ltq_cgu_membase = ioremap_nocache(ltq_cgu_resource.start,
+- resource_size(<q_cgu_resource));
+- if (!ltq_cgu_membase) {
+- pr_err("Failed to remap cgu memory\n");
+- unreachable();
+- }
+ clk = clk_get(0, "cpu");
+ mips_hpt_frequency = clk_get_rate(clk) / ltq_get_counter_resolution();
+ write_c0_compare(read_c0_count());
++ pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000);
+ clk_put(clk);
+ }
+diff --git a/arch/mips/lantiq/devices.c b/arch/mips/lantiq/devices.c
+index 44a3677..81c7aab 100644
+--- a/arch/mips/lantiq/devices.c
++++ b/arch/mips/lantiq/devices.c
+@@ -27,12 +27,8 @@
+ #include "devices.h"
+
+ /* nor flash */
+-static struct resource ltq_nor_resource = {
+- .name = "nor",
+- .start = LTQ_FLASH_START,
+- .end = LTQ_FLASH_START + LTQ_FLASH_MAX - 1,
+- .flags = IORESOURCE_MEM,
+-};
++static struct resource ltq_nor_resource =
++ MEM_RES("nor", LTQ_FLASH_START, LTQ_FLASH_MAX);
+
+ static struct platform_device ltq_nor = {
+ .name = "ltq_nor",
+@@ -47,12 +43,8 @@ void __init ltq_register_nor(struct physmap_flash_data *data)
+ }
+
+ /* watchdog */
+-static struct resource ltq_wdt_resource = {
+- .name = "watchdog",
+- .start = LTQ_WDT_BASE_ADDR,
+- .end = LTQ_WDT_BASE_ADDR + LTQ_WDT_SIZE - 1,
+- .flags = IORESOURCE_MEM,
+-};
++static struct resource ltq_wdt_resource =
++ MEM_RES("watchdog", LTQ_WDT_BASE_ADDR, LTQ_WDT_SIZE);
+
+ void __init ltq_register_wdt(void)
+ {
+@@ -61,24 +53,14 @@ void __init ltq_register_wdt(void)
+
+ /* asc ports */
+ static struct resource ltq_asc0_resources[] = {
+- {
+- .name = "asc0",
+- .start = LTQ_ASC0_BASE_ADDR,
+- .end = LTQ_ASC0_BASE_ADDR + LTQ_ASC_SIZE - 1,
+- .flags = IORESOURCE_MEM,
+- },
++ MEM_RES("asc0", LTQ_ASC0_BASE_ADDR, LTQ_ASC_SIZE),
+ IRQ_RES(tx, LTQ_ASC_TIR(0)),
+ IRQ_RES(rx, LTQ_ASC_RIR(0)),
+ IRQ_RES(err, LTQ_ASC_EIR(0)),
+ };
+
+ static struct resource ltq_asc1_resources[] = {
+- {
+- .name = "asc1",
+- .start = LTQ_ASC1_BASE_ADDR,
+- .end = LTQ_ASC1_BASE_ADDR + LTQ_ASC_SIZE - 1,
+- .flags = IORESOURCE_MEM,
+- },
++ MEM_RES("asc1", LTQ_ASC1_BASE_ADDR, LTQ_ASC_SIZE),
+ IRQ_RES(tx, LTQ_ASC_TIR(1)),
+ IRQ_RES(rx, LTQ_ASC_RIR(1)),
+ IRQ_RES(err, LTQ_ASC_EIR(1)),
+diff --git a/arch/mips/lantiq/devices.h b/arch/mips/lantiq/devices.h
+index 2947bb1..a03c23f 100644
+--- a/arch/mips/lantiq/devices.h
++++ b/arch/mips/lantiq/devices.h
+@@ -14,6 +14,10 @@
+
+ #define IRQ_RES(resname, irq) \
+ {.name = #resname, .start = (irq), .flags = IORESOURCE_IRQ}
++#define MEM_RES(resname, adr_start, adr_size) \
++ { .name = resname, .flags = IORESOURCE_MEM, \
++ .start = ((adr_start) & ~KSEG1), \
++ .end = ((adr_start + adr_size - 1) & ~KSEG1) }
+
+ extern void ltq_register_nor(struct physmap_flash_data *data);
+ extern void ltq_register_wdt(void);
+diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c
+index 5035c10..fead2cc 100644
+--- a/arch/mips/lantiq/prom.c
++++ b/arch/mips/lantiq/prom.c
+@@ -16,6 +16,10 @@
+ #include "prom.h"
+ #include "clk.h"
+
++/* access to the ebu needs to be locked between different drivers */
++DEFINE_SPINLOCK(ebu_lock);
++EXPORT_SYMBOL_GPL(ebu_lock);
++
+ static struct ltq_soc_info soc_info;
+
+ unsigned int ltq_get_cpu_ver(void)
+@@ -57,16 +61,50 @@ static void __init prom_init_cmdline(void)
+ }
+ }
+
+-void __init prom_init(void)
++void __iomem *ltq_remap_resource(struct resource *res)
+ {
+- struct clk *clk;
++ __iomem void *ret = NULL;
++ struct resource *lookup = lookup_resource(&iomem_resource, res->start);
++
++ if (lookup && strcmp(lookup->name, res->name)) {
++ panic("conflicting memory range %s\n", res->name);
++ return NULL;
++ }
++ if (!lookup) {
++ if (insert_resource(&iomem_resource, res) < 0) {
++ panic("Failed to insert %s memory\n", res->name);
++ return NULL;
++ }
++ }
++ if (request_mem_region(res->start,
++ resource_size(res), res->name) < 0) {
++ panic("Failed to request %s memory\n", res->name);
++ goto err_res;
++ }
+
++ ret = ioremap_nocache(res->start, resource_size(res));
++ if (!ret)
++ goto err_mem;
++
++ pr_debug("remap: 0x%08X-0x%08X : \"%s\"\n",
++ res->start, res->end, res->name);
++ return ret;
++
++err_mem:
++ panic("Failed to remap %s memory\n", res->name);
++ release_mem_region(res->start, resource_size(res));
++
++err_res:
++ release_resource(res);
++ return NULL;
++}
++
++void __init prom_init(void)
++{
+ ltq_soc_detect(&soc_info);
+ clk_init();
+- clk = clk_get(0, "cpu");
+- snprintf(soc_info.sys_type, LTQ_SYS_TYPE_LEN - 1, "%s rev1.%d",
+- soc_info.name, soc_info.rev);
+- clk_put(clk);
++ snprintf(soc_info.sys_type, LTQ_SYS_TYPE_LEN - 1, "%s rev %s",
++ soc_info.name, soc_info.rev_type);
+ soc_info.sys_type[LTQ_SYS_TYPE_LEN - 1] = '\0';
+ pr_info("SoC: %s\n", soc_info.sys_type);
+ prom_init_cmdline();
+diff --git a/arch/mips/lantiq/prom.h b/arch/mips/lantiq/prom.h
+index b4229d9..51dba1b 100644
+--- a/arch/mips/lantiq/prom.h
++++ b/arch/mips/lantiq/prom.h
+@@ -9,17 +9,21 @@
+ #ifndef _LTQ_PROM_H__
+ #define _LTQ_PROM_H__
+
++#define LTQ_SYS_REV_LEN 0x10
+ #define LTQ_SYS_TYPE_LEN 0x100
+
+ struct ltq_soc_info {
+ unsigned char *name;
+ unsigned int rev;
++ unsigned char rev_type[LTQ_SYS_REV_LEN];
++ unsigned int srev;
+ unsigned int partnum;
+ unsigned int type;
+ unsigned char sys_type[LTQ_SYS_TYPE_LEN];
+ };
+
+ extern void ltq_soc_detect(struct ltq_soc_info *i);
++extern void ltq_soc_init(void);
+ extern void ltq_soc_setup(void);
+
+ #endif
+diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile
+index c517f2e..6678402 100644
+--- a/arch/mips/lantiq/xway/Makefile
++++ b/arch/mips/lantiq/xway/Makefile
+@@ -1,7 +1,7 @@
+-obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o
++obj-y := sysctrl.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o
+
+-obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o setup-xway.o
+-obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o setup-ase.o
++obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o
++obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o
+
+ obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o
+ obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o
+diff --git a/arch/mips/lantiq/xway/devices.c b/arch/mips/lantiq/xway/devices.c
+index d0e32ab..9bacaa8 100644
+--- a/arch/mips/lantiq/xway/devices.c
++++ b/arch/mips/lantiq/xway/devices.c
+@@ -31,22 +31,9 @@
+
+ /* gpio */
+ static struct resource ltq_gpio_resource[] = {
+- {
+- .name = "gpio0",
+- .start = LTQ_GPIO0_BASE_ADDR,
+- .end = LTQ_GPIO0_BASE_ADDR + LTQ_GPIO_SIZE - 1,
+- .flags = IORESOURCE_MEM,
+- }, {
+- .name = "gpio1",
+- .start = LTQ_GPIO1_BASE_ADDR,
+- .end = LTQ_GPIO1_BASE_ADDR + LTQ_GPIO_SIZE - 1,
+- .flags = IORESOURCE_MEM,
+- }, {
+- .name = "gpio2",
+- .start = LTQ_GPIO2_BASE_ADDR,
+- .end = LTQ_GPIO2_BASE_ADDR + LTQ_GPIO_SIZE - 1,
+- .flags = IORESOURCE_MEM,
+- }
++ MEM_RES("gpio0", LTQ_GPIO0_BASE_ADDR, LTQ_GPIO_SIZE),
++ MEM_RES("gpio1", LTQ_GPIO1_BASE_ADDR, LTQ_GPIO_SIZE),
++ MEM_RES("gpio2", LTQ_GPIO2_BASE_ADDR, LTQ_GPIO_SIZE),
+ };
+
+ void __init ltq_register_gpio(void)
+@@ -64,12 +51,8 @@ void __init ltq_register_gpio(void)
+ }
+
+ /* serial to parallel conversion */
+-static struct resource ltq_stp_resource = {
+- .name = "stp",
+- .start = LTQ_STP_BASE_ADDR,
+- .end = LTQ_STP_BASE_ADDR + LTQ_STP_SIZE - 1,
+- .flags = IORESOURCE_MEM,
+-};
++static struct resource ltq_stp_resource =
++ MEM_RES("stp", LTQ_STP_BASE_ADDR, LTQ_STP_SIZE);
+
+ void __init ltq_register_gpio_stp(void)
+ {
+@@ -78,12 +61,7 @@ void __init ltq_register_gpio_stp(void)
+
+ /* asc ports - amazon se has its own serial mapping */
+ static struct resource ltq_ase_asc_resources[] = {
+- {
+- .name = "asc0",
+- .start = LTQ_ASC1_BASE_ADDR,
+- .end = LTQ_ASC1_BASE_ADDR + LTQ_ASC_SIZE - 1,
+- .flags = IORESOURCE_MEM,
+- },
++ MEM_RES("asc0", LTQ_ASC1_BASE_ADDR, LTQ_ASC_SIZE),
+ IRQ_RES(tx, LTQ_ASC_ASE_TIR),
+ IRQ_RES(rx, LTQ_ASC_ASE_RIR),
+ IRQ_RES(err, LTQ_ASC_ASE_EIR),
+@@ -96,12 +74,8 @@ void __init ltq_register_ase_asc(void)
+ }
+
+ /* ethernet */
+-static struct resource ltq_etop_resources = {
+- .name = "etop",
+- .start = LTQ_ETOP_BASE_ADDR,
+- .end = LTQ_ETOP_BASE_ADDR + LTQ_ETOP_SIZE - 1,
+- .flags = IORESOURCE_MEM,
+-};
++static struct resource ltq_etop_resources =
++ MEM_RES("etop", LTQ_ETOP_BASE_ADDR, LTQ_ETOP_SIZE);
+
+ static struct platform_device ltq_etop = {
+ .name = "ltq_etop",
+diff --git a/arch/mips/lantiq/xway/dma.c b/arch/mips/lantiq/xway/dma.c
+index 4278a45..af35e62 100644
+--- a/arch/mips/lantiq/xway/dma.c
++++ b/arch/mips/lantiq/xway/dma.c
+@@ -23,6 +23,8 @@
+ #include <lantiq_soc.h>
+ #include <xway_dma.h>
+
++#include "../devices.h"
++
+ #define LTQ_DMA_CTRL 0x10
+ #define LTQ_DMA_CPOLL 0x14
+ #define LTQ_DMA_CS 0x18
+@@ -54,12 +56,8 @@
+ #define ltq_dma_w32_mask(x, y, z) ltq_w32_mask(x, y, \
+ ltq_dma_membase + (z))
+
+-static struct resource ltq_dma_resource = {
+- .name = "dma",
+- .start = LTQ_DMA_BASE_ADDR,
+- .end = LTQ_DMA_BASE_ADDR + LTQ_DMA_SIZE - 1,
+- .flags = IORESOURCE_MEM,
+-};
++static struct resource ltq_dma_resource =
++ MEM_RES("dma", LTQ_DMA_BASE_ADDR, LTQ_DMA_SIZE);
+
+ static void __iomem *ltq_dma_membase;
+
+@@ -219,17 +217,8 @@ ltq_dma_init(void)
+ {
+ int i;
+
+- /* insert and request the memory region */
+- if (insert_resource(&iomem_resource, <q_dma_resource) < 0)
+- panic("Failed to insert dma memory\n");
+-
+- if (request_mem_region(ltq_dma_resource.start,
+- resource_size(<q_dma_resource), "dma") < 0)
+- panic("Failed to request dma memory\n");
+-
+ /* remap dma register range */
+- ltq_dma_membase = ioremap_nocache(ltq_dma_resource.start,
+- resource_size(<q_dma_resource));
++ ltq_dma_membase = ltq_remap_resource(<q_dma_resource);
+ if (!ltq_dma_membase)
+ panic("Failed to remap dma memory\n");
+
+diff --git a/arch/mips/lantiq/xway/ebu.c b/arch/mips/lantiq/xway/ebu.c
+deleted file mode 100644
+index 66eb52f..0000000
+--- a/arch/mips/lantiq/xway/ebu.c
++++ /dev/null
+@@ -1,53 +0,0 @@
+-/*
+- * This program is free software; you can redistribute it and/or modify it
+- * under the terms of the GNU General Public License version 2 as published
+- * by the Free Software Foundation.
+- *
+- * EBU - the external bus unit attaches PCI, NOR and NAND
+- *
+- * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/version.h>
+-#include <linux/ioport.h>
+-
+-#include <lantiq_soc.h>
+-
+-/* all access to the ebu must be locked */
+-DEFINE_SPINLOCK(ebu_lock);
+-EXPORT_SYMBOL_GPL(ebu_lock);
+-
+-static struct resource ltq_ebu_resource = {
+- .name = "ebu",
+- .start = LTQ_EBU_BASE_ADDR,
+- .end = LTQ_EBU_BASE_ADDR + LTQ_EBU_SIZE - 1,
+- .flags = IORESOURCE_MEM,
+-};
+-
+-/* remapped base addr of the clock unit and external bus unit */
+-void __iomem *ltq_ebu_membase;
+-
+-static int __init lantiq_ebu_init(void)
+-{
+- /* insert and request the memory region */
+- if (insert_resource(&iomem_resource, <q_ebu_resource) < 0)
+- panic("Failed to insert ebu memory\n");
+-
+- if (request_mem_region(ltq_ebu_resource.start,
+- resource_size(<q_ebu_resource), "ebu") < 0)
+- panic("Failed to request ebu memory\n");
+-
+- /* remap ebu register range */
+- ltq_ebu_membase = ioremap_nocache(ltq_ebu_resource.start,
+- resource_size(<q_ebu_resource));
+- if (!ltq_ebu_membase)
+- panic("Failed to remap ebu memory\n");
+-
+- /* make sure to unprotect the memory region where flash is located */
+- ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0);
+- return 0;
+-}
+-
+-postcore_initcall(lantiq_ebu_init);
+diff --git a/arch/mips/lantiq/xway/pmu.c b/arch/mips/lantiq/xway/pmu.c
+deleted file mode 100644
+index 9d69f01e..0000000
+--- a/arch/mips/lantiq/xway/pmu.c
++++ /dev/null
+@@ -1,70 +0,0 @@
+-/*
+- * This program is free software; you can redistribute it and/or modify it
+- * under the terms of the GNU General Public License version 2 as published
+- * by the Free Software Foundation.
+- *
+- * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/version.h>
+-#include <linux/ioport.h>
+-
+-#include <lantiq_soc.h>
+-
+-/* PMU - the power management unit allows us to turn part of the core
+- * on and off
+- */
+-
+-/* the enable / disable registers */
+-#define LTQ_PMU_PWDCR 0x1C
+-#define LTQ_PMU_PWDSR 0x20
+-
+-#define ltq_pmu_w32(x, y) ltq_w32((x), ltq_pmu_membase + (y))
+-#define ltq_pmu_r32(x) ltq_r32(ltq_pmu_membase + (x))
+-
+-static struct resource ltq_pmu_resource = {
+- .name = "pmu",
+- .start = LTQ_PMU_BASE_ADDR,
+- .end = LTQ_PMU_BASE_ADDR + LTQ_PMU_SIZE - 1,
+- .flags = IORESOURCE_MEM,
+-};
+-
+-static void __iomem *ltq_pmu_membase;
+-
+-void ltq_pmu_enable(unsigned int module)
+-{
+- int err = 1000000;
+-
+- ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) & ~module, LTQ_PMU_PWDCR);
+- do {} while (--err && (ltq_pmu_r32(LTQ_PMU_PWDSR) & module));
+-
+- if (!err)
+- panic("activating PMU module failed!\n");
+-}
+-EXPORT_SYMBOL(ltq_pmu_enable);
+-
+-void ltq_pmu_disable(unsigned int module)
+-{
+- ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) | module, LTQ_PMU_PWDCR);
+-}
+-EXPORT_SYMBOL(ltq_pmu_disable);
+-
+-int __init ltq_pmu_init(void)
+-{
+- if (insert_resource(&iomem_resource, <q_pmu_resource) < 0)
+- panic("Failed to insert pmu memory\n");
+-
+- if (request_mem_region(ltq_pmu_resource.start,
+- resource_size(<q_pmu_resource), "pmu") < 0)
+- panic("Failed to request pmu memory\n");
+-
+- ltq_pmu_membase = ioremap_nocache(ltq_pmu_resource.start,
+- resource_size(<q_pmu_resource));
+- if (!ltq_pmu_membase)
+- panic("Failed to remap pmu memory\n");
+- return 0;
+-}
+-
+-core_initcall(ltq_pmu_init);
+diff --git a/arch/mips/lantiq/xway/prom-ase.c b/arch/mips/lantiq/xway/prom-ase.c
+index abe49f4..aaccdcb 100644
+--- a/arch/mips/lantiq/xway/prom-ase.c
++++ b/arch/mips/lantiq/xway/prom-ase.c
+@@ -13,6 +13,7 @@
+
+ #include <lantiq_soc.h>
+
++#include "devices.h"
+ #include "../prom.h"
+
+ #define SOC_AMAZON_SE "Amazon_SE"
+@@ -26,6 +27,7 @@ void __init ltq_soc_detect(struct ltq_soc_info *i)
+ {
+ i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT;
+ i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT;
++ sprintf(i->rev_type, "1.%d", i->rev);
+ switch (i->partnum) {
+ case SOC_ID_AMAZON_SE:
+ i->name = SOC_AMAZON_SE;
+@@ -37,3 +39,10 @@ void __init ltq_soc_detect(struct ltq_soc_info *i)
+ break;
+ }
+ }
++
++void __init ltq_soc_setup(void)
++{
++ ltq_register_ase_asc();
++ ltq_register_gpio();
++ ltq_register_wdt();
++}
+diff --git a/arch/mips/lantiq/xway/prom-xway.c b/arch/mips/lantiq/xway/prom-xway.c
+index 1686692a..f3d1228 100644
+--- a/arch/mips/lantiq/xway/prom-xway.c
++++ b/arch/mips/lantiq/xway/prom-xway.c
+@@ -13,6 +13,7 @@
+
+ #include <lantiq_soc.h>
+
++#include "devices.h"
+ #include "../prom.h"
+
+ #define SOC_DANUBE "Danube"
+@@ -28,6 +29,7 @@ void __init ltq_soc_detect(struct ltq_soc_info *i)
+ {
+ i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT;
+ i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT;
++ sprintf(i->rev_type, "1.%d", i->rev);
+ switch (i->partnum) {
+ case SOC_ID_DANUBE1:
+ case SOC_ID_DANUBE2:
+@@ -52,3 +54,11 @@ void __init ltq_soc_detect(struct ltq_soc_info *i)
+ break;
+ }
+ }
++
++void __init ltq_soc_setup(void)
++{
++ ltq_register_asc(0);
++ ltq_register_asc(1);
++ ltq_register_gpio();
++ ltq_register_wdt();
++}
+diff --git a/arch/mips/lantiq/xway/reset.c b/arch/mips/lantiq/xway/reset.c
+index a1be36d..e701a48 100644
+--- a/arch/mips/lantiq/xway/reset.c
++++ b/arch/mips/lantiq/xway/reset.c
+@@ -15,6 +15,8 @@
+
+ #include <lantiq_soc.h>
+
++#include "../devices.h"
++
+ #define ltq_rcu_w32(x, y) ltq_w32((x), ltq_rcu_membase + (y))
+ #define ltq_rcu_r32(x) ltq_r32(ltq_rcu_membase + (x))
+
+@@ -25,12 +27,8 @@
+ #define LTQ_RCU_RST_STAT 0x0014
+ #define LTQ_RCU_STAT_SHIFT 26
+
+-static struct resource ltq_rcu_resource = {
+- .name = "rcu",
+- .start = LTQ_RCU_BASE_ADDR,
+- .end = LTQ_RCU_BASE_ADDR + LTQ_RCU_SIZE - 1,
+- .flags = IORESOURCE_MEM,
+-};
++static struct resource ltq_rcu_resource =
++ MEM_RES("rcu", LTQ_RCU_BASE_ADDR, LTQ_RCU_SIZE);
+
+ /* remapped base addr of the reset control unit */
+ static void __iomem *ltq_rcu_membase;
+@@ -67,17 +65,8 @@ static void ltq_machine_power_off(void)
+
+ static int __init mips_reboot_setup(void)
+ {
+- /* insert and request the memory region */
+- if (insert_resource(&iomem_resource, <q_rcu_resource) < 0)
+- panic("Failed to insert rcu memory\n");
+-
+- if (request_mem_region(ltq_rcu_resource.start,
+- resource_size(<q_rcu_resource), "rcu") < 0)
+- panic("Failed to request rcu memory\n");
+-
+ /* remap rcu register range */
+- ltq_rcu_membase = ioremap_nocache(ltq_rcu_resource.start,
+- resource_size(<q_rcu_resource));
++ ltq_rcu_membase = ltq_remap_resource(<q_rcu_resource);
+ if (!ltq_rcu_membase)
+ panic("Failed to remap rcu memory\n");
+
+diff --git a/arch/mips/lantiq/xway/setup-ase.c b/arch/mips/lantiq/xway/setup-ase.c
+deleted file mode 100644
+index f6f3267..0000000
+--- a/arch/mips/lantiq/xway/setup-ase.c
++++ /dev/null
+@@ -1,19 +0,0 @@
+-/*
+- * This program is free software; you can redistribute it and/or modify it
+- * under the terms of the GNU General Public License version 2 as published
+- * by the Free Software Foundation.
+- *
+- * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
+- */
+-
+-#include <lantiq_soc.h>
+-
+-#include "../prom.h"
+-#include "devices.h"
+-
+-void __init ltq_soc_setup(void)
+-{
+- ltq_register_ase_asc();
+- ltq_register_gpio();
+- ltq_register_wdt();
+-}
+diff --git a/arch/mips/lantiq/xway/setup-xway.c b/arch/mips/lantiq/xway/setup-xway.c
+deleted file mode 100644
+index c292f64..0000000
+--- a/arch/mips/lantiq/xway/setup-xway.c
++++ /dev/null
+@@ -1,20 +0,0 @@
+-/*
+- * This program is free software; you can redistribute it and/or modify it
+- * under the terms of the GNU General Public License version 2 as published
+- * by the Free Software Foundation.
+- *
+- * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
+- */
+-
+-#include <lantiq_soc.h>
+-
+-#include "../prom.h"
+-#include "devices.h"
+-
+-void __init ltq_soc_setup(void)
+-{
+- ltq_register_asc(0);
+- ltq_register_asc(1);
+- ltq_register_gpio();
+- ltq_register_wdt();
+-}
+diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c
+new file mode 100644
+index 0000000..a29944f
+--- /dev/null
++++ b/arch/mips/lantiq/xway/sysctrl.c
+@@ -0,0 +1,77 @@
++/*
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
++ */
++
++#include <linux/ioport.h>
++
++#include <lantiq_soc.h>
++
++#include "../devices.h"
++
++/* clock control register */
++#define LTQ_CGU_IFCCR 0x0018
++
++/* the enable / disable registers */
++#define LTQ_PMU_PWDCR 0x1C
++#define LTQ_PMU_PWDSR 0x20
++
++#define ltq_pmu_w32(x, y) ltq_w32((x), ltq_pmu_membase + (y))
++#define ltq_pmu_r32(x) ltq_r32(ltq_pmu_membase + (x))
++
++static struct resource ltq_cgu_resource =
++ MEM_RES("cgu", LTQ_CGU_BASE_ADDR, LTQ_CGU_SIZE);
++
++static struct resource ltq_pmu_resource =
++ MEM_RES("pmu", LTQ_PMU_BASE_ADDR, LTQ_PMU_SIZE);
++
++static struct resource ltq_ebu_resource =
++ MEM_RES("ebu", LTQ_EBU_BASE_ADDR, LTQ_EBU_SIZE);
++
++void __iomem *ltq_cgu_membase;
++void __iomem *ltq_ebu_membase;
++static void __iomem *ltq_pmu_membase;
++
++void ltq_cgu_enable(unsigned int clk)
++{
++ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | clk, LTQ_CGU_IFCCR);
++}
++
++void ltq_pmu_enable(unsigned int module)
++{
++ int err = 1000000;
++
++ ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) & ~module, LTQ_PMU_PWDCR);
++ do {} while (--err && (ltq_pmu_r32(LTQ_PMU_PWDSR) & module));
++
++ if (!err)
++ panic("activating PMU module failed!\n");
++}
++EXPORT_SYMBOL(ltq_pmu_enable);
++
++void ltq_pmu_disable(unsigned int module)
++{
++ ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) | module, LTQ_PMU_PWDCR);
++}
++EXPORT_SYMBOL(ltq_pmu_disable);
++
++void __init ltq_soc_init(void)
++{
++ ltq_pmu_membase = ltq_remap_resource(<q_pmu_resource);
++ if (!ltq_pmu_membase)
++ panic("Failed to remap pmu memory\n");
++
++ ltq_cgu_membase = ltq_remap_resource(<q_cgu_resource);
++ if (!ltq_cgu_membase)
++ panic("Failed to remap cgu memory\n");
++
++ ltq_ebu_membase = ltq_remap_resource(<q_ebu_resource);
++ if (!ltq_ebu_membase)
++ panic("Failed to remap ebu memory\n");
++
++ /* make sure to unprotect the memory region where flash is located */
++ ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0);
++}
+diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c
+index 102aed0..179bf98 100644
+--- a/drivers/watchdog/lantiq_wdt.c
++++ b/drivers/watchdog/lantiq_wdt.c
+@@ -16,7 +16,7 @@
+ #include <linux/clk.h>
+ #include <linux/io.h>
+
+-#include <lantiq.h>
++#include <lantiq_soc.h>
+
+ /* Section 3.4 of the datasheet
+ * The password sequence protects the WDT control register from unintended
+--
+1.7.5.4
+
--- /dev/null
+From d9355bb07878f9aa40856cc437c43cedc87662fc Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Thu, 11 Aug 2011 12:25:55 +0200
+Subject: [PATCH 05/24] MIPS: lantiq: make irq.c support the FALC-ON
+
+There are minor differences in how irqs work on xway and falcon socs.
+Xway needs 2 quirks that we need to disable for falcon to also work with
+this code.
+
+* EBU irq does not need to send a special ack to the EBU
+* The EIU does not exist
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Signed-off-by: Thomas Langer <thomas.langer@lantiq.com>
+Cc: linux-mips@linux-mips.org
+---
+ arch/mips/lantiq/irq.c | 24 +++++++++++++-----------
+ 1 files changed, 13 insertions(+), 11 deletions(-)
+
+diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c
+index f9737bb..17c057f 100644
+--- a/arch/mips/lantiq/irq.c
++++ b/arch/mips/lantiq/irq.c
+@@ -195,7 +195,7 @@ static void ltq_hw_irqdispatch(int module)
+ do_IRQ((int)irq + INT_NUM_IM0_IRL0 + (INT_NUM_IM_OFFSET * module));
+
+ /* if this is a EBU irq, we need to ack it or get a deadlock */
+- if ((irq == LTQ_ICU_EBU_IRQ) && (module == 0))
++ if ((irq == LTQ_ICU_EBU_IRQ) && (module == 0) && LTQ_EBU_PCC_ISTAT)
+ ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_ISTAT) | 0x10,
+ LTQ_EBU_PCC_ISTAT);
+ }
+@@ -260,17 +260,19 @@ void __init arch_init_irq(void)
+ if (!ltq_icu_membase)
+ panic("Failed to remap icu memory\n");
+
+- if (insert_resource(&iomem_resource, <q_eiu_resource) < 0)
+- panic("Failed to insert eiu memory\n");
++ if (LTQ_EIU_BASE_ADDR) {
++ if (insert_resource(&iomem_resource, <q_eiu_resource) < 0)
++ panic("Failed to insert eiu memory\n");
+
+- if (request_mem_region(ltq_eiu_resource.start,
+- resource_size(<q_eiu_resource), "eiu") < 0)
+- panic("Failed to request eiu memory\n");
++ if (request_mem_region(ltq_eiu_resource.start,
++ resource_size(<q_eiu_resource), "eiu") < 0)
++ panic("Failed to request eiu memory\n");
+
+- ltq_eiu_membase = ioremap_nocache(ltq_eiu_resource.start,
++ ltq_eiu_membase = ioremap_nocache(ltq_eiu_resource.start,
+ resource_size(<q_eiu_resource));
+- if (!ltq_eiu_membase)
+- panic("Failed to remap eiu memory\n");
++ if (!ltq_eiu_membase)
++ panic("Failed to remap eiu memory\n");
++ }
+
+ /* make sure all irqs are turned off by default */
+ for (i = 0; i < 5; i++)
+@@ -296,8 +298,8 @@ void __init arch_init_irq(void)
+
+ for (i = INT_NUM_IRQ0;
+ i <= (INT_NUM_IRQ0 + (5 * INT_NUM_IM_OFFSET)); i++)
+- if ((i == LTQ_EIU_IR0) || (i == LTQ_EIU_IR1) ||
+- (i == LTQ_EIU_IR2))
++ if (((i == LTQ_EIU_IR0) || (i == LTQ_EIU_IR1) ||
++ (i == LTQ_EIU_IR2)) && LTQ_EIU_BASE_ADDR)
+ irq_set_chip_and_handler(i, <q_eiu_type,
+ handle_level_irq);
+ /* EIU3-5 only exist on ar9 and vr9 */
+--
+1.7.5.4
+
--- /dev/null
+From ff57bc17a9964d24708759c6d78a51e337563d5f Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Thu, 11 Aug 2011 14:33:04 +0200
+Subject: [PATCH 06/24] MIPS: lantiq: add basic support for FALC-ON
+
+Adds support for the FALC-ON SoC. This SoC is from the fiber to the home GPON
+series.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Signed-off-by: Thomas Langer <thomas.langer@lantiq.com>
+Cc: linux-mips@linux-mips.org
+---
+ .../include/asm/mach-lantiq/falcon/falcon_irq.h | 268 ++++++++++++++++++++
+ arch/mips/include/asm/mach-lantiq/falcon/irq.h | 18 ++
+ .../include/asm/mach-lantiq/falcon/lantiq_soc.h | 140 ++++++++++
+ arch/mips/include/asm/mach-lantiq/lantiq.h | 1 +
+ arch/mips/lantiq/Kconfig | 4 +
+ arch/mips/lantiq/Makefile | 1 +
+ arch/mips/lantiq/Platform | 1 +
+ arch/mips/lantiq/falcon/Makefile | 1 +
+ arch/mips/lantiq/falcon/clk.c | 44 ++++
+ arch/mips/lantiq/falcon/devices.c | 87 +++++++
+ arch/mips/lantiq/falcon/devices.h | 18 ++
+ arch/mips/lantiq/falcon/prom.c | 72 ++++++
+ arch/mips/lantiq/falcon/reset.c | 87 +++++++
+ arch/mips/lantiq/falcon/sysctrl.c | 181 +++++++++++++
+ 14 files changed, 923 insertions(+), 0 deletions(-)
+ create mode 100644 arch/mips/include/asm/mach-lantiq/falcon/falcon_irq.h
+ create mode 100644 arch/mips/include/asm/mach-lantiq/falcon/irq.h
+ create mode 100644 arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h
+ create mode 100644 arch/mips/lantiq/falcon/Makefile
+ create mode 100644 arch/mips/lantiq/falcon/clk.c
+ create mode 100644 arch/mips/lantiq/falcon/devices.c
+ create mode 100644 arch/mips/lantiq/falcon/devices.h
+ create mode 100644 arch/mips/lantiq/falcon/prom.c
+ create mode 100644 arch/mips/lantiq/falcon/reset.c
+ create mode 100644 arch/mips/lantiq/falcon/sysctrl.c
+
+diff --git a/arch/mips/include/asm/mach-lantiq/falcon/falcon_irq.h b/arch/mips/include/asm/mach-lantiq/falcon/falcon_irq.h
+new file mode 100644
+index 0000000..4dc6466
+--- /dev/null
++++ b/arch/mips/include/asm/mach-lantiq/falcon/falcon_irq.h
+@@ -0,0 +1,268 @@
++/*
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com>
++ */
++
++#ifndef _FALCON_IRQ__
++#define _FALCON_IRQ__
++
++#define INT_NUM_IRQ0 8
++#define INT_NUM_IM0_IRL0 (INT_NUM_IRQ0 + 0)
++#define INT_NUM_IM1_IRL0 (INT_NUM_IM0_IRL0 + 32)
++#define INT_NUM_IM2_IRL0 (INT_NUM_IM1_IRL0 + 32)
++#define INT_NUM_IM3_IRL0 (INT_NUM_IM2_IRL0 + 32)
++#define INT_NUM_IM4_IRL0 (INT_NUM_IM3_IRL0 + 32)
++#define INT_NUM_EXTRA_START (INT_NUM_IM4_IRL0 + 32)
++#define INT_NUM_IM_OFFSET (INT_NUM_IM1_IRL0 - INT_NUM_IM0_IRL0)
++
++#define MIPS_CPU_TIMER_IRQ 7
++
++/* HOST IF Event Interrupt */
++#define FALCON_IRQ_HOST (INT_NUM_IM0_IRL0 + 0)
++/* HOST IF Mailbox0 Receive Interrupt */
++#define FALCON_IRQ_HOST_MB0_RX (INT_NUM_IM0_IRL0 + 1)
++/* HOST IF Mailbox0 Transmit Interrupt */
++#define FALCON_IRQ_HOST_MB0_TX (INT_NUM_IM0_IRL0 + 2)
++/* HOST IF Mailbox1 Receive Interrupt */
++#define FALCON_IRQ_HOST_MB1_RX (INT_NUM_IM0_IRL0 + 3)
++/* HOST IF Mailbox1 Transmit Interrupt */
++#define FALCON_IRQ_HOST_MB1_TX (INT_NUM_IM0_IRL0 + 4)
++/* I2C Last Single Data Transfer Request */
++#define FALCON_IRQ_I2C_LSREQ (INT_NUM_IM0_IRL0 + 8)
++/* I2C Single Data Transfer Request */
++#define FALCON_IRQ_I2C_SREQ (INT_NUM_IM0_IRL0 + 9)
++/* I2C Last Burst Data Transfer Request */
++#define FALCON_IRQ_I2C_LBREQ (INT_NUM_IM0_IRL0 + 10)
++/* I2C Burst Data Transfer Request */
++#define FALCON_IRQ_I2C_BREQ (INT_NUM_IM0_IRL0 + 11)
++/* I2C Error Interrupt */
++#define FALCON_IRQ_I2C_I2C_ERR (INT_NUM_IM0_IRL0 + 12)
++/* I2C Protocol Interrupt */
++#define FALCON_IRQ_I2C_I2C_P (INT_NUM_IM0_IRL0 + 13)
++/* SSC Transmit Interrupt */
++#define FALCON_IRQ_SSC_T (INT_NUM_IM0_IRL0 + 14)
++/* SSC Receive Interrupt */
++#define FALCON_IRQ_SSC_R (INT_NUM_IM0_IRL0 + 15)
++/* SSC Error Interrupt */
++#define FALCON_IRQ_SSC_E (INT_NUM_IM0_IRL0 + 16)
++/* SSC Frame Interrupt */
++#define FALCON_IRQ_SSC_F (INT_NUM_IM0_IRL0 + 17)
++/* Advanced Encryption Standard Interrupt */
++#define FALCON_IRQ_AES_AES (INT_NUM_IM0_IRL0 + 27)
++/* Secure Hash Algorithm Interrupt */
++#define FALCON_IRQ_SHA_HASH (INT_NUM_IM0_IRL0 + 28)
++/* PCM Receive Interrupt */
++#define FALCON_IRQ_PCM_RX (INT_NUM_IM0_IRL0 + 29)
++/* PCM Transmit Interrupt */
++#define FALCON_IRQ_PCM_TX (INT_NUM_IM0_IRL0 + 30)
++/* PCM Transmit Crash Interrupt */
++#define FALCON_IRQ_PCM_HW2_CRASH (INT_NUM_IM0_IRL0 + 31)
++
++/* EBU Serial Flash Command Error */
++#define FALCON_IRQ_EBU_SF_CMDERR (INT_NUM_IM1_IRL0 + 0)
++/* EBU Serial Flash Command Overwrite Error */
++#define FALCON_IRQ_EBU_SF_COVERR (INT_NUM_IM1_IRL0 + 1)
++/* EBU Serial Flash Busy */
++#define FALCON_IRQ_EBU_SF_BUSY (INT_NUM_IM1_IRL0 + 2)
++/* External Interrupt from GPIO P0 */
++#define FALCON_IRQ_GPIO_P0 (INT_NUM_IM1_IRL0 + 4)
++/* External Interrupt from GPIO P1 */
++#define FALCON_IRQ_GPIO_P1 (INT_NUM_IM1_IRL0 + 5)
++/* External Interrupt from GPIO P2 */
++#define FALCON_IRQ_GPIO_P2 (INT_NUM_IM1_IRL0 + 6)
++/* External Interrupt from GPIO P3 */
++#define FALCON_IRQ_GPIO_P3 (INT_NUM_IM1_IRL0 + 7)
++/* External Interrupt from GPIO P4 */
++#define FALCON_IRQ_GPIO_P4 (INT_NUM_IM1_IRL0 + 8)
++/* 8kHz backup interrupt derived from core-PLL */
++#define FALCON_IRQ_FSC_BKP (INT_NUM_IM1_IRL0 + 10)
++/* FSC Timer Interrupt 0 */
++#define FALCON_IRQ_FSCT_CMP0 (INT_NUM_IM1_IRL0 + 11)
++/* FSC Timer Interrupt 1 */
++#define FALCON_IRQ_FSCT_CMP1 (INT_NUM_IM1_IRL0 + 12)
++/* 8kHz root interrupt derived from GPON interface */
++#define FALCON_IRQ_FSC_ROOT (INT_NUM_IM1_IRL0 + 13)
++/* Time of Day */
++#define FALCON_IRQ_TOD (INT_NUM_IM1_IRL0 + 14)
++/* PMA Interrupt from IntNode of the 200MHz Domain */
++#define FALCON_IRQ_PMA_200M (INT_NUM_IM1_IRL0 + 15)
++/* PMA Interrupt from IntNode of the TX Clk Domain */
++#define FALCON_IRQ_PMA_TX (INT_NUM_IM1_IRL0 + 16)
++/* PMA Interrupt from IntNode of the RX Clk Domain */
++#define FALCON_IRQ_PMA_RX (INT_NUM_IM1_IRL0 + 17)
++/* SYS1 Interrupt */
++#define FALCON_IRQ_SYS1 (INT_NUM_IM1_IRL0 + 20)
++/* SYS GPE Interrupt */
++#define FALCON_IRQ_SYS_GPE (INT_NUM_IM1_IRL0 + 21)
++/* Watchdog Access Error Interrupt */
++#define FALCON_IRQ_WDT_AEIR (INT_NUM_IM1_IRL0 + 24)
++/* Watchdog Prewarning Interrupt */
++#define FALCON_IRQ_WDT_PIR (INT_NUM_IM1_IRL0 + 25)
++/* SBIU interrupt */
++#define FALCON_IRQ_SBIU0 (INT_NUM_IM1_IRL0 + 27)
++/* FPI Bus Control Unit Interrupt */
++#define FALCON_IRQ_BCU0 (INT_NUM_IM1_IRL0 + 29)
++/* DDR Controller Interrupt */
++#define FALCON_IRQ_DDR (INT_NUM_IM1_IRL0 + 30)
++/* Crossbar Error Interrupt */
++#define FALCON_IRQ_XBAR_ERROR (INT_NUM_IM1_IRL0 + 31)
++
++/* ICTRLL 0 Interrupt */
++#define FALCON_IRQ_ICTRLL0 (INT_NUM_IM2_IRL0 + 0)
++/* ICTRLL 1 Interrupt */
++#define FALCON_IRQ_ICTRLL1 (INT_NUM_IM2_IRL0 + 1)
++/* ICTRLL 2 Interrupt */
++#define FALCON_IRQ_ICTRLL2 (INT_NUM_IM2_IRL0 + 2)
++/* ICTRLL 3 Interrupt */
++#define FALCON_IRQ_ICTRLL3 (INT_NUM_IM2_IRL0 + 3)
++/* OCTRLL 0 Interrupt */
++#define FALCON_IRQ_OCTRLL0 (INT_NUM_IM2_IRL0 + 4)
++/* OCTRLL 1 Interrupt */
++#define FALCON_IRQ_OCTRLL1 (INT_NUM_IM2_IRL0 + 5)
++/* OCTRLL 2 Interrupt */
++#define FALCON_IRQ_OCTRLL2 (INT_NUM_IM2_IRL0 + 6)
++/* OCTRLL 3 Interrupt */
++#define FALCON_IRQ_OCTRLL3 (INT_NUM_IM2_IRL0 + 7)
++/* OCTRLG Interrupt */
++#define FALCON_IRQ_OCTRLG (INT_NUM_IM2_IRL0 + 9)
++/* IQM Interrupt */
++#define FALCON_IRQ_IQM (INT_NUM_IM2_IRL0 + 10)
++/* FSQM Interrupt */
++#define FALCON_IRQ_FSQM (INT_NUM_IM2_IRL0 + 11)
++/* TMU Interrupt */
++#define FALCON_IRQ_TMU (INT_NUM_IM2_IRL0 + 12)
++/* LINK1 Interrupt */
++#define FALCON_IRQ_LINK1 (INT_NUM_IM2_IRL0 + 14)
++/* ICTRLC 0 Interrupt */
++#define FALCON_IRQ_ICTRLC0 (INT_NUM_IM2_IRL0 + 16)
++/* ICTRLC 1 Interrupt */
++#define FALCON_IRQ_ICTRLC1 (INT_NUM_IM2_IRL0 + 17)
++/* OCTRLC Interrupt */
++#define FALCON_IRQ_OCTRLC (INT_NUM_IM2_IRL0 + 18)
++/* CONFIG Break Interrupt */
++#define FALCON_IRQ_CONFIG_BREAK (INT_NUM_IM2_IRL0 + 19)
++/* CONFIG Interrupt */
++#define FALCON_IRQ_CONFIG (INT_NUM_IM2_IRL0 + 20)
++/* Dispatcher Interrupt */
++#define FALCON_IRQ_DISP (INT_NUM_IM2_IRL0 + 21)
++/* TBM Interrupt */
++#define FALCON_IRQ_TBM (INT_NUM_IM2_IRL0 + 22)
++/* GTC Downstream Interrupt */
++#define FALCON_IRQ_GTC_DS (INT_NUM_IM2_IRL0 + 29)
++/* GTC Upstream Interrupt */
++#define FALCON_IRQ_GTC_US (INT_NUM_IM2_IRL0 + 30)
++/* EIM Interrupt */
++#define FALCON_IRQ_EIM (INT_NUM_IM2_IRL0 + 31)
++
++/* ASC0 Transmit Interrupt */
++#define FALCON_IRQ_ASC0_T (INT_NUM_IM3_IRL0 + 0)
++/* ASC0 Receive Interrupt */
++#define FALCON_IRQ_ASC0_R (INT_NUM_IM3_IRL0 + 1)
++/* ASC0 Error Interrupt */
++#define FALCON_IRQ_ASC0_E (INT_NUM_IM3_IRL0 + 2)
++/* ASC0 Transmit Buffer Interrupt */
++#define FALCON_IRQ_ASC0_TB (INT_NUM_IM3_IRL0 + 3)
++/* ASC0 Autobaud Start Interrupt */
++#define FALCON_IRQ_ASC0_ABST (INT_NUM_IM3_IRL0 + 4)
++/* ASC0 Autobaud Detection Interrupt */
++#define FALCON_IRQ_ASC0_ABDET (INT_NUM_IM3_IRL0 + 5)
++/* ASC1 Modem Status Interrupt */
++#define FALCON_IRQ_ASC0_MS (INT_NUM_IM3_IRL0 + 6)
++/* ASC0 Soft Flow Control Interrupt */
++#define FALCON_IRQ_ASC0_SFC (INT_NUM_IM3_IRL0 + 7)
++/* ASC1 Transmit Interrupt */
++#define FALCON_IRQ_ASC1_T (INT_NUM_IM3_IRL0 + 8)
++/* ASC1 Receive Interrupt */
++#define FALCON_IRQ_ASC1_R (INT_NUM_IM3_IRL0 + 9)
++/* ASC1 Error Interrupt */
++#define FALCON_IRQ_ASC1_E (INT_NUM_IM3_IRL0 + 10)
++/* ASC1 Transmit Buffer Interrupt */
++#define FALCON_IRQ_ASC1_TB (INT_NUM_IM3_IRL0 + 11)
++/* ASC1 Autobaud Start Interrupt */
++#define FALCON_IRQ_ASC1_ABST (INT_NUM_IM3_IRL0 + 12)
++/* ASC1 Autobaud Detection Interrupt */
++#define FALCON_IRQ_ASC1_ABDET (INT_NUM_IM3_IRL0 + 13)
++/* ASC1 Modem Status Interrupt */
++#define FALCON_IRQ_ASC1_MS (INT_NUM_IM3_IRL0 + 14)
++/* ASC1 Soft Flow Control Interrupt */
++#define FALCON_IRQ_ASC1_SFC (INT_NUM_IM3_IRL0 + 15)
++/* GPTC Timer/Counter 1A Interrupt */
++#define FALCON_IRQ_GPTC_TC1A (INT_NUM_IM3_IRL0 + 16)
++/* GPTC Timer/Counter 1B Interrupt */
++#define FALCON_IRQ_GPTC_TC1B (INT_NUM_IM3_IRL0 + 17)
++/* GPTC Timer/Counter 2A Interrupt */
++#define FALCON_IRQ_GPTC_TC2A (INT_NUM_IM3_IRL0 + 18)
++/* GPTC Timer/Counter 2B Interrupt */
++#define FALCON_IRQ_GPTC_TC2B (INT_NUM_IM3_IRL0 + 19)
++/* GPTC Timer/Counter 3A Interrupt */
++#define FALCON_IRQ_GPTC_TC3A (INT_NUM_IM3_IRL0 + 20)
++/* GPTC Timer/Counter 3B Interrupt */
++#define FALCON_IRQ_GPTC_TC3B (INT_NUM_IM3_IRL0 + 21)
++/* DFEV0, Channel 1 Transmit Interrupt */
++#define FALCON_IRQ_DFEV0_2TX (INT_NUM_IM3_IRL0 + 26)
++/* DFEV0, Channel 1 Receive Interrupt */
++#define FALCON_IRQ_DFEV0_2RX (INT_NUM_IM3_IRL0 + 27)
++/* DFEV0, Channel 1 General Purpose Interrupt */
++#define FALCON_IRQ_DFEV0_2GP (INT_NUM_IM3_IRL0 + 28)
++/* DFEV0, Channel 0 Transmit Interrupt */
++#define FALCON_IRQ_DFEV0_1TX (INT_NUM_IM3_IRL0 + 29)
++/* DFEV0, Channel 0 Receive Interrupt */
++#define FALCON_IRQ_DFEV0_1RX (INT_NUM_IM3_IRL0 + 30)
++/* DFEV0, Channel 0 General Purpose Interrupt */
++#define FALCON_IRQ_DFEV0_1GP (INT_NUM_IM3_IRL0 + 31)
++
++/* ICTRLL 0 Error */
++#define FALCON_IRQ_ICTRLL0_ERR (INT_NUM_IM4_IRL0 + 0)
++/* ICTRLL 1 Error */
++#define FALCON_IRQ_ICTRLL1_ERR (INT_NUM_IM4_IRL0 + 1)
++/* ICTRLL 2 Error */
++#define FALCON_IRQ_ICTRLL2_ERR (INT_NUM_IM4_IRL0 + 2)
++/* ICTRLL 3 Error */
++#define FALCON_IRQ_ICTRLL3_ERR (INT_NUM_IM4_IRL0 + 3)
++/* OCTRLL 0 Error */
++#define FALCON_IRQ_OCTRLL0_ERR (INT_NUM_IM4_IRL0 + 4)
++/* OCTRLL 1 Error */
++#define FALCON_IRQ_OCTRLL1_ERR (INT_NUM_IM4_IRL0 + 5)
++/* OCTRLL 2 Error */
++#define FALCON_IRQ_OCTRLL2_ERR (INT_NUM_IM4_IRL0 + 6)
++/* OCTRLL 3 Error */
++#define FALCON_IRQ_OCTRLL3_ERR (INT_NUM_IM4_IRL0 + 7)
++/* ICTRLG Error */
++#define FALCON_IRQ_ICTRLG_ERR (INT_NUM_IM4_IRL0 + 8)
++/* OCTRLG Error */
++#define FALCON_IRQ_OCTRLG_ERR (INT_NUM_IM4_IRL0 + 9)
++/* IQM Error */
++#define FALCON_IRQ_IQM_ERR (INT_NUM_IM4_IRL0 + 10)
++/* FSQM Error */
++#define FALCON_IRQ_FSQM_ERR (INT_NUM_IM4_IRL0 + 11)
++/* TMU Error */
++#define FALCON_IRQ_TMU_ERR (INT_NUM_IM4_IRL0 + 12)
++/* MPS Status Interrupt #0 (VPE1 to VPE0) */
++#define FALCON_IRQ_MPS_IR0 (INT_NUM_IM4_IRL0 + 14)
++/* MPS Status Interrupt #1 (VPE1 to VPE0) */
++#define FALCON_IRQ_MPS_IR1 (INT_NUM_IM4_IRL0 + 15)
++/* MPS Status Interrupt #2 (VPE1 to VPE0) */
++#define FALCON_IRQ_MPS_IR2 (INT_NUM_IM4_IRL0 + 16)
++/* MPS Status Interrupt #3 (VPE1 to VPE0) */
++#define FALCON_IRQ_MPS_IR3 (INT_NUM_IM4_IRL0 + 17)
++/* MPS Status Interrupt #4 (VPE1 to VPE0) */
++#define FALCON_IRQ_MPS_IR4 (INT_NUM_IM4_IRL0 + 18)
++/* MPS Status Interrupt #5 (VPE1 to VPE0) */
++#define FALCON_IRQ_MPS_IR5 (INT_NUM_IM4_IRL0 + 19)
++/* MPS Status Interrupt #6 (VPE1 to VPE0) */
++#define FALCON_IRQ_MPS_IR6 (INT_NUM_IM4_IRL0 + 20)
++/* MPS Status Interrupt #7 (VPE1 to VPE0) */
++#define FALCON_IRQ_MPS_IR7 (INT_NUM_IM4_IRL0 + 21)
++/* MPS Status Interrupt #8 (VPE1 to VPE0) */
++#define FALCON_IRQ_MPS_IR8 (INT_NUM_IM4_IRL0 + 22)
++/* VPE0 Exception Level Flag Interrupt */
++#define FALCON_IRQ_VPE0_EXL (INT_NUM_IM4_IRL0 + 29)
++/* VPE0 Error Level Flag Interrupt */
++#define FALCON_IRQ_VPE0_ERL (INT_NUM_IM4_IRL0 + 30)
++/* VPE0 Performance Monitoring Counter Interrupt */
++#define FALCON_IRQ_VPE0_PMCIR (INT_NUM_IM4_IRL0 + 31)
++
++#endif /* _FALCON_IRQ__ */
+diff --git a/arch/mips/include/asm/mach-lantiq/falcon/irq.h b/arch/mips/include/asm/mach-lantiq/falcon/irq.h
+new file mode 100644
+index 0000000..2caccd9
+--- /dev/null
++++ b/arch/mips/include/asm/mach-lantiq/falcon/irq.h
+@@ -0,0 +1,18 @@
++/*
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ * Copyright (C) 2011 Thomas Langer <thomas.langer@lantiq.com>
++ */
++
++#ifndef __FALCON_IRQ_H
++#define __FALCON_IRQ_H
++
++#include <falcon_irq.h>
++
++#define NR_IRQS 328
++
++#include_next <irq.h>
++
++#endif
+diff --git a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h
+new file mode 100644
+index 0000000..c092531
+--- /dev/null
++++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h
+@@ -0,0 +1,140 @@
++/*
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
++ */
++
++#ifndef _LTQ_FALCON_H__
++#define _LTQ_FALCON_H__
++
++#ifdef CONFIG_SOC_FALCON
++
++#include <lantiq.h>
++
++/* Chip IDs */
++#define SOC_ID_FALCON 0x01B8
++
++/* SoC Types */
++#define SOC_TYPE_FALCON 0x01
++
++/* ASC0/1 - serial port */
++#define LTQ_ASC0_BASE_ADDR 0x1E100C00
++#define LTQ_ASC1_BASE_ADDR 0x1E100B00
++#define LTQ_ASC_SIZE 0x100
++
++#define LTQ_ASC_TIR(x) (INT_NUM_IM3_IRL0 + (x * 8))
++#define LTQ_ASC_RIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 1)
++#define LTQ_ASC_EIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 2)
++
++/* during early_printk no ioremap possible at this early stage
++ lets use KSEG1 instead */
++#define LTQ_EARLY_ASC KSEG1ADDR(LTQ_ASC0_BASE_ADDR)
++
++/* ICU - interrupt control unit */
++#define LTQ_ICU_BASE_ADDR 0x1F880200
++#define LTQ_ICU_SIZE 0x100
++
++/* WDT */
++#define LTQ_WDT_BASE_ADDR 0x1F8803F0
++#define LTQ_WDT_SIZE 0x10
++
++#define LTQ_RST_CAUSE_WDTRST 0x0002
++
++/* EBU - external bus unit */
++#define LTQ_EBU_BASE_ADDR 0x18000000
++#define LTQ_EBU_SIZE 0x0100
++
++#define LTQ_EBU_MODCON 0x000C
++
++/* GPIO */
++#define LTQ_GPIO0_BASE_ADDR 0x1D810000
++#define LTQ_GPIO0_SIZE 0x0080
++#define LTQ_GPIO1_BASE_ADDR 0x1E800100
++#define LTQ_GPIO1_SIZE 0x0080
++#define LTQ_GPIO2_BASE_ADDR 0x1D810100
++#define LTQ_GPIO2_SIZE 0x0080
++#define LTQ_GPIO3_BASE_ADDR 0x1E800200
++#define LTQ_GPIO3_SIZE 0x0080
++#define LTQ_GPIO4_BASE_ADDR 0x1E800300
++#define LTQ_GPIO4_SIZE 0x0080
++#define LTQ_PADCTRL0_BASE_ADDR 0x1DB01000
++#define LTQ_PADCTRL0_SIZE 0x0100
++#define LTQ_PADCTRL1_BASE_ADDR 0x1E800400
++#define LTQ_PADCTRL1_SIZE 0x0100
++#define LTQ_PADCTRL2_BASE_ADDR 0x1DB02000
++#define LTQ_PADCTRL2_SIZE 0x0100
++#define LTQ_PADCTRL3_BASE_ADDR 0x1E800500
++#define LTQ_PADCTRL3_SIZE 0x0100
++#define LTQ_PADCTRL4_BASE_ADDR 0x1E800600
++#define LTQ_PADCTRL4_SIZE 0x0100
++
++/* CHIP ID */
++#define LTQ_STATUS_BASE_ADDR 0x1E802000
++
++#define LTQ_FALCON_CHIPID ((u32 *)(KSEG1 + LTQ_STATUS_BASE_ADDR + 0x0c))
++#define LTQ_FALCON_CHIPCONF ((u32 *)(KSEG1 + LTQ_STATUS_BASE_ADDR + 0x40))
++
++/* SYSCTL - start/stop/restart/configure/... different parts of the Soc */
++#define LTQ_SYS1_BASE_ADDR 0x1EF00000
++#define LTQ_SYS1_SIZE 0x0100
++#define LTQ_STATUS_BASE_ADDR 0x1E802000
++#define LTQ_STATUS_SIZE 0x0080
++#define LTQ_SYS_ETH_BASE_ADDR 0x1DB00000
++#define LTQ_SYS_ETH_SIZE 0x0100
++#define LTQ_SYS_GPE_BASE_ADDR 0x1D700000
++#define LTQ_SYS_GPE_SIZE 0x0100
++
++#define SYSCTL_SYS1 0
++#define SYSCTL_SYSETH 1
++#define SYSCTL_SYSGPE 2
++
++/* Activation Status Register */
++#define ACTS_ASC1_ACT 0x00000800
++#define ACTS_P0 0x00010000
++#define ACTS_P1 0x00010000
++#define ACTS_P2 0x00020000
++#define ACTS_P3 0x00020000
++#define ACTS_P4 0x00040000
++#define ACTS_PADCTRL0 0x00100000
++#define ACTS_PADCTRL1 0x00100000
++#define ACTS_PADCTRL2 0x00200000
++#define ACTS_PADCTRL3 0x00200000
++#define ACTS_PADCTRL4 0x00400000
++
++extern void ltq_sysctl_activate(int module, unsigned int mask);
++extern void ltq_sysctl_deactivate(int module, unsigned int mask);
++extern void ltq_sysctl_clken(int module, unsigned int mask);
++extern void ltq_sysctl_clkdis(int module, unsigned int mask);
++extern void ltq_sysctl_reboot(int module, unsigned int mask);
++extern int ltq_gpe_is_activated(unsigned int mask);
++
++/* global register ranges */
++extern __iomem void *ltq_ebu_membase;
++extern __iomem void *ltq_sys1_membase;
++#define ltq_ebu_w32(x, y) ltq_w32((x), ltq_ebu_membase + (y))
++#define ltq_ebu_r32(x) ltq_r32(ltq_ebu_membase + (x))
++#define ltq_ebu_w32_mask(clear, set, reg) \
++ ltq_ebu_w32((ltq_ebu_r32(reg) & ~(clear)) | (set), reg)
++
++#define ltq_sys1_w32(x, y) ltq_w32((x), ltq_sys1_membase + (y))
++#define ltq_sys1_r32(x) ltq_r32(ltq_sys1_membase + (x))
++#define ltq_sys1_w32_mask(clear, set, reg) \
++ ltq_sys1_w32((ltq_sys1_r32(reg) & ~(clear)) | (set), reg)
++
++/* gpio_request wrapper to help configure the pin */
++extern int ltq_gpio_request(unsigned int pin, unsigned int val,
++ unsigned int dir, const char *name);
++extern int ltq_gpio_mux_set(unsigned int pin, unsigned int mux);
++
++/* to keep the irq code generic we need to define these to 0 as falcon
++ has no EIU/EBU */
++#define LTQ_EIU_BASE_ADDR 0
++#define LTQ_EBU_PCC_ISTAT 0
++
++#define ltq_is_ar9() 0
++#define ltq_is_vr9() 0
++
++#endif /* CONFIG_SOC_FALCON */
++#endif /* _LTQ_XWAY_H__ */
+diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h
+index 66d7300..188de0f 100644
+--- a/arch/mips/include/asm/mach-lantiq/lantiq.h
++++ b/arch/mips/include/asm/mach-lantiq/lantiq.h
+@@ -25,6 +25,7 @@ extern unsigned int ltq_get_soc_type(void);
+ /* clock speeds */
+ #define CLOCK_60M 60000000
+ #define CLOCK_83M 83333333
++#define CLOCK_100M 100000000
+ #define CLOCK_111M 111111111
+ #define CLOCK_133M 133333333
+ #define CLOCK_167M 166666667
+diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig
+index 3fccf21..cb6b39f 100644
+--- a/arch/mips/lantiq/Kconfig
++++ b/arch/mips/lantiq/Kconfig
+@@ -16,8 +16,12 @@ config SOC_XWAY
+ bool "XWAY"
+ select SOC_TYPE_XWAY
+ select HW_HAS_PCI
++
++config SOC_FALCON
++ bool "FALCON"
+ endchoice
+
+ source "arch/mips/lantiq/xway/Kconfig"
++source "arch/mips/lantiq/falcon/Kconfig"
+
+ endif
+diff --git a/arch/mips/lantiq/Makefile b/arch/mips/lantiq/Makefile
+index e5dae0e..7e9c69e 100644
+--- a/arch/mips/lantiq/Makefile
++++ b/arch/mips/lantiq/Makefile
+@@ -9,3 +9,4 @@ obj-y := irq.o setup.o clk.o prom.o devices.o
+ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+
+ obj-$(CONFIG_SOC_TYPE_XWAY) += xway/
++obj-$(CONFIG_SOC_FALCON) += falcon/
+diff --git a/arch/mips/lantiq/Platform b/arch/mips/lantiq/Platform
+index f3dff05..b3ec498 100644
+--- a/arch/mips/lantiq/Platform
++++ b/arch/mips/lantiq/Platform
+@@ -6,3 +6,4 @@ platform-$(CONFIG_LANTIQ) += lantiq/
+ cflags-$(CONFIG_LANTIQ) += -I$(srctree)/arch/mips/include/asm/mach-lantiq
+ load-$(CONFIG_LANTIQ) = 0xffffffff80002000
+ cflags-$(CONFIG_SOC_TYPE_XWAY) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/xway
++cflags-$(CONFIG_SOC_FALCON) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/falcon
+diff --git a/arch/mips/lantiq/falcon/Makefile b/arch/mips/lantiq/falcon/Makefile
+new file mode 100644
+index 0000000..e9c7455
+--- /dev/null
++++ b/arch/mips/lantiq/falcon/Makefile
+@@ -0,0 +1 @@
++obj-y := clk.o prom.o reset.o sysctrl.o devices.o
+diff --git a/arch/mips/lantiq/falcon/clk.c b/arch/mips/lantiq/falcon/clk.c
+new file mode 100644
+index 0000000..1a550ea
+--- /dev/null
++++ b/arch/mips/lantiq/falcon/clk.c
+@@ -0,0 +1,44 @@
++/*
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ * Copyright (C) 2011 Thomas Langer <thomas.langer@lantiq.com>
++ * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
++ */
++
++#include <linux/ioport.h>
++#include <linux/module.h>
++
++#include <lantiq_soc.h>
++
++#include "devices.h"
++
++/* CPU0 Clock Control Register */
++#define LTQ_SYS1_CPU0CC 0x0040
++/* clock divider bit */
++#define LTQ_CPU0CC_CPUDIV 0x0001
++
++unsigned int
++ltq_get_io_region_clock(void)
++{
++ return CLOCK_200M;
++}
++EXPORT_SYMBOL(ltq_get_io_region_clock);
++
++unsigned int
++ltq_get_cpu_hz(void)
++{
++ if (ltq_sys1_r32(LTQ_SYS1_CPU0CC) & LTQ_CPU0CC_CPUDIV)
++ return CLOCK_200M;
++ else
++ return CLOCK_400M;
++}
++EXPORT_SYMBOL(ltq_get_cpu_hz);
++
++unsigned int
++ltq_get_fpi_hz(void)
++{
++ return CLOCK_100M;
++}
++EXPORT_SYMBOL(ltq_get_fpi_hz);
+diff --git a/arch/mips/lantiq/falcon/devices.c b/arch/mips/lantiq/falcon/devices.c
+new file mode 100644
+index 0000000..c4606f2
+--- /dev/null
++++ b/arch/mips/lantiq/falcon/devices.c
+@@ -0,0 +1,87 @@
++/*
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ * Copyright (C) 2011 Thomas Langer <thomas.langer@lantiq.com>
++ * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
++ */
++
++#include <linux/platform_device.h>
++#include <linux/mtd/nand.h>
++
++#include <lantiq_soc.h>
++
++#include "devices.h"
++
++/* nand flash */
++/* address lines used for NAND control signals */
++#define NAND_ADDR_ALE 0x10000
++#define NAND_ADDR_CLE 0x20000
++/* Ready/Busy Status */
++#define MODCON_STS 0x0002
++/* Ready/Busy Status Edge */
++#define MODCON_STSEDGE 0x0004
++
++static const char *part_probes[] = { "cmdlinepart", NULL };
++
++static int
++falcon_nand_ready(struct mtd_info *mtd)
++{
++ u32 modcon = ltq_ebu_r32(LTQ_EBU_MODCON);
++
++ return (((modcon & (MODCON_STS | MODCON_STSEDGE)) ==
++ (MODCON_STS | MODCON_STSEDGE)));
++}
++
++static void
++falcon_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
++{
++ struct nand_chip *this = mtd->priv;
++ unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
++
++ if (ctrl & NAND_CTRL_CHANGE) {
++ nandaddr &= ~(NAND_ADDR_ALE | NAND_ADDR_CLE);
++
++ if (ctrl & NAND_CLE)
++ nandaddr |= NAND_ADDR_CLE;
++ if (ctrl & NAND_ALE)
++ nandaddr |= NAND_ADDR_ALE;
++
++ this->IO_ADDR_W = (void __iomem *) nandaddr;
++ }
++
++ if (cmd != NAND_CMD_NONE)
++ writeb(cmd, this->IO_ADDR_W);
++}
++
++static struct platform_nand_data falcon_flash_nand_data = {
++ .chip = {
++ .nr_chips = 1,
++ .chip_delay = 25,
++ .part_probe_types = part_probes,
++ },
++ .ctrl = {
++ .cmd_ctrl = falcon_hwcontrol,
++ .dev_ready = falcon_nand_ready,
++ }
++};
++
++static struct resource ltq_nand_res =
++ MEM_RES("nand", LTQ_FLASH_START, LTQ_FLASH_MAX);
++
++static struct platform_device ltq_flash_nand = {
++ .name = "gen_nand",
++ .id = -1,
++ .num_resources = 1,
++ .resource = <q_nand_res,
++ .dev = {
++ .platform_data = &falcon_flash_nand_data,
++ },
++};
++
++void __init
++falcon_register_nand(void)
++{
++ platform_device_register(<q_flash_nand);
++}
+diff --git a/arch/mips/lantiq/falcon/devices.h b/arch/mips/lantiq/falcon/devices.h
+new file mode 100644
+index 0000000..e802a7c
+--- /dev/null
++++ b/arch/mips/lantiq/falcon/devices.h
+@@ -0,0 +1,18 @@
++/*
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * Copyright (C) 2011 Thomas Langer <thomas.langer@lantiq.com>
++ * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
++ */
++
++#ifndef _FALCON_DEVICES_H__
++#define _FALCON_DEVICES_H__
++
++#include "../devices.h"
++
++extern void falcon_register_nand(void);
++
++#endif
+diff --git a/arch/mips/lantiq/falcon/prom.c b/arch/mips/lantiq/falcon/prom.c
+new file mode 100644
+index 0000000..89367c4
+--- /dev/null
++++ b/arch/mips/lantiq/falcon/prom.c
+@@ -0,0 +1,72 @@
++/*
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ * Copyright (C) 2011 Thomas Langer <thomas.langer@lantiq.com>
++ * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
++ */
++
++#include <lantiq_soc.h>
++
++#include "devices.h"
++
++#include "../prom.h"
++
++#define SOC_FALCON "Falcon"
++
++#define PART_SHIFT 12
++#define PART_MASK 0x0FFFF000
++#define REV_SHIFT 28
++#define REV_MASK 0xF0000000
++#define SREV_SHIFT 22
++#define SREV_MASK 0x03C00000
++
++#define MUXC_SIF_RX_PIN 112
++#define MUXC_SIF_TX_PIN 113
++
++/* this parameter allows us enable/disable asc1 via commandline */
++static int register_asc1;
++static int __init
++ltq_parse_asc1(char *p)
++{
++ register_asc1 = 1;
++ return 0;
++}
++__setup("use_asc1", ltq_parse_asc1);
++
++void __init
++ltq_soc_setup(void)
++{
++ ltq_register_asc(0);
++ ltq_register_wdt();
++ falcon_register_gpio();
++ if (register_asc1) {
++ ltq_register_asc(1);
++ if (ltq_gpio_request(MUXC_SIF_RX_PIN, 3, 0, "asc1-rx"))
++ pr_err("failed to request asc1-rx");
++ if (ltq_gpio_request(MUXC_SIF_TX_PIN, 3, 1, "asc1-tx"))
++ pr_err("failed to request asc1-tx");
++ ltq_sysctl_activate(SYSCTL_SYS1, ACTS_ASC1_ACT);
++ }
++}
++
++void __init
++ltq_soc_detect(struct ltq_soc_info *i)
++{
++ i->partnum = (ltq_r32(LTQ_FALCON_CHIPID) & PART_MASK) >> PART_SHIFT;
++ i->rev = (ltq_r32(LTQ_FALCON_CHIPID) & REV_MASK) >> REV_SHIFT;
++ i->srev = (ltq_r32(LTQ_FALCON_CHIPCONF) & SREV_MASK) >> SREV_SHIFT;
++ sprintf(i->rev_type, "%c%d%d", (i->srev & 0x4) ? ('B') : ('A'),
++ i->rev & 0x7, i->srev & 0x3);
++ switch (i->partnum) {
++ case SOC_ID_FALCON:
++ i->name = SOC_FALCON;
++ i->type = SOC_TYPE_FALCON;
++ break;
++
++ default:
++ unreachable();
++ break;
++ }
++}
+diff --git a/arch/mips/lantiq/falcon/reset.c b/arch/mips/lantiq/falcon/reset.c
+new file mode 100644
+index 0000000..d3289ca
+--- /dev/null
++++ b/arch/mips/lantiq/falcon/reset.c
+@@ -0,0 +1,87 @@
++/*
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ * Copyright (C) 2011 Thomas Langer <thomas.langer@lantiq.com>
++ * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
++ */
++
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/pm.h>
++#include <asm/reboot.h>
++#include <linux/module.h>
++
++#include <lantiq_soc.h>
++
++/* CPU0 Reset Source Register */
++#define LTQ_SYS1_CPU0RS 0x0040
++/* reset cause mask */
++#define LTQ_CPU0RS_MASK 0x0003
++
++int
++ltq_reset_cause(void)
++{
++ return ltq_sys1_r32(LTQ_SYS1_CPU0RS) & LTQ_CPU0RS_MASK;
++}
++EXPORT_SYMBOL_GPL(ltq_reset_cause);
++
++#define BOOT_REG_BASE (KSEG1 | 0x1F200000)
++#define BOOT_PW1_REG (BOOT_REG_BASE | 0x20)
++#define BOOT_PW2_REG (BOOT_REG_BASE | 0x24)
++#define BOOT_PW1 0x4C545100
++#define BOOT_PW2 0x0051544C
++
++#define WDT_REG_BASE (KSEG1 | 0x1F8803F0)
++#define WDT_PW1 0x00BE0000
++#define WDT_PW2 0x00DC0000
++
++static void
++ltq_machine_restart(char *command)
++{
++ pr_notice("System restart\n");
++ local_irq_disable();
++
++ /* reboot magic */
++ ltq_w32(BOOT_PW1, (void *)BOOT_PW1_REG); /* 'LTQ\0' */
++ ltq_w32(BOOT_PW2, (void *)BOOT_PW2_REG); /* '\0QTL' */
++ ltq_w32(0, (void *)BOOT_REG_BASE); /* reset Bootreg RVEC */
++
++ /* watchdog magic */
++ ltq_w32(WDT_PW1, (void *)WDT_REG_BASE);
++ ltq_w32(WDT_PW2 |
++ (0x3 << 26) | /* PWL */
++ (0x2 << 24) | /* CLKDIV */
++ (0x1 << 31) | /* enable */
++ (1), /* reload */
++ (void *)WDT_REG_BASE);
++ unreachable();
++}
++
++static void
++ltq_machine_halt(void)
++{
++ pr_notice("System halted.\n");
++ local_irq_disable();
++ unreachable();
++}
++
++static void
++ltq_machine_power_off(void)
++{
++ pr_notice("Please turn off the power now.\n");
++ local_irq_disable();
++ unreachable();
++}
++
++static int __init
++mips_reboot_setup(void)
++{
++ _machine_restart = ltq_machine_restart;
++ _machine_halt = ltq_machine_halt;
++ pm_power_off = ltq_machine_power_off;
++ return 0;
++}
++
++arch_initcall(mips_reboot_setup);
+diff --git a/arch/mips/lantiq/falcon/sysctrl.c b/arch/mips/lantiq/falcon/sysctrl.c
+new file mode 100644
+index 0000000..d20b46b
+--- /dev/null
++++ b/arch/mips/lantiq/falcon/sysctrl.c
+@@ -0,0 +1,181 @@
++/*
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ * Copyright (C) 2011 Thomas Langer <thomas.langer@lantiq.com>
++ * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
++ */
++
++#include <linux/ioport.h>
++#include <asm/delay.h>
++
++#include <lantiq_soc.h>
++
++#include "devices.h"
++
++/* infrastructure control register */
++#define SYS1_INFRAC 0x00bc
++/* Configuration fuses for drivers and pll */
++#define STATUS_CONFIG 0x0040
++
++/* GPE frequency selection */
++#define GPPC_OFFSET 24
++#define GPEFREQ_MASK 0x00000C0
++#define GPEFREQ_OFFSET 10
++/* Clock status register */
++#define LTQ_SYSCTL_CLKS 0x0000
++/* Clock enable register */
++#define LTQ_SYSCTL_CLKEN 0x0004
++/* Clock clear register */
++#define LTQ_SYSCTL_CLKCLR 0x0008
++/* Activation Status Register */
++#define LTQ_SYSCTL_ACTS 0x0020
++/* Activation Register */
++#define LTQ_SYSCTL_ACT 0x0024
++/* Deactivation Register */
++#define LTQ_SYSCTL_DEACT 0x0028
++/* reboot Register */
++#define LTQ_SYSCTL_RBT 0x002c
++
++static struct resource ltq_sysctl_res[] = {
++ MEM_RES("sys1", LTQ_SYS1_BASE_ADDR, LTQ_SYS1_SIZE),
++ MEM_RES("syseth", LTQ_SYS_ETH_BASE_ADDR, LTQ_SYS_ETH_SIZE),
++ MEM_RES("sysgpe", LTQ_SYS_GPE_BASE_ADDR, LTQ_SYS_GPE_SIZE),
++};
++
++static struct resource ltq_status_res =
++ MEM_RES("status", LTQ_STATUS_BASE_ADDR, LTQ_STATUS_SIZE);
++static struct resource ltq_ebu_res =
++ MEM_RES("ebu", LTQ_EBU_BASE_ADDR, LTQ_EBU_SIZE);
++
++static void __iomem *ltq_sysctl[3];
++static void __iomem *ltq_status_membase;
++void __iomem *ltq_sys1_membase;
++void __iomem *ltq_ebu_membase;
++
++#define ltq_reg_w32(m, x, y) ltq_w32((x), ltq_sysctl[m] + (y))
++#define ltq_reg_r32(m, x) ltq_r32(ltq_sysctl[m] + (x))
++#define ltq_reg_w32_mask(m, clear, set, reg) \
++ ltq_reg_w32(m, (ltq_reg_r32(m, reg) & ~(clear)) | (set), reg)
++
++#define ltq_status_w32(x, y) ltq_w32((x), ltq_status_membase + (y))
++#define ltq_status_r32(x) ltq_r32(ltq_status_membase + (x))
++
++static inline void
++ltq_sysctl_wait(int module, unsigned int mask, unsigned int test)
++{
++ int err = 1000000;
++
++ do {} while (--err && ((ltq_reg_r32(module, LTQ_SYSCTL_ACTS)
++ & mask) != test));
++ if (!err)
++ pr_err("module de/activation failed %d %08X %08X\n",
++ module, mask, test);
++}
++
++void
++ltq_sysctl_activate(int module, unsigned int mask)
++{
++ if (module > SYSCTL_SYSGPE)
++ return;
++
++ ltq_reg_w32(module, mask, LTQ_SYSCTL_CLKEN);
++ ltq_reg_w32(module, mask, LTQ_SYSCTL_ACT);
++ ltq_sysctl_wait(module, mask, mask);
++}
++EXPORT_SYMBOL(ltq_sysctl_activate);
++
++void
++ltq_sysctl_deactivate(int module, unsigned int mask)
++{
++ if (module > SYSCTL_SYSGPE)
++ return;
++
++ ltq_reg_w32(module, mask, LTQ_SYSCTL_CLKCLR);
++ ltq_reg_w32(module, mask, LTQ_SYSCTL_DEACT);
++ ltq_sysctl_wait(module, mask, 0);
++}
++EXPORT_SYMBOL(ltq_sysctl_deactivate);
++
++void
++ltq_sysctl_clken(int module, unsigned int mask)
++{
++ if (module > SYSCTL_SYSGPE)
++ return;
++
++ ltq_reg_w32(module, mask, LTQ_SYSCTL_CLKEN);
++ ltq_sysctl_wait(module, mask, mask);
++}
++EXPORT_SYMBOL(ltq_sysctl_clken);
++
++void
++ltq_sysctl_clkdis(int module, unsigned int mask)
++{
++ if (module > SYSCTL_SYSGPE)
++ return;
++
++ ltq_reg_w32(module, mask, LTQ_SYSCTL_CLKCLR);
++ ltq_sysctl_wait(module, mask, 0);
++}
++EXPORT_SYMBOL(ltq_sysctl_clkdis);
++
++void
++ltq_sysctl_reboot(int module, unsigned int mask)
++{
++ unsigned int act;
++
++ if (module > SYSCTL_SYSGPE)
++ return;
++
++ act = ltq_reg_r32(module, LTQ_SYSCTL_ACT);
++ if ((~act & mask) != 0)
++ ltq_sysctl_activate(module, ~act & mask);
++ ltq_reg_w32(module, act & mask, LTQ_SYSCTL_RBT);
++ ltq_sysctl_wait(module, mask, mask);
++}
++EXPORT_SYMBOL(ltq_sysctl_reboot);
++
++/* enable the ONU core */
++static void
++ltq_gpe_enable(void)
++{
++ unsigned int freq;
++ unsigned int status;
++
++ /* if if the clock is already enabled */
++ status = ltq_reg_r32(SYSCTL_SYS1, SYS1_INFRAC);
++ if (status & (1 << (GPPC_OFFSET + 1)))
++ return;
++
++ if (ltq_status_r32(STATUS_CONFIG) == 0)
++ freq = 1; /* use 625MHz on unfused chip */
++ else
++ freq = (ltq_status_r32(STATUS_CONFIG) &
++ GPEFREQ_MASK) >>
++ GPEFREQ_OFFSET;
++
++ /* apply new frequency */
++ ltq_reg_w32_mask(SYSCTL_SYS1, 7 << (GPPC_OFFSET + 1),
++ freq << (GPPC_OFFSET + 2) , SYS1_INFRAC);
++ udelay(1);
++
++ /* enable new frequency */
++ ltq_reg_w32_mask(SYSCTL_SYS1, 0, 1 << (GPPC_OFFSET + 1), SYS1_INFRAC);
++ udelay(1);
++}
++
++void __init
++ltq_soc_init(void)
++{
++ int i;
++
++ for (i = 0; i < 3; i++)
++ ltq_sysctl[i] = ltq_remap_resource(<q_sysctl_res[i]);
++
++ ltq_sys1_membase = ltq_sysctl[0];
++ ltq_status_membase = ltq_remap_resource(<q_status_res);
++ ltq_ebu_membase = ltq_remap_resource(<q_ebu_res);
++
++ ltq_gpe_enable();
++}
+--
+1.7.5.4
+
--- /dev/null
+From 02d9df56be1ba23c7bec51c94e5d2ac0d13d2d78 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Thu, 11 Aug 2011 14:35:02 +0200
+Subject: [PATCH 07/24] MIPS: lantiq: add support for FALC-ON GPIOs
+
+FALC-ON uses a different GPIO core than the other Lantiq SoCs. This patch adds
+the new driver.
+
+Signed-off-by: Thomas Langer <thomas.langer@lantiq.com>
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Cc: linux-mips@linux-mips.org
+---
+ arch/mips/lantiq/falcon/Makefile | 2 +-
+ arch/mips/lantiq/falcon/devices.c | 41 ++++
+ arch/mips/lantiq/falcon/devices.h | 2 +
+ arch/mips/lantiq/falcon/gpio.c | 398 +++++++++++++++++++++++++++++++++++++
+ 4 files changed, 442 insertions(+), 1 deletions(-)
+ create mode 100644 arch/mips/lantiq/falcon/gpio.c
+
+diff --git a/arch/mips/lantiq/falcon/Makefile b/arch/mips/lantiq/falcon/Makefile
+index e9c7455..de72209 100644
+--- a/arch/mips/lantiq/falcon/Makefile
++++ b/arch/mips/lantiq/falcon/Makefile
+@@ -1 +1 @@
+-obj-y := clk.o prom.o reset.o sysctrl.o devices.o
++obj-y := clk.o prom.o reset.o sysctrl.o devices.o gpio.o
+diff --git a/arch/mips/lantiq/falcon/devices.c b/arch/mips/lantiq/falcon/devices.c
+index c4606f2..4f47b44 100644
+--- a/arch/mips/lantiq/falcon/devices.c
++++ b/arch/mips/lantiq/falcon/devices.c
+@@ -9,6 +9,7 @@
+
+ #include <linux/platform_device.h>
+ #include <linux/mtd/nand.h>
++#include <linux/gpio.h>
+
+ #include <lantiq_soc.h>
+
+@@ -85,3 +86,43 @@ falcon_register_nand(void)
+ {
+ platform_device_register(<q_flash_nand);
+ }
++
++/* gpio */
++#define DECLARE_GPIO_RES(port) \
++static struct resource falcon_gpio ## port ## _res[] = { \
++ MEM_RES("gpio"#port, LTQ_GPIO ## port ## _BASE_ADDR, \
++ LTQ_GPIO ## port ## _SIZE), \
++ MEM_RES("padctrl"#port, LTQ_PADCTRL ## port ## _BASE_ADDR, \
++ LTQ_PADCTRL ## port ## _SIZE), \
++ IRQ_RES("gpio_mux"#port, FALCON_IRQ_GPIO_P ## port) \
++}
++DECLARE_GPIO_RES(0);
++DECLARE_GPIO_RES(1);
++DECLARE_GPIO_RES(2);
++DECLARE_GPIO_RES(3);
++DECLARE_GPIO_RES(4);
++
++void __init
++falcon_register_gpio(void)
++{
++ platform_device_register_simple("falcon_gpio", 0,
++ falcon_gpio0_res, ARRAY_SIZE(falcon_gpio0_res));
++ platform_device_register_simple("falcon_gpio", 1,
++ falcon_gpio1_res, ARRAY_SIZE(falcon_gpio1_res));
++ platform_device_register_simple("falcon_gpio", 2,
++ falcon_gpio2_res, ARRAY_SIZE(falcon_gpio2_res));
++ ltq_sysctl_activate(SYSCTL_SYS1, ACTS_PADCTRL1 | ACTS_P1);
++ ltq_sysctl_activate(SYSCTL_SYSETH, ACTS_PADCTRL0 |
++ ACTS_PADCTRL2 | ACTS_P0 | ACTS_P2);
++}
++
++void __init
++falcon_register_gpio_extra(void)
++{
++ platform_device_register_simple("falcon_gpio", 3,
++ falcon_gpio3_res, ARRAY_SIZE(falcon_gpio3_res));
++ platform_device_register_simple("falcon_gpio", 4,
++ falcon_gpio4_res, ARRAY_SIZE(falcon_gpio4_res));
++ ltq_sysctl_activate(SYSCTL_SYS1,
++ ACTS_PADCTRL3 | ACTS_PADCTRL4 | ACTS_P3 | ACTS_P4);
++}
+diff --git a/arch/mips/lantiq/falcon/devices.h b/arch/mips/lantiq/falcon/devices.h
+index e802a7c..18be8b6 100644
+--- a/arch/mips/lantiq/falcon/devices.h
++++ b/arch/mips/lantiq/falcon/devices.h
+@@ -14,5 +14,7 @@
+ #include "../devices.h"
+
+ extern void falcon_register_nand(void);
++extern void falcon_register_gpio(void);
++extern void falcon_register_gpio_extra(void);
+
+ #endif
+diff --git a/arch/mips/lantiq/falcon/gpio.c b/arch/mips/lantiq/falcon/gpio.c
+new file mode 100644
+index 0000000..b87582d
+--- /dev/null
++++ b/arch/mips/lantiq/falcon/gpio.c
+@@ -0,0 +1,398 @@
++/*
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ * Copyright (C) 2011 Thomas Langer <thomas.langer@lantiq.com>
++ * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
++ */
++
++#include <linux/gpio.h>
++#include <linux/interrupt.h>
++#include <linux/slab.h>
++#include <linux/platform_device.h>
++
++#include <lantiq_soc.h>
++
++/* Multiplexer Control Register */
++#define LTQ_PADC_MUX(x) (x * 0x4)
++/* Pad Control Availability Register */
++#define LTQ_PADC_AVAIL 0x000000F0
++
++/* Data Output Register */
++#define LTQ_GPIO_OUT 0x00000000
++/* Data Input Register */
++#define LTQ_GPIO_IN 0x00000004
++/* Direction Register */
++#define LTQ_GPIO_DIR 0x00000008
++/* External Interrupt Control Register 0 */
++#define LTQ_GPIO_EXINTCR0 0x00000018
++/* External Interrupt Control Register 1 */
++#define LTQ_GPIO_EXINTCR1 0x0000001C
++/* IRN Capture Register */
++#define LTQ_GPIO_IRNCR 0x00000020
++/* IRN Interrupt Configuration Register */
++#define LTQ_GPIO_IRNCFG 0x0000002C
++/* IRN Interrupt Enable Set Register */
++#define LTQ_GPIO_IRNRNSET 0x00000030
++/* IRN Interrupt Enable Clear Register */
++#define LTQ_GPIO_IRNENCLR 0x00000034
++/* Output Set Register */
++#define LTQ_GPIO_OUTSET 0x00000040
++/* Output Cler Register */
++#define LTQ_GPIO_OUTCLR 0x00000044
++/* Direction Clear Register */
++#define LTQ_GPIO_DIRSET 0x00000048
++/* Direction Set Register */
++#define LTQ_GPIO_DIRCLR 0x0000004C
++
++/* turn a gpio_chip into a falcon_gpio_port */
++#define ctop(c) container_of(c, struct falcon_gpio_port, gpio_chip)
++/* turn a irq_data into a falcon_gpio_port */
++#define itop(i) ((struct falcon_gpio_port *) irq_get_chip_data(i->irq))
++
++#define ltq_pad_r32(p, reg) ltq_r32(p->pad + reg)
++#define ltq_pad_w32(p, val, reg) ltq_w32(val, p->pad + reg)
++#define ltq_pad_w32_mask(c, clear, set, reg) \
++ ltq_pad_w32(c, (ltq_pad_r32(c, reg) & ~(clear)) | (set), reg)
++
++#define ltq_port_r32(p, reg) ltq_r32(p->port + reg)
++#define ltq_port_w32(p, val, reg) ltq_w32(val, p->port + reg)
++#define ltq_port_w32_mask(p, clear, set, reg) \
++ ltq_port_w32(p, (ltq_port_r32(p, reg) & ~(clear)) | (set), reg)
++
++#define MAX_PORTS 5
++#define PINS_PER_PORT 32
++
++struct falcon_gpio_port {
++ struct gpio_chip gpio_chip;
++ void __iomem *pad;
++ void __iomem *port;
++ unsigned int irq_base;
++ unsigned int chained_irq;
++};
++
++static struct falcon_gpio_port ltq_gpio_port[MAX_PORTS];
++
++int gpio_to_irq(unsigned int gpio)
++{
++ return __gpio_to_irq(gpio);
++}
++EXPORT_SYMBOL(gpio_to_irq);
++
++int ltq_gpio_mux_set(unsigned int pin, unsigned int mux)
++{
++ int port = pin / 100;
++ int offset = pin % 100;
++ struct falcon_gpio_port *gpio_port;
++
++ if ((offset >= PINS_PER_PORT) || (port >= MAX_PORTS))
++ return -EINVAL;
++
++ gpio_port = <q_gpio_port[port];
++ ltq_pad_w32(gpio_port, mux & 0x3, LTQ_PADC_MUX(offset));
++
++ return 0;
++}
++EXPORT_SYMBOL(ltq_gpio_mux_set);
++
++int ltq_gpio_request(unsigned int pin, unsigned int val,
++ unsigned int dir, const char *name)
++{
++ int port = pin / 100;
++ int offset = pin % 100;
++
++ if (offset >= PINS_PER_PORT || port >= MAX_PORTS)
++ return -EINVAL;
++
++ if (gpio_request(pin, name)) {
++ pr_err("failed to setup lantiq gpio: %s\n", name);
++ return -EBUSY;
++ }
++
++ if (dir)
++ gpio_direction_output(pin, 1);
++ else
++ gpio_direction_input(pin);
++
++ return ltq_gpio_mux_set(pin, val);
++}
++EXPORT_SYMBOL(ltq_gpio_request);
++
++static int
++falcon_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
++{
++ ltq_port_w32(ctop(chip), 1 << offset, LTQ_GPIO_DIRCLR);
++
++ return 0;
++}
++
++static void
++falcon_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
++{
++ if (value)
++ ltq_port_w32(ctop(chip), 1 << offset, LTQ_GPIO_OUTSET);
++ else
++ ltq_port_w32(ctop(chip), 1 << offset, LTQ_GPIO_OUTCLR);
++}
++
++static int
++falcon_gpio_direction_output(struct gpio_chip *chip,
++ unsigned int offset, int value)
++{
++ falcon_gpio_set(chip, offset, value);
++ ltq_port_w32(ctop(chip), 1 << offset, LTQ_GPIO_DIRSET);
++
++ return 0;
++}
++
++static int
++falcon_gpio_get(struct gpio_chip *chip, unsigned int offset)
++{
++ if ((ltq_port_r32(ctop(chip), LTQ_GPIO_DIR) >> offset) & 1)
++ return (ltq_port_r32(ctop(chip), LTQ_GPIO_OUT) >> offset) & 1;
++ else
++ return (ltq_port_r32(ctop(chip), LTQ_GPIO_IN) >> offset) & 1;
++}
++
++static int
++falcon_gpio_request(struct gpio_chip *chip, unsigned offset)
++{
++ if ((ltq_pad_r32(ctop(chip), LTQ_PADC_AVAIL) >> offset) & 1) {
++ if (ltq_pad_r32(ctop(chip), LTQ_PADC_MUX(offset)) > 1)
++ return -EBUSY;
++ /* switch on gpio function */
++ ltq_pad_w32(ctop(chip), 1, LTQ_PADC_MUX(offset));
++ return 0;
++ }
++
++ return -ENODEV;
++}
++
++static void
++falcon_gpio_free(struct gpio_chip *chip, unsigned offset)
++{
++ if ((ltq_pad_r32(ctop(chip), LTQ_PADC_AVAIL) >> offset) & 1) {
++ if (ltq_pad_r32(ctop(chip), LTQ_PADC_MUX(offset)) > 1)
++ return;
++ /* switch off gpio function */
++ ltq_pad_w32(ctop(chip), 0, LTQ_PADC_MUX(offset));
++ }
++}
++
++static int
++falcon_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
++{
++ return ctop(chip)->irq_base + offset;
++}
++
++static void
++falcon_gpio_disable_irq(struct irq_data *d)
++{
++ unsigned int offset = d->irq - itop(d)->irq_base;
++
++ ltq_port_w32(itop(d), 1 << offset, LTQ_GPIO_IRNENCLR);
++}
++
++static void
++falcon_gpio_enable_irq(struct irq_data *d)
++{
++ unsigned int offset = d->irq - itop(d)->irq_base;
++
++ if (!ltq_pad_r32(itop(d), LTQ_PADC_MUX(offset)) < 1)
++ /* switch on gpio function */
++ ltq_pad_w32(itop(d), 1, LTQ_PADC_MUX(offset));
++
++ ltq_port_w32(itop(d), 1 << offset, LTQ_GPIO_IRNRNSET);
++}
++
++static void
++falcon_gpio_ack_irq(struct irq_data *d)
++{
++ unsigned int offset = d->irq - itop(d)->irq_base;
++
++ ltq_port_w32(itop(d), 1 << offset, LTQ_GPIO_IRNCR);
++}
++
++static void
++falcon_gpio_mask_and_ack_irq(struct irq_data *d)
++{
++ unsigned int offset = d->irq - itop(d)->irq_base;
++
++ ltq_port_w32(itop(d), 1 << offset, LTQ_GPIO_IRNENCLR);
++ ltq_port_w32(itop(d), 1 << offset, LTQ_GPIO_IRNCR);
++}
++
++static struct irq_chip falcon_gpio_irq_chip;
++static int
++falcon_gpio_irq_type(struct irq_data *d, unsigned int type)
++{
++ unsigned int offset = d->irq - itop(d)->irq_base;
++ unsigned int mask = 1 << offset;
++
++ if ((type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_NONE)
++ return 0;
++
++ if ((type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) != 0) {
++ /* level triggered */
++ ltq_port_w32_mask(itop(d), 0, mask, LTQ_GPIO_IRNCFG);
++ irq_set_chip_and_handler_name(d->irq,
++ &falcon_gpio_irq_chip, handle_level_irq, "mux");
++ } else {
++ /* edge triggered */
++ ltq_port_w32_mask(itop(d), mask, 0, LTQ_GPIO_IRNCFG);
++ irq_set_chip_and_handler_name(d->irq,
++ &falcon_gpio_irq_chip, handle_simple_irq, "mux");
++ }
++
++ if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
++ ltq_port_w32_mask(itop(d), mask, 0, LTQ_GPIO_EXINTCR0);
++ ltq_port_w32_mask(itop(d), 0, mask, LTQ_GPIO_EXINTCR1);
++ } else {
++ if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH)) != 0)
++ /* positive logic: rising edge, high level */
++ ltq_port_w32_mask(itop(d), mask, 0, LTQ_GPIO_EXINTCR0);
++ else
++ /* negative logic: falling edge, low level */
++ ltq_port_w32_mask(itop(d), 0, mask, LTQ_GPIO_EXINTCR0);
++ ltq_port_w32_mask(itop(d), mask, 0, LTQ_GPIO_EXINTCR1);
++ }
++
++ return gpio_direction_input(itop(d)->gpio_chip.base + offset);
++}
++
++static void
++falcon_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
++{
++ struct falcon_gpio_port *gpio_port = irq_desc_get_handler_data(desc);
++ unsigned long irncr;
++ int offset;
++
++ /* acknowledge interrupt */
++ irncr = ltq_port_r32(gpio_port, LTQ_GPIO_IRNCR);
++ ltq_port_w32(gpio_port, irncr, LTQ_GPIO_IRNCR);
++
++ desc->irq_data.chip->irq_ack(&desc->irq_data);
++
++ for_each_set_bit(offset, &irncr, gpio_port->gpio_chip.ngpio)
++ generic_handle_irq(gpio_port->irq_base + offset);
++}
++
++static struct irq_chip falcon_gpio_irq_chip = {
++ .name = "gpio_irq_mux",
++ .irq_mask = falcon_gpio_disable_irq,
++ .irq_unmask = falcon_gpio_enable_irq,
++ .irq_ack = falcon_gpio_ack_irq,
++ .irq_mask_ack = falcon_gpio_mask_and_ack_irq,
++ .irq_set_type = falcon_gpio_irq_type,
++};
++
++static struct irqaction gpio_cascade = {
++ .handler = no_action,
++ .flags = IRQF_DISABLED,
++ .name = "gpio_cascade",
++};
++
++static int
++falcon_gpio_probe(struct platform_device *pdev)
++{
++ struct falcon_gpio_port *gpio_port;
++ int ret, i;
++ struct resource *gpiores, *padres;
++ int irq;
++
++ if (pdev->id >= MAX_PORTS)
++ return -ENODEV;
++
++ gpiores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ padres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ irq = platform_get_irq(pdev, 0);
++ if (!gpiores || !padres)
++ return -ENODEV;
++
++ gpio_port = <q_gpio_port[pdev->id];
++ gpio_port->gpio_chip.label = "falcon-gpio";
++ gpio_port->gpio_chip.direction_input = falcon_gpio_direction_input;
++ gpio_port->gpio_chip.direction_output = falcon_gpio_direction_output;
++ gpio_port->gpio_chip.get = falcon_gpio_get;
++ gpio_port->gpio_chip.set = falcon_gpio_set;
++ gpio_port->gpio_chip.request = falcon_gpio_request;
++ gpio_port->gpio_chip.free = falcon_gpio_free;
++ gpio_port->gpio_chip.base = 100 * pdev->id;
++ gpio_port->gpio_chip.ngpio = 32;
++ gpio_port->gpio_chip.dev = &pdev->dev;
++
++ gpio_port->port = ltq_remap_resource(gpiores);
++ gpio_port->pad = ltq_remap_resource(padres);
++
++ if (!gpio_port->port || !gpio_port->pad) {
++ dev_err(&pdev->dev, "Could not map io ranges\n");
++ ret = -ENOMEM;
++ goto err;
++ }
++
++ if (irq > 0) {
++ /* irq_chip support */
++ gpio_port->gpio_chip.to_irq = falcon_gpio_to_irq;
++ gpio_port->irq_base = INT_NUM_EXTRA_START + (32 * pdev->id);
++
++ for (i = 0; i < 32; i++) {
++ irq_set_chip_and_handler_name(gpio_port->irq_base + i,
++ &falcon_gpio_irq_chip, handle_simple_irq,
++ "mux");
++ irq_set_chip_data(gpio_port->irq_base + i, gpio_port);
++ /* set to negative logic (falling edge, low level) */
++ ltq_port_w32_mask(gpio_port, 0, 1 << i,
++ LTQ_GPIO_EXINTCR0);
++ }
++
++ gpio_port->chained_irq = irq;
++ setup_irq(irq, &gpio_cascade);
++ irq_set_handler_data(irq, gpio_port);
++ irq_set_chained_handler(irq, falcon_gpio_irq_handler);
++ }
++
++ ret = gpiochip_add(&gpio_port->gpio_chip);
++ if (ret < 0) {
++ dev_err(&pdev->dev, "Could not register gpiochip %d, %d\n",
++ pdev->id, ret);
++ goto err;
++ }
++ platform_set_drvdata(pdev, gpio_port);
++ return ret;
++
++err:
++ dev_err(&pdev->dev, "Error in gpio_probe %d, %d\n", pdev->id, ret);
++ if (gpiores)
++ release_resource(gpiores);
++ if (padres)
++ release_resource(padres);
++
++ if (gpio_port->port)
++ iounmap(gpio_port->port);
++ if (gpio_port->pad)
++ iounmap(gpio_port->pad);
++ return ret;
++}
++
++static struct platform_driver falcon_gpio_driver = {
++ .probe = falcon_gpio_probe,
++ .driver = {
++ .name = "falcon_gpio",
++ .owner = THIS_MODULE,
++ },
++};
++
++int __init
++falcon_gpio_init(void)
++{
++ int ret;
++
++ pr_info("FALC(tm) ON GPIO Driver, (C) 2011 Lantiq Deutschland Gmbh\n");
++ ret = platform_driver_register(&falcon_gpio_driver);
++ if (ret)
++ pr_err("falcon_gpio: Error registering platform driver!");
++ return ret;
++}
++
++postcore_initcall(falcon_gpio_init);
+--
+1.7.5.4
+
--- /dev/null
+From ec6ba0f79c010a878d679c057fb6306b50a201b0 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Thu, 11 Aug 2011 14:09:35 +0200
+Subject: [PATCH 08/24] MIPS: lantiq: add support for the EASY98000 evaluation
+ board
+
+This patch adds the machine code for the EASY9800 evaluation board.
+
+Signed-off-by: Thomas Langer <thomas.langer@lantiq.com>
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Cc: linux-mips@linux-mips.org
+---
+ arch/mips/lantiq/falcon/Kconfig | 11 +++
+ arch/mips/lantiq/falcon/Makefile | 1 +
+ arch/mips/lantiq/falcon/mach-easy98000.c | 110 ++++++++++++++++++++++++++++++
+ arch/mips/lantiq/machtypes.h | 5 ++
+ 4 files changed, 127 insertions(+), 0 deletions(-)
+ create mode 100644 arch/mips/lantiq/falcon/Kconfig
+ create mode 100644 arch/mips/lantiq/falcon/mach-easy98000.c
+
+diff --git a/arch/mips/lantiq/falcon/Kconfig b/arch/mips/lantiq/falcon/Kconfig
+new file mode 100644
+index 0000000..03e999d
+--- /dev/null
++++ b/arch/mips/lantiq/falcon/Kconfig
+@@ -0,0 +1,11 @@
++if SOC_FALCON
++
++menu "MIPS Machine"
++
++config LANTIQ_MACH_EASY98000
++ bool "Easy98000"
++ default y
++
++endmenu
++
++endif
+diff --git a/arch/mips/lantiq/falcon/Makefile b/arch/mips/lantiq/falcon/Makefile
+index de72209..56b22eb 100644
+--- a/arch/mips/lantiq/falcon/Makefile
++++ b/arch/mips/lantiq/falcon/Makefile
+@@ -1 +1,2 @@
+ obj-y := clk.o prom.o reset.o sysctrl.o devices.o gpio.o
++obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o
+diff --git a/arch/mips/lantiq/falcon/mach-easy98000.c b/arch/mips/lantiq/falcon/mach-easy98000.c
+new file mode 100644
+index 0000000..361b8f0
+--- /dev/null
++++ b/arch/mips/lantiq/falcon/mach-easy98000.c
+@@ -0,0 +1,110 @@
++/*
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ * Copyright (C) 2011 Thomas Langer <thomas.langer@lantiq.com>
++ * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
++ */
++
++#include <linux/platform_device.h>
++#include <linux/mtd/partitions.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/spi_gpio.h>
++#include <linux/spi/eeprom.h>
++
++#include "../machtypes.h"
++
++#include "devices.h"
++
++static struct mtd_partition easy98000_nor_partitions[] = {
++ {
++ .name = "uboot",
++ .offset = 0x0,
++ .size = 0x40000,
++ },
++ {
++ .name = "uboot_env",
++ .offset = 0x40000,
++ .size = 0x40000, /* 2 sectors for redundant env. */
++ },
++ {
++ .name = "linux",
++ .offset = 0x80000,
++ .size = 0xF80000, /* map only 16 MiB */
++ },
++};
++
++struct physmap_flash_data easy98000_nor_flash_data = {
++ .nr_parts = ARRAY_SIZE(easy98000_nor_partitions),
++ .parts = easy98000_nor_partitions,
++};
++
++/* setup gpio based spi bus/device for access to the eeprom on the board */
++#define SPI_GPIO_MRST 102
++#define SPI_GPIO_MTSR 103
++#define SPI_GPIO_CLK 104
++#define SPI_GPIO_CS0 105
++#define SPI_GPIO_CS1 106
++#define SPI_GPIO_BUS_NUM 1
++
++static struct spi_gpio_platform_data easy98000_spi_gpio_data = {
++ .sck = SPI_GPIO_CLK,
++ .mosi = SPI_GPIO_MTSR,
++ .miso = SPI_GPIO_MRST,
++ .num_chipselect = 2,
++};
++
++static struct platform_device easy98000_spi_gpio_device = {
++ .name = "spi_gpio",
++ .id = SPI_GPIO_BUS_NUM,
++ .dev.platform_data = &easy98000_spi_gpio_data,
++};
++
++static struct spi_eeprom at25160n = {
++ .byte_len = 16 * 1024 / 8,
++ .name = "at25160n",
++ .page_size = 32,
++ .flags = EE_ADDR2,
++};
++
++static struct spi_board_info easy98000_spi_gpio_devices __initdata = {
++ .modalias = "at25",
++ .bus_num = SPI_GPIO_BUS_NUM,
++ .max_speed_hz = 1000 * 1000,
++ .mode = SPI_MODE_3,
++ .chip_select = 1,
++ .controller_data = (void *) SPI_GPIO_CS1,
++ .platform_data = &at25160n,
++};
++
++static void __init
++easy98000_init_common(void)
++{
++ spi_register_board_info(&easy98000_spi_gpio_devices, 1);
++ platform_device_register(&easy98000_spi_gpio_device);
++}
++
++static void __init
++easy98000_init(void)
++{
++ easy98000_init_common();
++ ltq_register_nor(&easy98000_nor_flash_data);
++}
++
++static void __init
++easy98000nand_init(void)
++{
++ easy98000_init_common();
++ falcon_register_nand();
++}
++
++MIPS_MACHINE(LANTIQ_MACH_EASY98000,
++ "EASY98000",
++ "EASY98000 Eval Board",
++ easy98000_init);
++
++MIPS_MACHINE(LANTIQ_MACH_EASY98000NAND,
++ "EASY98000NAND",
++ "EASY98000 Eval Board (NAND Flash)",
++ easy98000nand_init);
+diff --git a/arch/mips/lantiq/machtypes.h b/arch/mips/lantiq/machtypes.h
+index 7e01b8c..dfc6af7 100644
+--- a/arch/mips/lantiq/machtypes.h
++++ b/arch/mips/lantiq/machtypes.h
+@@ -15,6 +15,11 @@ enum lantiq_mach_type {
+ LTQ_MACH_GENERIC = 0,
+ LTQ_MACH_EASY50712, /* Danube evaluation board */
+ LTQ_MACH_EASY50601, /* Amazon SE evaluation board */
++
++ /* FALCON */
++ LANTIQ_MACH_EASY98000, /* Falcon Eval Board, NOR Flash */
++ LANTIQ_MACH_EASY98000SF, /* Falcon Eval Board, Serial Flash */
++ LANTIQ_MACH_EASY98000NAND, /* Falcon Eval Board, NAND Flash */
+ };
+
+ #endif
+--
+1.7.5.4
+
--- /dev/null
+From 88bb1794592e3fe9c8d65ce73ee851e11dbbd26b Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Wed, 24 Aug 2011 13:24:11 +0200
+Subject: [PATCH 09/24] MIPS: make oprofile use cp0_perfcount_irq if it is set
+
+The patch makes the oprofile code use the performance counters irq.
+
+This patch is written by Felix Fietkau.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Cc: linux-mips@linux-mips.org
+---
+ arch/mips/oprofile/op_model_mipsxx.c | 12 ++++++++++++
+ 1 files changed, 12 insertions(+), 0 deletions(-)
+
+diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c
+index 54759f1..86cf234 100644
+--- a/arch/mips/oprofile/op_model_mipsxx.c
++++ b/arch/mips/oprofile/op_model_mipsxx.c
+@@ -298,6 +298,11 @@ static void reset_counters(void *arg)
+ }
+ }
+
++static irqreturn_t mipsxx_perfcount_int(int irq, void *dev_id)
++{
++ return mipsxx_perfcount_handler();
++}
++
+ static int __init mipsxx_init(void)
+ {
+ int counters;
+@@ -374,6 +379,10 @@ static int __init mipsxx_init(void)
+ save_perf_irq = perf_irq;
+ perf_irq = mipsxx_perfcount_handler;
+
++ if (cp0_perfcount_irq >= 0)
++ return request_irq(cp0_perfcount_irq, mipsxx_perfcount_int,
++ IRQF_SHARED, "Perfcounter", save_perf_irq);
++
+ return 0;
+ }
+
+@@ -381,6 +390,9 @@ static void mipsxx_exit(void)
+ {
+ int counters = op_model_mipsxx_ops.num_counters;
+
++ if (cp0_perfcount_irq >= 0)
++ free_irq(cp0_perfcount_irq, save_perf_irq);
++
+ counters = counters_per_cpu_to_total(counters);
+ on_each_cpu(reset_counters, (void *)(long)counters, 1);
+
+--
+1.7.5.4
+
--- /dev/null
+From cc4b9cdff8665a414ae51101d3a0ca6ed7444a27 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Wed, 24 Aug 2011 13:28:55 +0200
+Subject: [PATCH 10/24] MIPS: enable oprofile support on lantiq targets
+
+This patch sets the performance counters irq and HAVE_OPROFILE flag.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Cc: linux-mips@linux-mips.org
+---
+ arch/mips/Kconfig | 1 +
+ arch/mips/lantiq/irq.c | 5 +++++
+ 2 files changed, 6 insertions(+), 0 deletions(-)
+
+diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
+index b122adc..0cf5bbd 100644
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -230,6 +230,7 @@ config LANTIQ
+ select SWAP_IO_SPACE
+ select BOOT_RAW
+ select HAVE_CLK
++ select HAVE_OPROFILE
+ select MIPS_MACHINE
+
+ config LASAT
+diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c
+index 17c057f..0b2ed87 100644
+--- a/arch/mips/lantiq/irq.c
++++ b/arch/mips/lantiq/irq.c
+@@ -40,6 +40,9 @@
+
+ #define MAX_EIU 6
+
++/* the performance counter */
++#define LTQ_PERF_IRQ (INT_NUM_IM4_IRL0 + 31)
++
+ /* irqs generated by device attached to the EBU need to be acked in
+ * a special manner
+ */
+@@ -318,6 +321,8 @@ void __init arch_init_irq(void)
+ set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ0 | IE_IRQ1 |
+ IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5);
+ #endif
++
++ cp0_perfcount_irq = LTQ_PERF_IRQ;
+ }
+
+ unsigned int __cpuinit get_c0_compare_int(void)
+--
+1.7.5.4
+
--- /dev/null
+From 6437f41dfdf9475178e22ab0dd886af033f90cc2 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Thu, 29 Sep 2011 21:10:16 +0200
+Subject: [PATCH 11/24] MIPS: lantiq: adds falcon I2C
+
+---
+ arch/mips/lantiq/falcon/devices.c | 21 +
+ arch/mips/lantiq/falcon/devices.h | 1 +
+ drivers/i2c/busses/Kconfig | 4 +
+ drivers/i2c/busses/Makefile | 1 +
+ drivers/i2c/busses/i2c-falcon.c | 815 +++++++++++++++++++++++++++++++++++++
+ 5 files changed, 842 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/i2c/busses/i2c-falcon.c
+
+diff --git a/arch/mips/lantiq/falcon/devices.c b/arch/mips/lantiq/falcon/devices.c
+index 4f47b44..a998b6b 100644
+--- a/arch/mips/lantiq/falcon/devices.c
++++ b/arch/mips/lantiq/falcon/devices.c
+@@ -126,3 +126,24 @@ falcon_register_gpio_extra(void)
+ ltq_sysctl_activate(SYSCTL_SYS1,
+ ACTS_PADCTRL3 | ACTS_PADCTRL4 | ACTS_P3 | ACTS_P4);
+ }
++
++/* i2c */
++static struct resource falcon_i2c_resources[] = {
++ MEM_RES("i2c", GPON_I2C_BASE,GPON_I2C_END),
++ IRQ_RES("i2c_lb", FALCON_IRQ_I2C_LBREQ),
++ IRQ_RES("i2c_b", FALCON_IRQ_I2C_BREQ),
++ IRQ_RES("i2c_err", FALCON_IRQ_I2C_I2C_ERR),
++ IRQ_RES("i2c_p", FALCON_IRQ_I2C_I2C_P),
++};
++
++void __init falcon_register_i2c(void)
++{
++ platform_device_register_simple("i2c-falcon", 0,
++ falcon_i2c_resources, ARRAY_SIZE(falcon_i2c_resources));
++ sys1_hw_activate(ACTS_I2C_ACT);
++}
++
++void __init falcon_register_crypto(void)
++{
++ platform_device_register_simple("ltq_falcon_deu", 0, NULL, 0);
++}
+diff --git a/arch/mips/lantiq/falcon/devices.h b/arch/mips/lantiq/falcon/devices.h
+index 18be8b6..2fdcb08 100644
+--- a/arch/mips/lantiq/falcon/devices.h
++++ b/arch/mips/lantiq/falcon/devices.h
+@@ -16,5 +16,6 @@
+ extern void falcon_register_nand(void);
+ extern void falcon_register_gpio(void);
+ extern void falcon_register_gpio_extra(void);
++extern void falcon_register_i2c(void);
+
+ #endif
+diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
+index 646068e..e6c3ab6 100644
+--- a/drivers/i2c/busses/Kconfig
++++ b/drivers/i2c/busses/Kconfig
+@@ -284,6 +284,10 @@ config I2C_POWERMAC
+
+ comment "I2C system bus drivers (mostly embedded / system-on-chip)"
+
++config I2C_FALCON
++ tristate "Falcon I2C interface"
++# depends on SOC_FALCON
++
+ config I2C_AT91
+ tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
+ depends on ARCH_AT91 && EXPERIMENTAL && BROKEN
+diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
+index e6cf294..83e9250 100644
+--- a/drivers/i2c/busses/Makefile
++++ b/drivers/i2c/busses/Makefile
+@@ -82,5 +82,6 @@ obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
+ obj-$(CONFIG_I2C_STUB) += i2c-stub.o
+ obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
+ obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
++obj-$(CONFIG_I2C_FALCON) += i2c-falcon.o
+
+ ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
+diff --git a/drivers/i2c/busses/i2c-falcon.c b/drivers/i2c/busses/i2c-falcon.c
+new file mode 100644
+index 0000000..7bb1253
+--- /dev/null
++++ b/drivers/i2c/busses/i2c-falcon.c
+@@ -0,0 +1,815 @@
++/*
++ * Lantiq FALC(tm) ON - I2C bus adapter
++ *
++ * Parts based on i2c-designware.c and other i2c drivers from Linux 2.6.33
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++/* #define DEBUG */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/slab.h> /* for kzalloc, kfree */
++#include <linux/i2c.h>
++#include <linux/clk.h>
++#include <linux/errno.h>
++#include <linux/sched.h>
++#include <linux/err.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/gpio.h>
++
++#include <falcon/lantiq_soc.h>
++
++/* CURRENT ISSUES:
++ * - no high speed support
++ * - supports only master mode
++ * - ten bit mode is not tested (no slave devices)
++ */
++
++/* mapping for access macros */
++#define reg_r32(reg) __raw_readl(reg)
++#define reg_w32(val, reg) __raw_writel(val, reg)
++#define reg_w32_mask(clear, set, reg) \
++ reg_w32((reg_r32(reg) & ~(clear)) | (set), reg)
++#define reg_r32_table(reg, idx) reg_r32(&((uint32_t *)®)[idx])
++#define reg_w32_table(val, reg, idx) reg_w32(val, &((uint32_t *)®)[idx])
++#define i2c (priv->membase)
++#include <falcon/i2c_reg.h>
++
++#define DRV_NAME "i2c-falcon"
++#define DRV_VERSION "1.01"
++
++#define FALCON_I2C_BUSY_TIMEOUT 20 /* ms */
++
++#ifdef DEBUG
++#define FALCON_I2C_XFER_TIMEOUT 25*HZ
++#else
++#define FALCON_I2C_XFER_TIMEOUT HZ
++#endif
++#if defined(DEBUG) && 0
++#define PRINTK(arg...) printk(arg)
++#else
++#define PRINTK(arg...) do {} while (0)
++#endif
++
++#define FALCON_I2C_IMSC_DEFAULT_MASK (I2C_IMSC_I2C_P_INT_EN | \
++ I2C_IMSC_I2C_ERR_INT_EN)
++
++#define FALCON_I2C_ARB_LOST (1 << 0)
++#define FALCON_I2C_NACK (1 << 1)
++#define FALCON_I2C_RX_UFL (1 << 2)
++#define FALCON_I2C_RX_OFL (1 << 3)
++#define FALCON_I2C_TX_UFL (1 << 4)
++#define FALCON_I2C_TX_OFL (1 << 5)
++
++struct falcon_i2c {
++ struct mutex mutex;
++
++ enum {
++ FALCON_I2C_MODE_100 = 1,
++ FALCON_I2C_MODE_400 = 2,
++ FALCON_I2C_MODE_3400 = 3
++ } mode; /* current speed mode */
++
++ struct clk *clk; /* clock input for i2c hardware block */
++ struct gpon_reg_i2c __iomem *membase; /* base of mapped registers */
++ int irq_lb, irq_b, irq_err, irq_p; /* last burst, burst, error,
++ protocol IRQs */
++
++ struct i2c_adapter adap;
++ struct device *dev;
++
++ struct completion cmd_complete;
++
++ /* message transfer data */
++ /* current message */
++ struct i2c_msg *current_msg;
++ /* number of messages to handle */
++ int msgs_num;
++ /* current buffer */
++ u8 *msg_buf;
++ /* remaining length of current buffer */
++ u32 msg_buf_len;
++ /* error status of the current transfer */
++ int msg_err;
++
++ /* master status codes */
++ enum {
++ STATUS_IDLE,
++ STATUS_ADDR, /* address phase */
++ STATUS_WRITE,
++ STATUS_READ,
++ STATUS_READ_END,
++ STATUS_STOP
++ } status;
++};
++
++static irqreturn_t falcon_i2c_isr(int irq, void *dev_id);
++
++static inline void enable_burst_irq(struct falcon_i2c *priv)
++{
++ i2c_w32_mask(0, I2C_IMSC_LBREQ_INT_EN | I2C_IMSC_BREQ_INT_EN, imsc);
++}
++static inline void disable_burst_irq(struct falcon_i2c *priv)
++{
++ i2c_w32_mask(I2C_IMSC_LBREQ_INT_EN | I2C_IMSC_BREQ_INT_EN, 0, imsc);
++}
++
++static void prepare_msg_send_addr(struct falcon_i2c *priv)
++{
++ struct i2c_msg *msg = priv->current_msg;
++ int rd = !!(msg->flags & I2C_M_RD); /* extends to 0 or 1 */
++ u16 addr = msg->addr;
++
++ /* new i2c_msg */
++ priv->msg_buf = msg->buf;
++ priv->msg_buf_len = msg->len;
++ if (rd)
++ priv->status = STATUS_READ;
++ else
++ priv->status = STATUS_WRITE;
++
++ /* send slave address */
++ if (msg->flags & I2C_M_TEN) {
++ i2c_w32(0xf0 | ((addr & 0x300) >> 7) | rd, txd);
++ i2c_w32(addr & 0xff, txd);
++ } else
++ i2c_w32((addr & 0x7f) << 1 | rd, txd);
++}
++
++static void set_tx_len(struct falcon_i2c *priv)
++{
++ struct i2c_msg *msg = priv->current_msg;
++ int len = (msg->flags & I2C_M_TEN) ? 2 : 1;
++
++ PRINTK("set_tx_len %cX\n", (msg->flags & I2C_M_RD)?'R':'T');
++
++ priv->status = STATUS_ADDR;
++
++ if (!(msg->flags & I2C_M_RD)) {
++ len += msg->len;
++ } else {
++ /* set maximum received packet size (before rx int!) */
++ i2c_w32(msg->len, mrps_ctrl);
++ }
++ i2c_w32(len, tps_ctrl);
++ enable_burst_irq(priv);
++}
++
++static int falcon_i2c_hw_init(struct i2c_adapter *adap)
++{
++ struct falcon_i2c *priv = i2c_get_adapdata(adap);
++
++ /* disable bus */
++ i2c_w32_mask(I2C_RUN_CTRL_RUN_EN, 0, run_ctrl);
++
++#ifndef DEBUG
++ /* set normal operation clock divider */
++ i2c_w32(1 << I2C_CLC_RMC_OFFSET, clc);
++#else
++ /* for debugging a higher divider value! */
++ i2c_w32(0xF0 << I2C_CLC_RMC_OFFSET, clc);
++#endif
++
++ /* set frequency */
++ if (priv->mode == FALCON_I2C_MODE_100) {
++ dev_dbg(priv->dev, "set standard mode (100 kHz)\n");
++ i2c_w32(0, fdiv_high_cfg);
++ i2c_w32((1 << I2C_FDIV_CFG_INC_OFFSET) |
++ (499 << I2C_FDIV_CFG_DEC_OFFSET),
++ fdiv_cfg);
++ } else if (priv->mode == FALCON_I2C_MODE_400) {
++ dev_dbg(priv->dev, "set fast mode (400 kHz)\n");
++ i2c_w32(0, fdiv_high_cfg);
++ i2c_w32((1 << I2C_FDIV_CFG_INC_OFFSET) |
++ (124 << I2C_FDIV_CFG_DEC_OFFSET),
++ fdiv_cfg);
++ } else if (priv->mode == FALCON_I2C_MODE_3400) {
++ dev_dbg(priv->dev, "set high mode (3.4 MHz)\n");
++ i2c_w32(0, fdiv_cfg);
++ /* TODO recalculate value for 100MHz input */
++ i2c_w32((41 << I2C_FDIV_HIGH_CFG_INC_OFFSET) |
++ (152 << I2C_FDIV_HIGH_CFG_DEC_OFFSET),
++ fdiv_high_cfg);
++ } else {
++ dev_warn(priv->dev, "unknown mode\n");
++ return -ENODEV;
++ }
++
++ /* configure fifo */
++ i2c_w32(I2C_FIFO_CFG_TXFC | /* tx fifo as flow controller */
++ I2C_FIFO_CFG_RXFC | /* rx fifo as flow controller */
++ I2C_FIFO_CFG_TXFA_TXFA2 | /* tx fifo 4-byte aligned */
++ I2C_FIFO_CFG_RXFA_RXFA2 | /* rx fifo 4-byte aligned */
++ I2C_FIFO_CFG_TXBS_TXBS0 | /* tx fifo burst size is 1 word */
++ I2C_FIFO_CFG_RXBS_RXBS0, /* rx fifo burst size is 1 word */
++ fifo_cfg);
++
++ /* configure address */
++ i2c_w32(I2C_ADDR_CFG_SOPE_EN | /* generate stop when no more data in the
++ fifo */
++ I2C_ADDR_CFG_SONA_EN | /* generate stop when NA received */
++ I2C_ADDR_CFG_MnS_EN | /* we are master device */
++ 0, /* our slave address (not used!) */
++ addr_cfg);
++
++ /* enable bus */
++ i2c_w32_mask(0, I2C_RUN_CTRL_RUN_EN, run_ctrl);
++
++ return 0;
++}
++
++static int falcon_i2c_wait_bus_not_busy(struct falcon_i2c *priv)
++{
++ int timeout = FALCON_I2C_BUSY_TIMEOUT;
++
++ while ((i2c_r32(bus_stat) & I2C_BUS_STAT_BS_MASK)
++ != I2C_BUS_STAT_BS_FREE) {
++ if (timeout <= 0) {
++ dev_warn(priv->dev, "timeout waiting for bus ready\n");
++ return -ETIMEDOUT;
++ }
++ timeout--;
++ mdelay(1);
++ }
++
++ return 0;
++}
++
++static void falcon_i2c_tx(struct falcon_i2c *priv, int last)
++{
++ if (priv->msg_buf_len && priv->msg_buf) {
++ i2c_w32(*priv->msg_buf, txd);
++
++ if (--priv->msg_buf_len)
++ priv->msg_buf++;
++ else
++ priv->msg_buf = NULL;
++ } else
++ last = 1;
++
++ if (last) {
++ disable_burst_irq(priv);
++ }
++}
++
++static void falcon_i2c_rx(struct falcon_i2c *priv, int last)
++{
++ u32 fifo_stat,timeout;
++ if (priv->msg_buf_len && priv->msg_buf) {
++ timeout = 5000000;
++ do {
++ fifo_stat = i2c_r32(ffs_stat);
++ } while (!fifo_stat && --timeout);
++ if (!timeout) {
++ last = 1;
++ PRINTK("\nrx timeout\n");
++ goto err;
++ }
++ while (fifo_stat) {
++ *priv->msg_buf = i2c_r32(rxd);
++ if (--priv->msg_buf_len)
++ priv->msg_buf++;
++ else {
++ priv->msg_buf = NULL;
++ last = 1;
++ break;
++ }
++ #if 0
++ fifo_stat = i2c_r32(ffs_stat);
++ #else
++ /* do not read more than burst size, otherwise no "last
++ burst" is generated and the transaction is blocked! */
++ fifo_stat = 0;
++ #endif
++ }
++ } else {
++ last = 1;
++ }
++err:
++ if (last) {
++ disable_burst_irq(priv);
++
++ if (priv->status == STATUS_READ_END) {
++ /* do the STATUS_STOP and complete() here, as sometimes
++ the tx_end is already seen before this is finished */
++ priv->status = STATUS_STOP;
++ complete(&priv->cmd_complete);
++ } else {
++ i2c_w32(I2C_ENDD_CTRL_SETEND, endd_ctrl);
++ priv->status = STATUS_READ_END;
++ }
++ }
++}
++
++static void falcon_i2c_xfer_init(struct falcon_i2c *priv)
++{
++ /* enable interrupts */
++ i2c_w32(FALCON_I2C_IMSC_DEFAULT_MASK, imsc);
++
++ /* trigger transfer of first msg */
++ set_tx_len(priv);
++}
++
++static void dump_msgs(struct i2c_msg msgs[], int num, int rx)
++{
++#if defined(DEBUG)
++ int i, j;
++ printk("Messages %d %s\n", num, rx ? "out" : "in");
++ for (i = 0; i < num; i++) {
++ printk("%2d %cX Msg(%d) addr=0x%X: ", i,
++ (msgs[i].flags & I2C_M_RD)?'R':'T',
++ msgs[i].len, msgs[i].addr);
++ if (!(msgs[i].flags & I2C_M_RD) || rx) {
++ for (j = 0; j < msgs[i].len; j++)
++ printk("%02X ", msgs[i].buf[j]);
++ }
++ printk("\n");
++ }
++#endif
++}
++
++static void falcon_i2c_release_bus(struct falcon_i2c *priv)
++{
++ if ((i2c_r32(bus_stat) & I2C_BUS_STAT_BS_MASK) == I2C_BUS_STAT_BS_BM)
++ i2c_w32(I2C_ENDD_CTRL_SETEND, endd_ctrl);
++}
++
++static int falcon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
++ int num)
++{
++ struct falcon_i2c *priv = i2c_get_adapdata(adap);
++ int ret;
++
++ dev_dbg(priv->dev, "xfer %u messages\n", num);
++ dump_msgs(msgs, num, 0);
++
++ mutex_lock(&priv->mutex);
++
++ INIT_COMPLETION(priv->cmd_complete);
++ priv->current_msg = msgs;
++ priv->msgs_num = num;
++ priv->msg_err = 0;
++ priv->status = STATUS_IDLE;
++
++ /* wait for the bus to become ready */
++ ret = falcon_i2c_wait_bus_not_busy(priv);
++ if (ret)
++ goto done;
++
++ while (priv->msgs_num) {
++ /* start the transfers */
++ falcon_i2c_xfer_init(priv);
++
++ /* wait for transfers to complete */
++ ret = wait_for_completion_interruptible_timeout(
++ &priv->cmd_complete, FALCON_I2C_XFER_TIMEOUT);
++ if (ret == 0) {
++ dev_err(priv->dev, "controller timed out\n");
++ falcon_i2c_hw_init(adap);
++ ret = -ETIMEDOUT;
++ goto done;
++ } else if (ret < 0)
++ goto done;
++
++ if (priv->msg_err) {
++ if (priv->msg_err & FALCON_I2C_NACK)
++ ret = -ENXIO;
++ else
++ ret = -EREMOTEIO;
++ goto done;
++ }
++ if (--priv->msgs_num) {
++ priv->current_msg++;
++ }
++ }
++ /* no error? */
++ ret = num;
++
++done:
++ falcon_i2c_release_bus(priv);
++
++ mutex_unlock(&priv->mutex);
++
++ if (ret>=0)
++ dump_msgs(msgs, num, 1);
++
++ PRINTK("XFER ret %d\n", ret);
++ return ret;
++}
++
++static irqreturn_t falcon_i2c_isr_burst(int irq, void *dev_id)
++{
++ struct falcon_i2c *priv = dev_id;
++ struct i2c_msg *msg = priv->current_msg;
++ int last = (irq == priv->irq_lb);
++
++ if (last)
++ PRINTK("LB ");
++ else
++ PRINTK("B ");
++
++ if (msg->flags & I2C_M_RD) {
++ switch (priv->status) {
++ case STATUS_ADDR:
++ PRINTK("X");
++ prepare_msg_send_addr(priv);
++ disable_burst_irq(priv);
++ break;
++ case STATUS_READ:
++ case STATUS_READ_END:
++ PRINTK("R");
++ falcon_i2c_rx(priv, last);
++ break;
++ default:
++ disable_burst_irq(priv);
++ printk("Status R %d\n", priv->status);
++ break;
++ }
++ } else {
++ switch (priv->status) {
++ case STATUS_ADDR:
++ PRINTK("x");
++ prepare_msg_send_addr(priv);
++ break;
++ case STATUS_WRITE:
++ PRINTK("w");
++ falcon_i2c_tx(priv, last);
++ break;
++ default:
++ disable_burst_irq(priv);
++ printk("Status W %d\n", priv->status);
++ break;
++ }
++ }
++
++ i2c_w32(I2C_ICR_BREQ_INT_CLR | I2C_ICR_LBREQ_INT_CLR, icr);
++ return IRQ_HANDLED;
++}
++
++static void falcon_i2c_isr_prot(struct falcon_i2c *priv)
++{
++ u32 i_pro = i2c_r32(p_irqss);
++
++ PRINTK("i2c-p");
++
++ /* not acknowledge */
++ if (i_pro & I2C_P_IRQSS_NACK) {
++ priv->msg_err |= FALCON_I2C_NACK;
++ PRINTK(" nack");
++ }
++
++ /* arbitration lost */
++ if (i_pro & I2C_P_IRQSS_AL) {
++ priv->msg_err |= FALCON_I2C_ARB_LOST;
++ PRINTK(" arb-lost");
++ }
++ /* tx -> rx switch */
++ if (i_pro & I2C_P_IRQSS_RX)
++ PRINTK(" rx");
++
++ /* tx end */
++ if (i_pro & I2C_P_IRQSS_TX_END)
++ PRINTK(" txend");
++ PRINTK("\n");
++
++ if (!priv->msg_err) {
++ /* tx -> rx switch */
++ if (i_pro & I2C_P_IRQSS_RX) {
++ priv->status = STATUS_READ;
++ enable_burst_irq(priv);
++ }
++ if (i_pro & I2C_P_IRQSS_TX_END) {
++ if (priv->status == STATUS_READ)
++ priv->status = STATUS_READ_END;
++ else {
++ disable_burst_irq(priv);
++ priv->status = STATUS_STOP;
++ }
++ }
++ }
++
++ i2c_w32(i_pro, p_irqsc);
++}
++
++static irqreturn_t falcon_i2c_isr(int irq, void *dev_id)
++{
++ u32 i_raw, i_err=0;
++ struct falcon_i2c *priv = dev_id;
++
++ i_raw = i2c_r32(mis);
++ PRINTK("i_raw 0x%08X\n", i_raw);
++
++ /* error interrupt */
++ if (i_raw & I2C_RIS_I2C_ERR_INT_INTOCC) {
++ i_err = i2c_r32(err_irqss);
++ PRINTK("i_err 0x%08X bus_stat 0x%04X\n",
++ i_err, i2c_r32(bus_stat));
++
++ /* tx fifo overflow (8) */
++ if (i_err & I2C_ERR_IRQSS_TXF_OFL)
++ priv->msg_err |= FALCON_I2C_TX_OFL;
++
++ /* tx fifo underflow (4) */
++ if (i_err & I2C_ERR_IRQSS_TXF_UFL)
++ priv->msg_err |= FALCON_I2C_TX_UFL;
++
++ /* rx fifo overflow (2) */
++ if (i_err & I2C_ERR_IRQSS_RXF_OFL)
++ priv->msg_err |= FALCON_I2C_RX_OFL;
++
++ /* rx fifo underflow (1) */
++ if (i_err & I2C_ERR_IRQSS_RXF_UFL)
++ priv->msg_err |= FALCON_I2C_RX_UFL;
++
++ i2c_w32(i_err, err_irqsc);
++ }
++
++ /* protocol interrupt */
++ if (i_raw & I2C_RIS_I2C_P_INT_INTOCC)
++ falcon_i2c_isr_prot(priv);
++
++ if ((priv->msg_err) || (priv->status == STATUS_STOP))
++ complete(&priv->cmd_complete);
++
++ return IRQ_HANDLED;
++}
++
++static u32 falcon_i2c_functionality(struct i2c_adapter *adap)
++{
++ return I2C_FUNC_I2C |
++ I2C_FUNC_10BIT_ADDR |
++ I2C_FUNC_SMBUS_EMUL;
++}
++
++static struct i2c_algorithm falcon_i2c_algorithm = {
++ .master_xfer = falcon_i2c_xfer,
++ .functionality = falcon_i2c_functionality,
++};
++
++static int __devinit falcon_i2c_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++ struct falcon_i2c *priv;
++ struct i2c_adapter *adap;
++ struct resource *mmres, *ioarea,
++ *irqres_lb, *irqres_b, *irqres_err, *irqres_p;
++ struct clk *clk;
++
++ dev_dbg(&pdev->dev, "probing\n");
++
++ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ irqres_lb = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
++ "i2c_lb");
++ irqres_b = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "i2c_b");
++ irqres_err = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
++ "i2c_err");
++ irqres_p = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "i2c_p");
++
++ if (!mmres || !irqres_lb || !irqres_b || !irqres_err || !irqres_p) {
++ dev_err(&pdev->dev, "no resources\n");
++ return -ENODEV;
++ }
++
++ clk = clk_get(&pdev->dev, "fpi");
++ if (IS_ERR(clk)) {
++ dev_err(&pdev->dev, "failed to get fpi clk\n");
++ return -ENOENT;
++ }
++
++ if (clk_get_rate(clk) != 100000000) {
++ dev_err(&pdev->dev, "input clock is not 100MHz\n");
++ return -ENOENT;
++ }
++
++ /* allocate private data */
++ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
++ if (!priv) {
++ dev_err(&pdev->dev, "can't allocate private data\n");
++ return -ENOMEM;
++ }
++
++ adap = &priv->adap;
++ i2c_set_adapdata(adap, priv);
++ adap->owner = THIS_MODULE;
++ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
++ strlcpy(adap->name, DRV_NAME "-adapter", sizeof(adap->name));
++ adap->algo = &falcon_i2c_algorithm;
++
++ priv->mode = FALCON_I2C_MODE_100;
++ priv->clk = clk;
++ priv->dev = &pdev->dev;
++
++ init_completion(&priv->cmd_complete);
++ mutex_init(&priv->mutex);
++
++ ret = ltq_gpio_request(107, 0, 0, 0, DRV_NAME":sda");
++ if (ret) {
++ dev_err(&pdev->dev, "I2C gpio 107 (sda) not available\n");
++ ret = -ENXIO;
++ goto err_free_priv;
++ }
++ ret = ltq_gpio_request(108, 0, 0, 0, DRV_NAME":scl");
++ if (ret) {
++ gpio_free(107);
++ dev_err(&pdev->dev, "I2C gpio 108 (scl) not available\n");
++ ret = -ENXIO;
++ goto err_free_priv;
++ }
++
++ ioarea = request_mem_region(mmres->start, resource_size(mmres),
++ pdev->name);
++
++ if (ioarea == NULL) {
++ dev_err(&pdev->dev, "I2C region already claimed\n");
++ ret = -ENXIO;
++ goto err_free_gpio;
++ }
++
++ /* map memory */
++ priv->membase = ioremap_nocache(mmres->start & ~KSEG1,
++ resource_size(mmres));
++ if (priv->membase == NULL) {
++ ret = -ENOMEM;
++ goto err_release_region;
++ }
++
++ priv->irq_lb = irqres_lb->start;
++ ret = request_irq(priv->irq_lb, falcon_i2c_isr_burst, IRQF_DISABLED,
++ irqres_lb->name, priv);
++ if (ret) {
++ dev_err(&pdev->dev, "can't get last burst IRQ %d\n", irqres_lb->start);
++ ret = -ENODEV;
++ goto err_unmap_mem;
++ }
++
++ priv->irq_b = irqres_b->start;
++ ret = request_irq(priv->irq_b, falcon_i2c_isr_burst, IRQF_DISABLED,
++ irqres_b->name, priv);
++ if (ret) {
++ dev_err(&pdev->dev, "can't get burst IRQ %d\n", irqres_b->start);
++ ret = -ENODEV;
++ goto err_free_lb_irq;
++ }
++
++ priv->irq_err = irqres_err->start;
++ ret = request_irq(priv->irq_err, falcon_i2c_isr, IRQF_DISABLED,
++ irqres_err->name, priv);
++ if (ret) {
++ dev_err(&pdev->dev, "can't get error IRQ %d\n", irqres_err->start);
++ ret = -ENODEV;
++ goto err_free_b_irq;
++ }
++
++ priv->irq_p = irqres_p->start;
++ ret = request_irq(priv->irq_p, falcon_i2c_isr, IRQF_DISABLED,
++ irqres_p->name, priv);
++ if (ret) {
++ dev_err(&pdev->dev, "can't get protocol IRQ %d\n", irqres_p->start);
++ ret = -ENODEV;
++ goto err_free_err_irq;
++ }
++
++ dev_dbg(&pdev->dev, "mapped io-space to %p\n", priv->membase);
++ dev_dbg(&pdev->dev, "use IRQs %d, %d, %d, %d\n", irqres_lb->start,
++ irqres_b->start, irqres_err->start, irqres_p->start);
++
++ /* add our adapter to the i2c stack */
++ ret = i2c_add_numbered_adapter(adap);
++ if (ret) {
++ dev_err(&pdev->dev, "can't register I2C adapter\n");
++ goto err_free_p_irq;
++ }
++
++ platform_set_drvdata(pdev, priv);
++ i2c_set_adapdata(adap, priv);
++
++ /* print module version information */
++ dev_dbg(&pdev->dev, "module id=%u revision=%u\n",
++ (i2c_r32(id) & I2C_ID_ID_MASK) >> I2C_ID_ID_OFFSET,
++ (i2c_r32(id) & I2C_ID_REV_MASK) >> I2C_ID_REV_OFFSET);
++
++ /* initialize HW */
++ ret = falcon_i2c_hw_init(adap);
++ if (ret) {
++ dev_err(&pdev->dev, "can't configure adapter\n");
++ goto err_remove_adapter;
++ }
++
++ dev_info(&pdev->dev, "version %s\n", DRV_VERSION);
++
++ return 0;
++
++err_remove_adapter:
++ i2c_del_adapter(adap);
++ platform_set_drvdata(pdev, NULL);
++
++err_free_p_irq:
++ free_irq(priv->irq_p, priv);
++
++err_free_err_irq:
++ free_irq(priv->irq_err, priv);
++
++err_free_b_irq:
++ free_irq(priv->irq_b, priv);
++
++err_free_lb_irq:
++ free_irq(priv->irq_lb, priv);
++
++err_unmap_mem:
++ iounmap(priv->membase);
++
++err_release_region:
++ release_mem_region(mmres->start, resource_size(mmres));
++
++err_free_gpio:
++ gpio_free(108);
++ gpio_free(107);
++
++err_free_priv:
++ kfree(priv);
++
++ return ret;
++}
++
++static int __devexit falcon_i2c_remove(struct platform_device *pdev)
++{
++ struct falcon_i2c *priv = platform_get_drvdata(pdev);
++ struct resource *mmres;
++
++ /* disable bus */
++ i2c_w32_mask(I2C_RUN_CTRL_RUN_EN, 0, run_ctrl);
++
++ /* remove driver */
++ platform_set_drvdata(pdev, NULL);
++ i2c_del_adapter(&priv->adap);
++
++ free_irq(priv->irq_lb, priv);
++ free_irq(priv->irq_b, priv);
++ free_irq(priv->irq_err, priv);
++ free_irq(priv->irq_p, priv);
++
++ iounmap(priv->membase);
++
++ gpio_free(108);
++ gpio_free(107);
++
++ kfree(priv);
++
++ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ release_mem_region(mmres->start, resource_size(mmres));
++
++ dev_dbg(&pdev->dev, "removed\n");
++
++ return 0;
++}
++
++static struct platform_driver falcon_i2c_driver = {
++ .probe = falcon_i2c_probe,
++ .remove = __devexit_p(falcon_i2c_remove),
++ .driver = {
++ .name = DRV_NAME,
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init falcon_i2c_init(void)
++{
++ int ret;
++
++ ret = platform_driver_register(&falcon_i2c_driver);
++
++ if (ret)
++ pr_debug(DRV_NAME ": can't register platform driver\n");
++
++ return ret;
++}
++
++static void __exit falcon_i2c_exit(void)
++{
++ platform_driver_unregister(&falcon_i2c_driver);
++}
++
++module_init(falcon_i2c_init);
++module_exit(falcon_i2c_exit);
++
++MODULE_DESCRIPTION("Lantiq FALC(tm) ON - I2C bus adapter");
++MODULE_ALIAS("platform:" DRV_NAME);
++MODULE_LICENSE("GPL");
++MODULE_VERSION(DRV_VERSION);
+--
+1.7.5.4
+
--- /dev/null
+From 6b5e2ee7c8f9722d59213f17d423b3f90d80f822 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sat, 13 Aug 2011 13:59:50 +0200
+Subject: [PATCH 12/24] MIPS: lantiq: adds GPIO3 support on AR9
+
+There are 3 16bit and 1 8bit gpio ports on AR9. The gpio driver needs a hack
+at 2 places to make the different register layout of the GPIO3 work properly
+with the driver. Before only GPIO0-2 were supported. As the GPIO number scheme
+clashes with the new size, we also move the other gpio chips to new offsets.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Signed-off-by: Thomas Langer <thomas.langer@lantiq.com>
+---
+ .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 2 +
+ arch/mips/lantiq/xway/devices.c | 3 +
+ arch/mips/lantiq/xway/gpio.c | 62 ++++++++++++++++----
+ arch/mips/lantiq/xway/gpio_ebu.c | 3 +-
+ arch/mips/lantiq/xway/gpio_stp.c | 3 +-
+ 5 files changed, 57 insertions(+), 16 deletions(-)
+
+diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
+index da8ff95..421768e 100644
+--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
+@@ -113,7 +113,9 @@
+ #define LTQ_GPIO0_BASE_ADDR 0x1E100B10
+ #define LTQ_GPIO1_BASE_ADDR 0x1E100B40
+ #define LTQ_GPIO2_BASE_ADDR 0x1E100B70
++#define LTQ_GPIO3_BASE_ADDR 0x1E100BA0
+ #define LTQ_GPIO_SIZE 0x30
++#define LTQ_GPIO3_SIZE 0x10
+
+ /* SSC */
+ #define LTQ_SSC_BASE_ADDR 0x1e100800
+diff --git a/arch/mips/lantiq/xway/devices.c b/arch/mips/lantiq/xway/devices.c
+index 9bacaa8..b7efac5 100644
+--- a/arch/mips/lantiq/xway/devices.c
++++ b/arch/mips/lantiq/xway/devices.c
+@@ -34,6 +34,7 @@ static struct resource ltq_gpio_resource[] = {
+ MEM_RES("gpio0", LTQ_GPIO0_BASE_ADDR, LTQ_GPIO_SIZE),
+ MEM_RES("gpio1", LTQ_GPIO1_BASE_ADDR, LTQ_GPIO_SIZE),
+ MEM_RES("gpio2", LTQ_GPIO2_BASE_ADDR, LTQ_GPIO_SIZE),
++ MEM_RES("gpio3", LTQ_GPIO3_BASE_ADDR, LTQ_GPIO3_SIZE),
+ };
+
+ void __init ltq_register_gpio(void)
+@@ -47,6 +48,8 @@ void __init ltq_register_gpio(void)
+ if (ltq_is_ar9() || ltq_is_vr9()) {
+ platform_device_register_simple("ltq_gpio", 2,
+ <q_gpio_resource[2], 1);
++ platform_device_register_simple("ltq_gpio", 3,
++ <q_gpio_resource[3], 1);
+ }
+ }
+
+diff --git a/arch/mips/lantiq/xway/gpio.c b/arch/mips/lantiq/xway/gpio.c
+index a321451..2c48c17 100644
+--- a/arch/mips/lantiq/xway/gpio.c
++++ b/arch/mips/lantiq/xway/gpio.c
+@@ -21,9 +21,15 @@
+ #define LTQ_GPIO_ALTSEL0 0x0C
+ #define LTQ_GPIO_ALTSEL1 0x10
+ #define LTQ_GPIO_OD 0x14
++#define LTQ_GPIO3_OD 0x24
++#define LTQ_GPIO3_ALTSEL1 0x24
+
++/* PORT3 only has 8 pins and its register layout
++ is slightly different */
+ #define PINS_PER_PORT 16
+-#define MAX_PORTS 3
++#define PINS_PORT3 8
++#define MAX_PORTS 4
++#define MAX_PIN 56
+
+ #define ltq_gpio_getbit(m, r, p) (!!(ltq_r32(m + r) & (1 << p)))
+ #define ltq_gpio_setbit(m, r, p) ltq_w32_mask(0, (1 << p), m + r)
+@@ -53,7 +59,7 @@ int ltq_gpio_request(unsigned int pin, unsigned int alt0,
+ {
+ int id = 0;
+
+- if (pin >= (MAX_PORTS * PINS_PER_PORT))
++ if (pin >= MAX_PIN)
+ return -EINVAL;
+ if (gpio_request(pin, name)) {
+ pr_err("failed to setup lantiq gpio: %s\n", name);
+@@ -73,12 +79,21 @@ int ltq_gpio_request(unsigned int pin, unsigned int alt0,
+ else
+ ltq_gpio_clearbit(ltq_gpio_port[id].membase,
+ LTQ_GPIO_ALTSEL0, pin);
+- if (alt1)
+- ltq_gpio_setbit(ltq_gpio_port[id].membase,
+- LTQ_GPIO_ALTSEL1, pin);
+- else
+- ltq_gpio_clearbit(ltq_gpio_port[id].membase,
+- LTQ_GPIO_ALTSEL1, pin);
++ if (id == 3) {
++ if (alt1)
++ ltq_gpio_setbit(ltq_gpio_port[1].membase,
++ LTQ_GPIO3_ALTSEL1, pin);
++ else
++ ltq_gpio_clearbit(ltq_gpio_port[1].membase,
++ LTQ_GPIO3_ALTSEL1, pin);
++ } else {
++ if (alt1)
++ ltq_gpio_setbit(ltq_gpio_port[id].membase,
++ LTQ_GPIO_ALTSEL1, pin);
++ else
++ ltq_gpio_clearbit(ltq_gpio_port[id].membase,
++ LTQ_GPIO_ALTSEL1, pin);
++ }
+ return 0;
+ }
+ EXPORT_SYMBOL(ltq_gpio_request);
+@@ -104,7 +119,11 @@ static int ltq_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
+ {
+ struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
+
+- ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OD, offset);
++ if (chip->ngpio == PINS_PORT3)
++ ltq_gpio_clearbit(ltq_gpio_port[0].membase,
++ LTQ_GPIO3_OD, offset);
++ else
++ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OD, offset);
+ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset);
+
+ return 0;
+@@ -115,7 +134,10 @@ static int ltq_gpio_direction_output(struct gpio_chip *chip,
+ {
+ struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
+
+- ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OD, offset);
++ if (chip->ngpio == PINS_PORT3)
++ ltq_gpio_setbit(ltq_gpio_port[0].membase, LTQ_GPIO3_OD, offset);
++ else
++ ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OD, offset);
+ ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset);
+ ltq_gpio_set(chip, offset, value);
+
+@@ -127,7 +149,11 @@ static int ltq_gpio_req(struct gpio_chip *chip, unsigned offset)
+ struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
+
+ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL0, offset);
+- ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL1, offset);
++ if (chip->ngpio == PINS_PORT3)
++ ltq_gpio_clearbit(ltq_gpio_port[1].membase,
++ LTQ_GPIO3_ALTSEL1, offset);
++ else
++ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL1, offset);
+ return 0;
+ }
+
+@@ -140,6 +166,15 @@ static int ltq_gpio_probe(struct platform_device *pdev)
+ pdev->id);
+ return -EINVAL;
+ }
++
++ /* dirty hack - The registers of port3 are not mapped linearly.
++ Port 3 may only load if Port 1/2 are mapped */
++ if ((pdev->id == 3) && (!ltq_gpio_port[1].membase || !ltq_gpio_port[2].membase)) {
++ dev_err(&pdev->dev,
++ "ports 1/2 need to be loaded before port 3 works\n");
++ return -ENOMEM;
++ }
++
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get memory for gpio port %d\n",
+@@ -169,7 +204,10 @@ static int ltq_gpio_probe(struct platform_device *pdev)
+ ltq_gpio_port[pdev->id].chip.set = ltq_gpio_set;
+ ltq_gpio_port[pdev->id].chip.request = ltq_gpio_req;
+ ltq_gpio_port[pdev->id].chip.base = PINS_PER_PORT * pdev->id;
+- ltq_gpio_port[pdev->id].chip.ngpio = PINS_PER_PORT;
++ if (pdev->id == 3)
++ ltq_gpio_port[pdev->id].chip.ngpio = PINS_PORT3;
++ else
++ ltq_gpio_port[pdev->id].chip.ngpio = PINS_PER_PORT;
+ platform_set_drvdata(pdev, <q_gpio_port[pdev->id]);
+ return gpiochip_add(<q_gpio_port[pdev->id].chip);
+ }
+diff --git a/arch/mips/lantiq/xway/gpio_ebu.c b/arch/mips/lantiq/xway/gpio_ebu.c
+index a479355..729f8e3 100644
+--- a/arch/mips/lantiq/xway/gpio_ebu.c
++++ b/arch/mips/lantiq/xway/gpio_ebu.c
+@@ -61,9 +61,8 @@ static struct gpio_chip ltq_ebu_chip = {
+ .label = "ltq_ebu",
+ .direction_output = ltq_ebu_direction_output,
+ .set = ltq_ebu_set,
+- .base = 72,
++ .base = 100,
+ .ngpio = 16,
+- .can_sleep = 1,
+ .owner = THIS_MODULE,
+ };
+
+diff --git a/arch/mips/lantiq/xway/gpio_stp.c b/arch/mips/lantiq/xway/gpio_stp.c
+index 67d59d6..c01294e 100644
+--- a/arch/mips/lantiq/xway/gpio_stp.c
++++ b/arch/mips/lantiq/xway/gpio_stp.c
+@@ -70,9 +70,8 @@ static struct gpio_chip ltq_stp_chip = {
+ .label = "ltq_stp",
+ .direction_output = ltq_stp_direction_output,
+ .set = ltq_stp_set,
+- .base = 48,
++ .base = 200,
+ .ngpio = 24,
+- .can_sleep = 1,
+ .owner = THIS_MODULE,
+ };
+
+--
+1.7.5.4
+
--- /dev/null
+From 2bd534c30688bcb3f70f1816fbcff813fc746103 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sat, 27 Aug 2011 18:12:26 +0200
+Subject: [PATCH 13/24] MIPS: lantiq: adds FALC-ON spi driver
+
+The external bus unit (EBU) found on the FALC-ON SoC has spi emulation that is
+designed for serial flash access.
+
+Signed-off-by: Thomas Langer <thomas.langer@lantiq.com>
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ arch/mips/lantiq/falcon/devices.c | 12 +-
+ arch/mips/lantiq/falcon/devices.h | 4 +
+ arch/mips/lantiq/falcon/mach-easy98000.c | 27 ++
+ drivers/spi/Kconfig | 4 +
+ drivers/spi/Makefile | 1 +
+ drivers/spi/spi-falcon.c | 477 ++++++++++++++++++++++++++++++
+ 6 files changed, 523 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/spi/spi-falcon.c
+
+Index: linux-3.0.3/arch/mips/lantiq/falcon/devices.c
+===================================================================
+--- linux-3.0.3.orig/arch/mips/lantiq/falcon/devices.c 2011-10-05 12:30:34.584838403 +0200
++++ linux-3.0.3/arch/mips/lantiq/falcon/devices.c 2011-10-05 12:42:58.696870214 +0200
+@@ -129,7 +129,7 @@
+
+ /* i2c */
+ static struct resource falcon_i2c_resources[] = {
+- MEM_RES("i2c", GPON_I2C_BASE,GPON_I2C_END),
++ MEM_RES("i2c", LTQ_I2C_BASE_ADDR, LTQ_I2C_SIZE),
+ IRQ_RES("i2c_lb", FALCON_IRQ_I2C_LBREQ),
+ IRQ_RES("i2c_b", FALCON_IRQ_I2C_BREQ),
+ IRQ_RES("i2c_err", FALCON_IRQ_I2C_I2C_ERR),
+@@ -140,10 +140,18 @@
+ {
+ platform_device_register_simple("i2c-falcon", 0,
+ falcon_i2c_resources, ARRAY_SIZE(falcon_i2c_resources));
+- sys1_hw_activate(ACTS_I2C_ACT);
++ ltq_sysctl_activate(SYSCTL_SYS1, ACTS_I2C_ACT);
+ }
+
+-void __init falcon_register_crypto(void)
++/* spi flash */
++static struct platform_device ltq_spi = {
++ .name = "falcon_spi",
++ .num_resources = 0,
++};
++
++void __init
++falcon_register_spi_flash(struct spi_board_info *data)
+ {
+- platform_device_register_simple("ltq_falcon_deu", 0, NULL, 0);
++ spi_register_board_info(data, 1);
++ platform_device_register(<q_spi);
+ }
+Index: linux-3.0.3/arch/mips/lantiq/falcon/devices.h
+===================================================================
+--- linux-3.0.3.orig/arch/mips/lantiq/falcon/devices.h 2011-10-05 12:30:34.584838403 +0200
++++ linux-3.0.3/arch/mips/lantiq/falcon/devices.h 2011-10-05 12:30:34.600838405 +0200
+@@ -11,11 +11,15 @@
+ #ifndef _FALCON_DEVICES_H__
+ #define _FALCON_DEVICES_H__
+
++#include <linux/spi/spi.h>
++#include <linux/spi/flash.h>
++
+ #include "../devices.h"
+
+ extern void falcon_register_nand(void);
+ extern void falcon_register_gpio(void);
+ extern void falcon_register_gpio_extra(void);
+ extern void falcon_register_i2c(void);
++extern void falcon_register_spi_flash(struct spi_board_info *data);
+
+ #endif
+Index: linux-3.0.3/arch/mips/lantiq/falcon/mach-easy98000.c
+===================================================================
+--- linux-3.0.3.orig/arch/mips/lantiq/falcon/mach-easy98000.c 2011-10-05 12:30:34.552838402 +0200
++++ linux-3.0.3/arch/mips/lantiq/falcon/mach-easy98000.c 2011-10-05 12:30:34.600838405 +0200
+@@ -40,6 +40,21 @@
+ .parts = easy98000_nor_partitions,
+ };
+
++static struct flash_platform_data easy98000_spi_flash_platform_data = {
++ .name = "sflash",
++ .parts = easy98000_nor_partitions,
++ .nr_parts = ARRAY_SIZE(easy98000_nor_partitions)
++};
++
++static struct spi_board_info easy98000_spi_flash_data __initdata = {
++ .modalias = "m25p80",
++ .bus_num = 0,
++ .chip_select = 0,
++ .max_speed_hz = 10 * 1000 * 1000,
++ .mode = SPI_MODE_3,
++ .platform_data = &easy98000_spi_flash_platform_data
++};
++
+ /* setup gpio based spi bus/device for access to the eeprom on the board */
+ #define SPI_GPIO_MRST 102
+ #define SPI_GPIO_MTSR 103
+@@ -93,6 +108,13 @@
+ }
+
+ static void __init
++easy98000sf_init(void)
++{
++ easy98000_init_common();
++ falcon_register_spi_flash(&easy98000_spi_flash_data);
++}
++
++static void __init
+ easy98000nand_init(void)
+ {
+ easy98000_init_common();
+@@ -104,6 +126,11 @@
+ "EASY98000 Eval Board",
+ easy98000_init);
+
++MIPS_MACHINE(LANTIQ_MACH_EASY98000SF,
++ "EASY98000SF",
++ "EASY98000 Eval Board (Serial Flash)",
++ easy98000sf_init);
++
+ MIPS_MACHINE(LANTIQ_MACH_EASY98000NAND,
+ "EASY98000NAND",
+ "EASY98000 Eval Board (NAND Flash)",
+Index: linux-3.0.3/drivers/spi/Kconfig
+===================================================================
+--- linux-3.0.3.orig/drivers/spi/Kconfig 2011-10-05 12:30:33.608838362 +0200
++++ linux-3.0.3/drivers/spi/Kconfig 2011-10-05 12:41:56.864867570 +0200
+@@ -219,6 +219,10 @@
+ This drivers supports the MPC52xx SPI controller in master SPI
+ mode.
+
++config SPI_FALCON
++ tristate "Falcon SPI controller support"
++ depends on SOC_FALCON
++
+ config SPI_MPC52xx_PSC
+ tristate "Freescale MPC52xx PSC SPI controller"
+ depends on PPC_MPC52xx && EXPERIMENTAL
+Index: linux-3.0.3/drivers/spi/Makefile
+===================================================================
+--- linux-3.0.3.orig/drivers/spi/Makefile 2011-10-05 12:30:33.608838362 +0200
++++ linux-3.0.3/drivers/spi/Makefile 2011-10-05 12:41:56.884867571 +0200
+@@ -56,6 +56,7 @@
+ obj-$(CONFIG_SPI_SH_MSIOF) += spi_sh_msiof.o
+ obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o
+ obj-$(CONFIG_SPI_NUC900) += spi_nuc900.o
++obj-$(CONFIG_SPI_FALCON) += spi-falcon.o
+
+ # special build for s3c24xx spi driver with fiq support
+ spi_s3c24xx_hw-y := spi_s3c24xx.o
+Index: linux-3.0.3/drivers/spi/spi-falcon.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-3.0.3/drivers/spi/spi-falcon.c 2011-10-05 12:30:34.600838405 +0200
+@@ -0,0 +1,477 @@
++/*
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com>
++ */
++
++#include <linux/module.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/spi/spi.h>
++#include <linux/delay.h>
++#include <linux/workqueue.h>
++
++#include <lantiq_soc.h>
++
++#define DRV_NAME "falcon_spi"
++
++#define FALCON_SPI_XFER_BEGIN (1 << 0)
++#define FALCON_SPI_XFER_END (1 << 1)
++
++/* Bus Read Configuration Register0 */
++#define LTQ_BUSRCON0 0x00000010
++/* Bus Write Configuration Register0 */
++#define LTQ_BUSWCON0 0x00000018
++/* Serial Flash Configuration Register */
++#define LTQ_SFCON 0x00000080
++/* Serial Flash Time Register */
++#define LTQ_SFTIME 0x00000084
++/* Serial Flash Status Register */
++#define LTQ_SFSTAT 0x00000088
++/* Serial Flash Command Register */
++#define LTQ_SFCMD 0x0000008C
++/* Serial Flash Address Register */
++#define LTQ_SFADDR 0x00000090
++/* Serial Flash Data Register */
++#define LTQ_SFDATA 0x00000094
++/* Serial Flash I/O Control Register */
++#define LTQ_SFIO 0x00000098
++/* EBU Clock Control Register */
++#define LTQ_EBUCC 0x000000C4
++
++/* Dummy Phase Length */
++#define SFCMD_DUMLEN_OFFSET 16
++#define SFCMD_DUMLEN_MASK 0x000F0000
++/* Chip Select */
++#define SFCMD_CS_OFFSET 24
++#define SFCMD_CS_MASK 0x07000000
++/* field offset */
++#define SFCMD_ALEN_OFFSET 20
++#define SFCMD_ALEN_MASK 0x00700000
++/* SCK Rise-edge Position */
++#define SFTIME_SCKR_POS_OFFSET 8
++#define SFTIME_SCKR_POS_MASK 0x00000F00
++/* SCK Period */
++#define SFTIME_SCK_PER_OFFSET 0
++#define SFTIME_SCK_PER_MASK 0x0000000F
++/* SCK Fall-edge Position */
++#define SFTIME_SCKF_POS_OFFSET 12
++#define SFTIME_SCKF_POS_MASK 0x0000F000
++/* Device Size */
++#define SFCON_DEV_SIZE_A23_0 0x03000000
++#define SFCON_DEV_SIZE_MASK 0x0F000000
++/* Read Data Position */
++#define SFTIME_RD_POS_MASK 0x000F0000
++/* Data Output */
++#define SFIO_UNUSED_WD_MASK 0x0000000F
++/* Command Opcode mask */
++#define SFCMD_OPC_MASK 0x000000FF
++/* dlen bytes of data to write */
++#define SFCMD_DIR_WRITE 0x00000100
++/* Data Length offset */
++#define SFCMD_DLEN_OFFSET 9
++/* Command Error */
++#define SFSTAT_CMD_ERR 0x20000000
++/* Access Command Pending */
++#define SFSTAT_CMD_PEND 0x00400000
++/* Frequency set to 100MHz. */
++#define EBUCC_EBUDIV_SELF100 0x00000001
++/* Serial Flash */
++#define BUSRCON0_AGEN_SERIAL_FLASH 0xF0000000
++/* 8-bit multiplexed */
++#define BUSRCON0_PORTW_8_BIT_MUX 0x00000000
++/* Serial Flash */
++#define BUSWCON0_AGEN_SERIAL_FLASH 0xF0000000
++/* Chip Select after opcode */
++#define SFCMD_KEEP_CS_KEEP_SELECTED 0x00008000
++
++struct falcon_spi {
++ u32 sfcmd; /* for caching of opcode, direction, ... */
++ struct spi_master *master;
++};
++
++int
++falcon_spi_xfer(struct spi_device *spi,
++ struct spi_transfer *t,
++ unsigned long flags)
++{
++ struct device *dev = &spi->dev;
++ struct falcon_spi *priv = spi_master_get_devdata(spi->master);
++ const u8 *txp = t->tx_buf;
++ u8 *rxp = t->rx_buf;
++ unsigned int bytelen = ((8 * t->len + 7) / 8);
++ unsigned int len, alen, dumlen;
++ u32 val;
++ enum {
++ state_init,
++ state_command_prepare,
++ state_write,
++ state_read,
++ state_disable_cs,
++ state_end
++ } state = state_init;
++
++ do {
++ switch (state) {
++ case state_init: /* detect phase of upper layer sequence */
++ {
++ /* initial write ? */
++ if (flags & FALCON_SPI_XFER_BEGIN) {
++ if (!txp) {
++ dev_err(dev,
++ "BEGIN without tx data!\n");
++ return -1;
++ }
++ /*
++ * Prepare the parts of the sfcmd register,
++ * which should not
++ * change during a sequence!
++ * Only exception are the length fields,
++ * especially alen and dumlen.
++ */
++
++ priv->sfcmd = ((spi->chip_select
++ << SFCMD_CS_OFFSET)
++ & SFCMD_CS_MASK);
++ priv->sfcmd |= SFCMD_KEEP_CS_KEEP_SELECTED;
++ priv->sfcmd |= *txp;
++ txp++;
++ bytelen--;
++ if (bytelen) {
++ /* more data:
++ * maybe address and/or dummy */
++ state = state_command_prepare;
++ break;
++ } else {
++ dev_dbg(dev, "write cmd %02X\n",
++ priv->sfcmd & SFCMD_OPC_MASK);
++ }
++ }
++ /* continued write ? */
++ if (txp && bytelen) {
++ state = state_write;
++ break;
++ }
++ /* read data? */
++ if (rxp && bytelen) {
++ state = state_read;
++ break;
++ }
++ /* end of sequence? */
++ if (flags & FALCON_SPI_XFER_END)
++ state = state_disable_cs;
++ else
++ state = state_end;
++ break;
++ }
++ case state_command_prepare: /* collect tx data for
++ address and dummy phase */
++ {
++ /* txp is valid, already checked */
++ val = 0;
++ alen = 0;
++ dumlen = 0;
++ while (bytelen > 0) {
++ if (alen < 3) {
++ val = (val<<8)|(*txp++);
++ alen++;
++ } else if ((dumlen < 15) && (*txp == 0)) {
++ /*
++ * assume dummy bytes are set to 0
++ * from upper layer
++ */
++ dumlen++;
++ txp++;
++ } else
++ break;
++ bytelen--;
++ }
++ priv->sfcmd &= ~(SFCMD_ALEN_MASK | SFCMD_DUMLEN_MASK);
++ priv->sfcmd |= (alen << SFCMD_ALEN_OFFSET) |
++ (dumlen << SFCMD_DUMLEN_OFFSET);
++ if (alen > 0)
++ ltq_ebu_w32(val, LTQ_SFADDR);
++
++ dev_dbg(dev, "write cmd %02X, alen=%d "
++ "(addr=%06X) dumlen=%d\n",
++ priv->sfcmd & SFCMD_OPC_MASK,
++ alen, val, dumlen);
++
++ if (bytelen > 0) {
++ /* continue with write */
++ state = state_write;
++ } else if (flags & FALCON_SPI_XFER_END) {
++ /* end of sequence? */
++ state = state_disable_cs;
++ } else {
++ /* go to end and expect another
++ * call (read or write) */
++ state = state_end;
++ }
++ break;
++ }
++ case state_write:
++ {
++ /* txp still valid */
++ priv->sfcmd |= SFCMD_DIR_WRITE;
++ len = 0;
++ val = 0;
++ do {
++ if (bytelen--)
++ val |= (*txp++) << (8 * len++);
++ if ((flags & FALCON_SPI_XFER_END)
++ && (bytelen == 0)) {
++ priv->sfcmd &=
++ ~SFCMD_KEEP_CS_KEEP_SELECTED;
++ }
++ if ((len == 4) || (bytelen == 0)) {
++ ltq_ebu_w32(val, LTQ_SFDATA);
++ ltq_ebu_w32(priv->sfcmd
++ | (len<<SFCMD_DLEN_OFFSET),
++ LTQ_SFCMD);
++ len = 0;
++ val = 0;
++ priv->sfcmd &= ~(SFCMD_ALEN_MASK
++ | SFCMD_DUMLEN_MASK);
++ }
++ } while (bytelen);
++ state = state_end;
++ break;
++ }
++ case state_read:
++ {
++ /* read data */
++ priv->sfcmd &= ~SFCMD_DIR_WRITE;
++ do {
++ if ((flags & FALCON_SPI_XFER_END)
++ && (bytelen <= 4)) {
++ priv->sfcmd &=
++ ~SFCMD_KEEP_CS_KEEP_SELECTED;
++ }
++ len = (bytelen > 4) ? 4 : bytelen;
++ bytelen -= len;
++ ltq_ebu_w32(priv->sfcmd
++ |(len<<SFCMD_DLEN_OFFSET), LTQ_SFCMD);
++ priv->sfcmd &= ~(SFCMD_ALEN_MASK
++ | SFCMD_DUMLEN_MASK);
++ do {
++ val = ltq_ebu_r32(LTQ_SFSTAT);
++ if (val & SFSTAT_CMD_ERR) {
++ /* reset error status */
++ dev_err(dev, "SFSTAT: CMD_ERR "
++ "(%x)\n", val);
++ ltq_ebu_w32(SFSTAT_CMD_ERR,
++ LTQ_SFSTAT);
++ return -1;
++ }
++ } while (val & SFSTAT_CMD_PEND);
++ val = ltq_ebu_r32(LTQ_SFDATA);
++ do {
++ *rxp = (val & 0xFF);
++ rxp++;
++ val >>= 8;
++ len--;
++ } while (len);
++ } while (bytelen);
++ state = state_end;
++ break;
++ }
++ case state_disable_cs:
++ {
++ priv->sfcmd &= ~SFCMD_KEEP_CS_KEEP_SELECTED;
++ ltq_ebu_w32(priv->sfcmd | (0 << SFCMD_DLEN_OFFSET),
++ LTQ_SFCMD);
++ val = ltq_ebu_r32(LTQ_SFSTAT);
++ if (val & SFSTAT_CMD_ERR) {
++ /* reset error status */
++ dev_err(dev, "SFSTAT: CMD_ERR (%x)\n", val);
++ ltq_ebu_w32(SFSTAT_CMD_ERR, LTQ_SFSTAT);
++ return -1;
++ }
++ state = state_end;
++ break;
++ }
++ case state_end:
++ break;
++ }
++ } while (state != state_end);
++
++ return 0;
++}
++
++static int
++falcon_spi_setup(struct spi_device *spi)
++{
++ struct device *dev = &spi->dev;
++ const u32 ebuclk = CLOCK_100M;
++ unsigned int i;
++ unsigned long flags;
++
++ dev_dbg(dev, "setup\n");
++
++ if (spi->master->bus_num > 0 || spi->chip_select > 0)
++ return -ENODEV;
++
++ spin_lock_irqsave(&ebu_lock, flags);
++
++ if (ebuclk < spi->max_speed_hz) {
++ /* set EBU clock to 100 MHz */
++ ltq_sys1_w32_mask(0, EBUCC_EBUDIV_SELF100, LTQ_EBUCC);
++ i = 1; /* divider */
++ } else {
++ /* set EBU clock to 50 MHz */
++ ltq_sys1_w32_mask(EBUCC_EBUDIV_SELF100, 0, LTQ_EBUCC);
++
++ /* search for suitable divider */
++ for (i = 1; i < 7; i++) {
++ if (ebuclk / i <= spi->max_speed_hz)
++ break;
++ }
++ }
++
++ /* setup period of serial clock */
++ ltq_ebu_w32_mask(SFTIME_SCKF_POS_MASK
++ | SFTIME_SCKR_POS_MASK
++ | SFTIME_SCK_PER_MASK,
++ (i << SFTIME_SCKR_POS_OFFSET)
++ | (i << (SFTIME_SCK_PER_OFFSET + 1)),
++ LTQ_SFTIME);
++
++ /* set some bits of unused_wd, to not trigger HOLD/WP
++ * signals on non QUAD flashes */
++ ltq_ebu_w32((SFIO_UNUSED_WD_MASK & (0x8 | 0x4)), LTQ_SFIO);
++
++ ltq_ebu_w32(BUSRCON0_AGEN_SERIAL_FLASH | BUSRCON0_PORTW_8_BIT_MUX,
++ LTQ_BUSRCON0);
++ ltq_ebu_w32(BUSWCON0_AGEN_SERIAL_FLASH, LTQ_BUSWCON0);
++ /* set address wrap around to maximum for 24-bit addresses */
++ ltq_ebu_w32_mask(SFCON_DEV_SIZE_MASK, SFCON_DEV_SIZE_A23_0, LTQ_SFCON);
++
++ spin_unlock_irqrestore(&ebu_lock, flags);
++
++ return 0;
++}
++
++static int
++falcon_spi_transfer(struct spi_device *spi, struct spi_message *m)
++{
++ struct falcon_spi *priv = spi_master_get_devdata(spi->master);
++ struct spi_transfer *t;
++ unsigned long spi_flags;
++ unsigned long flags;
++ int ret = 0;
++
++ priv->sfcmd = 0;
++ m->actual_length = 0;
++
++ spi_flags = FALCON_SPI_XFER_BEGIN;
++ list_for_each_entry(t, &m->transfers, transfer_list) {
++ if (list_is_last(&t->transfer_list, &m->transfers))
++ spi_flags |= FALCON_SPI_XFER_END;
++
++ spin_lock_irqsave(&ebu_lock, flags);
++ ret = falcon_spi_xfer(spi, t, spi_flags);
++ spin_unlock_irqrestore(&ebu_lock, flags);
++
++ if (ret)
++ break;
++
++ m->actual_length += t->len;
++
++ if (t->delay_usecs || t->cs_change)
++ BUG();
++
++ spi_flags = 0;
++ }
++
++ m->status = ret;
++ m->complete(m->context);
++
++ return 0;
++}
++
++static void
++falcon_spi_cleanup(struct spi_device *spi)
++{
++ struct device *dev = &spi->dev;
++
++ dev_dbg(dev, "cleanup\n");
++}
++
++static int __devinit
++falcon_spi_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct falcon_spi *priv;
++ struct spi_master *master;
++ int ret;
++
++ dev_dbg(dev, "probing\n");
++
++ master = spi_alloc_master(&pdev->dev, sizeof(*priv));
++ if (!master) {
++ dev_err(dev, "no memory for spi_master\n");
++ return -ENOMEM;
++ }
++
++ priv = spi_master_get_devdata(master);
++ priv->master = master;
++
++ master->mode_bits = SPI_MODE_3;
++ master->num_chipselect = 1;
++ master->bus_num = 0;
++
++ master->setup = falcon_spi_setup;
++ master->transfer = falcon_spi_transfer;
++ master->cleanup = falcon_spi_cleanup;
++
++ platform_set_drvdata(pdev, priv);
++
++ ret = spi_register_master(master);
++ if (ret)
++ spi_master_put(master);
++
++ return ret;
++}
++
++static int __devexit
++falcon_spi_remove(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct falcon_spi *priv = platform_get_drvdata(pdev);
++
++ dev_dbg(dev, "removed\n");
++
++ spi_unregister_master(priv->master);
++
++ return 0;
++}
++
++static struct platform_driver falcon_spi_driver = {
++ .probe = falcon_spi_probe,
++ .remove = __devexit_p(falcon_spi_remove),
++ .driver = {
++ .name = DRV_NAME,
++ .owner = THIS_MODULE
++ }
++};
++
++static int __init
++falcon_spi_init(void)
++{
++ return platform_driver_register(&falcon_spi_driver);
++}
++
++static void __exit
++falcon_spi_exit(void)
++{
++ platform_driver_unregister(&falcon_spi_driver);
++}
++
++module_init(falcon_spi_init);
++module_exit(falcon_spi_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Lantiq Falcon SPI controller driver");
+Index: linux-3.0.3/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h
+===================================================================
+--- linux-3.0.3.orig/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h 2011-10-05 12:38:16.176858136 +0200
++++ linux-3.0.3/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h 2011-10-05 12:39:54.936862358 +0200
+@@ -48,6 +48,10 @@
+
+ #define LTQ_EBU_MODCON 0x000C
+
++/* I2C */
++#define LTQ_I2C_BASE_ADDR 0x1E200000
++#define LTQ_I2C_SIZE 0x00010000
++
+ /* GPIO */
+ #define LTQ_GPIO0_BASE_ADDR 0x1D810000
+ #define LTQ_GPIO0_SIZE 0x0080
+@@ -92,6 +96,7 @@
+
+ /* Activation Status Register */
+ #define ACTS_ASC1_ACT 0x00000800
++#define ACTS_I2C_ACT 0x00004000
+ #define ACTS_P0 0x00010000
+ #define ACTS_P1 0x00010000
+ #define ACTS_P2 0x00020000
--- /dev/null
+From e29263339db41d49d79482c93463c4c0cbe764d7 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Fri, 30 Sep 2011 14:23:42 +0200
+Subject: [PATCH 14/24] MIPS: lantiq: adds xway spi
+
+---
+ .../mips/include/asm/mach-lantiq/lantiq_platform.h | 9 +
+ .../mips/include/asm/mach-lantiq/xway/lantiq_irq.h | 2 +
+ .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 1 +
+ drivers/spi/Kconfig | 8 +
+ drivers/spi/Makefile | 2 +-
+ drivers/spi/spi-xway.c | 1062 ++++++++++++++++++++
+ 6 files changed, 1083 insertions(+), 1 deletions(-)
+ create mode 100644 drivers/spi/spi-xway.c
+
+Index: linux-3.0.3/arch/mips/include/asm/mach-lantiq/lantiq_platform.h
+===================================================================
+--- linux-3.0.3.orig/arch/mips/include/asm/mach-lantiq/lantiq_platform.h 2011-08-17 19:57:16.000000000 +0200
++++ linux-3.0.3/arch/mips/include/asm/mach-lantiq/lantiq_platform.h 2011-10-04 20:05:23.962311503 +0200
+@@ -50,4 +50,13 @@
+ int mii_mode;
+ };
+
++
++struct ltq_spi_platform_data {
++ u16 num_chipselect;
++};
++
++struct ltq_spi_controller_data {
++ unsigned gpio;
++};
++
+ #endif
+Index: linux-3.0.3/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h
+===================================================================
+--- linux-3.0.3.orig/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h 2011-08-17 19:57:16.000000000 +0200
++++ linux-3.0.3/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h 2011-10-04 20:05:23.962311503 +0200
+@@ -27,6 +27,8 @@
+
+ #define LTQ_SSC_TIR (INT_NUM_IM0_IRL0 + 15)
+ #define LTQ_SSC_RIR (INT_NUM_IM0_IRL0 + 14)
++#define LTQ_SSC_TIR_AR9 (INT_NUM_IM0_IRL0 + 14)
++#define LTQ_SSC_RIR_AR9 (INT_NUM_IM0_IRL0 + 15)
+ #define LTQ_SSC_EIR (INT_NUM_IM0_IRL0 + 16)
+
+ #define LTQ_MEI_DYING_GASP_INT (INT_NUM_IM1_IRL0 + 21)
+Index: linux-3.0.3/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
+===================================================================
+--- linux-3.0.3.orig/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h 2011-10-04 20:03:54.934307699 +0200
++++ linux-3.0.3/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h 2011-10-04 20:05:23.966311504 +0200
+@@ -81,6 +81,7 @@
+
+ #define PMU_DMA 0x0020
+ #define PMU_USB 0x8041
++#define PMU_SPI 0x0100
+ #define PMU_LED 0x0800
+ #define PMU_GPT 0x1000
+ #define PMU_PPE 0x2000
+Index: linux-3.0.3/drivers/spi/Kconfig
+===================================================================
+--- linux-3.0.3.orig/drivers/spi/Kconfig 2011-10-04 20:05:07.030310779 +0200
++++ linux-3.0.3/drivers/spi/Kconfig 2011-10-04 20:05:23.966311504 +0200
+@@ -433,6 +433,14 @@
+ help
+ SPI driver for Nuvoton NUC900 series ARM SoCs
+
++config SPI_XWAY
++ tristate "Lantiq XWAY SPI controller"
++ depends on LANTIQ && SOC_TYPE_XWAY
++ select SPI_BITBANG
++ help
++ This driver supports the Lantiq SoC SPI controller in master
++ mode.
++
+ #
+ # Add new SPI master controllers in alphabetical order above this line
+ #
+Index: linux-3.0.3/drivers/spi/Makefile
+===================================================================
+--- linux-3.0.3.orig/drivers/spi/Makefile 2011-10-04 20:05:20.000000000 +0200
++++ linux-3.0.3/drivers/spi/Makefile 2011-10-04 20:05:35.802312011 +0200
+@@ -57,6 +57,7 @@
+ obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o
+ obj-$(CONFIG_SPI_NUC900) += spi_nuc900.o
+ obj-$(CONFIG_SPI_FALCON) += spi-falcon.o
++obj-$(CONFIG_SPI_XWAY) += spi-xway.o
+
+ # special build for s3c24xx spi driver with fiq support
+ spi_s3c24xx_hw-y := spi_s3c24xx.o
+Index: linux-3.0.3/drivers/spi/spi-xway.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-3.0.3/drivers/spi/spi-xway.c 2011-10-04 20:05:23.966311504 +0200
+@@ -0,0 +1,1062 @@
++/*
++ * Lantiq SoC SPI controller
++ *
++ * Copyright (C) 2011 Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>
++ *
++ * This program is free software; you can distribute it and/or modify it
++ * under the terms of the GNU General Public License (Version 2) as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/workqueue.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/sched.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/completion.h>
++#include <linux/spinlock.h>
++#include <linux/err.h>
++#include <linux/clk.h>
++#include <linux/gpio.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/spi_bitbang.h>
++
++#include <lantiq_soc.h>
++#include <lantiq_platform.h>
++
++#define LTQ_SPI_CLC 0x00 /* Clock control */
++#define LTQ_SPI_PISEL 0x04 /* Port input select */
++#define LTQ_SPI_ID 0x08 /* Identification */
++#define LTQ_SPI_CON 0x10 /* Control */
++#define LTQ_SPI_STAT 0x14 /* Status */
++#define LTQ_SPI_WHBSTATE 0x18 /* Write HW modified state */
++#define LTQ_SPI_TB 0x20 /* Transmit buffer */
++#define LTQ_SPI_RB 0x24 /* Receive buffer */
++#define LTQ_SPI_RXFCON 0x30 /* Receive FIFO control */
++#define LTQ_SPI_TXFCON 0x34 /* Transmit FIFO control */
++#define LTQ_SPI_FSTAT 0x38 /* FIFO status */
++#define LTQ_SPI_BRT 0x40 /* Baudrate timer */
++#define LTQ_SPI_BRSTAT 0x44 /* Baudrate timer status */
++#define LTQ_SPI_SFCON 0x60 /* Serial frame control */
++#define LTQ_SPI_SFSTAT 0x64 /* Serial frame status */
++#define LTQ_SPI_GPOCON 0x70 /* General purpose output control */
++#define LTQ_SPI_GPOSTAT 0x74 /* General purpose output status */
++#define LTQ_SPI_FGPO 0x78 /* Forced general purpose output */
++#define LTQ_SPI_RXREQ 0x80 /* Receive request */
++#define LTQ_SPI_RXCNT 0x84 /* Receive count */
++#define LTQ_SPI_DMACON 0xEC /* DMA control */
++#define LTQ_SPI_IRNEN 0xF4 /* Interrupt node enable */
++#define LTQ_SPI_IRNICR 0xF8 /* Interrupt node interrupt capture */
++#define LTQ_SPI_IRNCR 0xFC /* Interrupt node control */
++
++#define LTQ_SPI_CLC_SMC_SHIFT 16 /* Clock divider for sleep mode */
++#define LTQ_SPI_CLC_SMC_MASK 0xFF
++#define LTQ_SPI_CLC_RMC_SHIFT 8 /* Clock divider for normal run mode */
++#define LTQ_SPI_CLC_RMC_MASK 0xFF
++#define LTQ_SPI_CLC_DISS BIT(1) /* Disable status bit */
++#define LTQ_SPI_CLC_DISR BIT(0) /* Disable request bit */
++
++#define LTQ_SPI_ID_TXFS_SHIFT 24 /* Implemented TX FIFO size */
++#define LTQ_SPI_ID_TXFS_MASK 0x3F
++#define LTQ_SPI_ID_RXFS_SHIFT 16 /* Implemented RX FIFO size */
++#define LTQ_SPI_ID_RXFS_MASK 0x3F
++#define LTQ_SPI_ID_REV_MASK 0x1F /* Hardware revision number */
++#define LTQ_SPI_ID_CFG BIT(5) /* DMA interface support */
++
++#define LTQ_SPI_CON_BM_SHIFT 16 /* Data width selection */
++#define LTQ_SPI_CON_BM_MASK 0x1F
++#define LTQ_SPI_CON_EM BIT(24) /* Echo mode */
++#define LTQ_SPI_CON_IDLE BIT(23) /* Idle bit value */
++#define LTQ_SPI_CON_ENBV BIT(22) /* Enable byte valid control */
++#define LTQ_SPI_CON_RUEN BIT(12) /* Receive underflow error enable */
++#define LTQ_SPI_CON_TUEN BIT(11) /* Transmit underflow error enable */
++#define LTQ_SPI_CON_AEN BIT(10) /* Abort error enable */
++#define LTQ_SPI_CON_REN BIT(9) /* Receive overflow error enable */
++#define LTQ_SPI_CON_TEN BIT(8) /* Transmit overflow error enable */
++#define LTQ_SPI_CON_LB BIT(7) /* Loopback control */
++#define LTQ_SPI_CON_PO BIT(6) /* Clock polarity control */
++#define LTQ_SPI_CON_PH BIT(5) /* Clock phase control */
++#define LTQ_SPI_CON_HB BIT(4) /* Heading control */
++#define LTQ_SPI_CON_RXOFF BIT(1) /* Switch receiver off */
++#define LTQ_SPI_CON_TXOFF BIT(0) /* Switch transmitter off */
++
++#define LTQ_SPI_STAT_RXBV_MASK 0x7
++#define LTQ_SPI_STAT_RXBV_SHIFT 28
++#define LTQ_SPI_STAT_BSY BIT(13) /* Busy flag */
++#define LTQ_SPI_STAT_RUE BIT(12) /* Receive underflow error flag */
++#define LTQ_SPI_STAT_TUE BIT(11) /* Transmit underflow error flag */
++#define LTQ_SPI_STAT_AE BIT(10) /* Abort error flag */
++#define LTQ_SPI_STAT_RE BIT(9) /* Receive error flag */
++#define LTQ_SPI_STAT_TE BIT(8) /* Transmit error flag */
++#define LTQ_SPI_STAT_MS BIT(1) /* Master/slave select bit */
++#define LTQ_SPI_STAT_EN BIT(0) /* Enable bit */
++
++#define LTQ_SPI_WHBSTATE_SETTUE BIT(15) /* Set transmit underflow error flag */
++#define LTQ_SPI_WHBSTATE_SETAE BIT(14) /* Set abort error flag */
++#define LTQ_SPI_WHBSTATE_SETRE BIT(13) /* Set receive error flag */
++#define LTQ_SPI_WHBSTATE_SETTE BIT(12) /* Set transmit error flag */
++#define LTQ_SPI_WHBSTATE_CLRTUE BIT(11) /* Clear transmit underflow error flag */
++#define LTQ_SPI_WHBSTATE_CLRAE BIT(10) /* Clear abort error flag */
++#define LTQ_SPI_WHBSTATE_CLRRE BIT(9) /* Clear receive error flag */
++#define LTQ_SPI_WHBSTATE_CLRTE BIT(8) /* Clear transmit error flag */
++#define LTQ_SPI_WHBSTATE_SETME BIT(7) /* Set mode error flag */
++#define LTQ_SPI_WHBSTATE_CLRME BIT(6) /* Clear mode error flag */
++#define LTQ_SPI_WHBSTATE_SETRUE BIT(5) /* Set receive underflow error flag */
++#define LTQ_SPI_WHBSTATE_CLRRUE BIT(4) /* Clear receive underflow error flag */
++#define LTQ_SPI_WHBSTATE_SETMS BIT(3) /* Set master select bit */
++#define LTQ_SPI_WHBSTATE_CLRMS BIT(2) /* Clear master select bit */
++#define LTQ_SPI_WHBSTATE_SETEN BIT(1) /* Set enable bit (operational mode) */
++#define LTQ_SPI_WHBSTATE_CLREN BIT(0) /* Clear enable bit (config mode */
++#define LTQ_SPI_WHBSTATE_CLR_ERRORS 0x0F50
++
++#define LTQ_SPI_RXFCON_RXFITL_SHIFT 8 /* FIFO interrupt trigger level */
++#define LTQ_SPI_RXFCON_RXFITL_MASK 0x3F
++#define LTQ_SPI_RXFCON_RXFLU BIT(1) /* FIFO flush */
++#define LTQ_SPI_RXFCON_RXFEN BIT(0) /* FIFO enable */
++
++#define LTQ_SPI_TXFCON_TXFITL_SHIFT 8 /* FIFO interrupt trigger level */
++#define LTQ_SPI_TXFCON_TXFITL_MASK 0x3F
++#define LTQ_SPI_TXFCON_TXFLU BIT(1) /* FIFO flush */
++#define LTQ_SPI_TXFCON_TXFEN BIT(0) /* FIFO enable */
++
++#define LTQ_SPI_FSTAT_RXFFL_MASK 0x3f
++#define LTQ_SPI_FSTAT_RXFFL_SHIFT 0
++#define LTQ_SPI_FSTAT_TXFFL_MASK 0x3f
++#define LTQ_SPI_FSTAT_TXFFL_SHIFT 8
++
++#define LTQ_SPI_GPOCON_ISCSBN_SHIFT 8
++#define LTQ_SPI_GPOCON_INVOUTN_SHIFT 0
++
++#define LTQ_SPI_FGPO_SETOUTN_SHIFT 8
++#define LTQ_SPI_FGPO_CLROUTN_SHIFT 0
++
++#define LTQ_SPI_RXREQ_RXCNT_MASK 0xFFFF /* Receive count value */
++#define LTQ_SPI_RXCNT_TODO_MASK 0xFFFF /* Recevie to-do value */
++
++#define LTQ_SPI_IRNEN_F BIT(3) /* Frame end interrupt request */
++#define LTQ_SPI_IRNEN_E BIT(2) /* Error end interrupt request */
++#define LTQ_SPI_IRNEN_T BIT(1) /* Transmit end interrupt request */
++#define LTQ_SPI_IRNEN_R BIT(0) /* Receive end interrupt request */
++#define LTQ_SPI_IRNEN_ALL 0xF
++
++/* Hard-wired GPIOs used by SPI controller */
++#define LTQ_SPI_GPIO_DI 16
++#define LTQ_SPI_GPIO_DO 17
++#define LTQ_SPI_GPIO_CLK 18
++
++struct ltq_spi {
++ struct spi_bitbang bitbang;
++ struct completion done;
++ spinlock_t lock;
++
++ struct device *dev;
++ void __iomem *base;
++ struct clk *clk;
++
++ int status;
++ int irq[3];
++
++ const u8 *tx;
++ u8 *rx;
++ u32 tx_cnt;
++ u32 rx_cnt;
++ u32 len;
++ struct spi_transfer *curr_transfer;
++
++ u32 (*get_tx) (struct ltq_spi *);
++
++ u16 txfs;
++ u16 rxfs;
++ unsigned dma_support:1;
++ unsigned cfg_mode:1;
++
++};
++
++struct ltq_spi_controller_state {
++ void (*cs_activate) (struct spi_device *);
++ void (*cs_deactivate) (struct spi_device *);
++};
++
++struct ltq_spi_irq_map {
++ char *name;
++ irq_handler_t handler;
++};
++
++struct ltq_spi_cs_gpio_map {
++ unsigned gpio;
++ unsigned altsel0;
++ unsigned altsel1;
++};
++
++static inline struct ltq_spi *ltq_spi_to_hw(struct spi_device *spi)
++{
++ return spi_master_get_devdata(spi->master);
++}
++
++static inline u32 ltq_spi_reg_read(struct ltq_spi *hw, u32 reg)
++{
++ return ioread32be(hw->base + reg);
++}
++
++static inline void ltq_spi_reg_write(struct ltq_spi *hw, u32 val, u32 reg)
++{
++ iowrite32be(val, hw->base + reg);
++}
++
++static inline void ltq_spi_reg_setbit(struct ltq_spi *hw, u32 bits, u32 reg)
++{
++ u32 val;
++
++ val = ltq_spi_reg_read(hw, reg);
++ val |= bits;
++ ltq_spi_reg_write(hw, val, reg);
++}
++
++static inline void ltq_spi_reg_clearbit(struct ltq_spi *hw, u32 bits, u32 reg)
++{
++ u32 val;
++
++ val = ltq_spi_reg_read(hw, reg);
++ val &= ~bits;
++ ltq_spi_reg_write(hw, val, reg);
++}
++
++static void ltq_spi_hw_enable(struct ltq_spi *hw)
++{
++ u32 clc;
++
++ /* Power-up mdule */
++ ltq_pmu_enable(PMU_SPI);
++
++ /*
++ * Set clock divider for run mode to 1 to
++ * run at same frequency as FPI bus
++ */
++ clc = (1 << LTQ_SPI_CLC_RMC_SHIFT);
++ ltq_spi_reg_write(hw, clc, LTQ_SPI_CLC);
++}
++
++static void ltq_spi_hw_disable(struct ltq_spi *hw)
++{
++ /* Set clock divider to 0 and set module disable bit */
++ ltq_spi_reg_write(hw, LTQ_SPI_CLC_DISS, LTQ_SPI_CLC);
++
++ /* Power-down mdule */
++ ltq_pmu_disable(PMU_SPI);
++}
++
++static void ltq_spi_reset_fifos(struct ltq_spi *hw)
++{
++ u32 val;
++
++ /*
++ * Enable and flush FIFOs. Set interrupt trigger level to
++ * half of FIFO count implemented in hardware.
++ */
++ if (hw->txfs > 1) {
++ val = hw->txfs << (LTQ_SPI_TXFCON_TXFITL_SHIFT - 1);
++ val |= LTQ_SPI_TXFCON_TXFEN | LTQ_SPI_TXFCON_TXFLU;
++ ltq_spi_reg_write(hw, val, LTQ_SPI_TXFCON);
++ }
++
++ if (hw->rxfs > 1) {
++ val = hw->rxfs << (LTQ_SPI_RXFCON_RXFITL_SHIFT - 1);
++ val |= LTQ_SPI_RXFCON_RXFEN | LTQ_SPI_RXFCON_RXFLU;
++ ltq_spi_reg_write(hw, val, LTQ_SPI_RXFCON);
++ }
++}
++
++static inline int ltq_spi_wait_ready(struct ltq_spi *hw)
++{
++ u32 stat;
++ unsigned long timeout;
++
++ timeout = jiffies + msecs_to_jiffies(200);
++
++ do {
++ stat = ltq_spi_reg_read(hw, LTQ_SPI_STAT);
++ if (!(stat & LTQ_SPI_STAT_BSY))
++ return 0;
++
++ cond_resched();
++ } while (!time_after_eq(jiffies, timeout));
++
++ dev_err(hw->dev, "SPI wait ready timed out\n");
++
++ return -ETIMEDOUT;
++}
++
++static void ltq_spi_config_mode_set(struct ltq_spi *hw)
++{
++ if (hw->cfg_mode)
++ return;
++
++ /*
++ * Putting the SPI module in config mode is only safe if no
++ * transfer is in progress as indicated by busy flag STATE.BSY.
++ */
++ if (ltq_spi_wait_ready(hw)) {
++ ltq_spi_reset_fifos(hw);
++ hw->status = -ETIMEDOUT;
++ }
++ ltq_spi_reg_write(hw, LTQ_SPI_WHBSTATE_CLREN, LTQ_SPI_WHBSTATE);
++
++ hw->cfg_mode = 1;
++}
++
++static void ltq_spi_run_mode_set(struct ltq_spi *hw)
++{
++ if (!hw->cfg_mode)
++ return;
++
++ ltq_spi_reg_write(hw, LTQ_SPI_WHBSTATE_SETEN, LTQ_SPI_WHBSTATE);
++
++ hw->cfg_mode = 0;
++}
++
++static u32 ltq_spi_tx_word_u8(struct ltq_spi *hw)
++{
++ const u8 *tx = hw->tx;
++ u32 data = *tx++;
++
++ hw->tx_cnt++;
++ hw->tx++;
++
++ return data;
++}
++
++static u32 ltq_spi_tx_word_u16(struct ltq_spi *hw)
++{
++ const u16 *tx = (u16 *) hw->tx;
++ u32 data = *tx++;
++
++ hw->tx_cnt += 2;
++ hw->tx += 2;
++
++ return data;
++}
++
++static u32 ltq_spi_tx_word_u32(struct ltq_spi *hw)
++{
++ const u32 *tx = (u32 *) hw->tx;
++ u32 data = *tx++;
++
++ hw->tx_cnt += 4;
++ hw->tx += 4;
++
++ return data;
++}
++
++static void ltq_spi_bits_per_word_set(struct spi_device *spi)
++{
++ struct ltq_spi *hw = ltq_spi_to_hw(spi);
++ u32 bm;
++ u8 bits_per_word = spi->bits_per_word;
++
++ /*
++ * Use either default value of SPI device or value
++ * from current transfer.
++ */
++ if (hw->curr_transfer && hw->curr_transfer->bits_per_word)
++ bits_per_word = hw->curr_transfer->bits_per_word;
++
++ if (bits_per_word <= 8)
++ hw->get_tx = ltq_spi_tx_word_u8;
++ else if (bits_per_word <= 16)
++ hw->get_tx = ltq_spi_tx_word_u16;
++ else if (bits_per_word <= 32)
++ hw->get_tx = ltq_spi_tx_word_u32;
++
++ /* CON.BM value = bits_per_word - 1 */
++ bm = (bits_per_word - 1) << LTQ_SPI_CON_BM_SHIFT;
++
++ ltq_spi_reg_clearbit(hw, LTQ_SPI_CON_BM_MASK <<
++ LTQ_SPI_CON_BM_SHIFT, LTQ_SPI_CON);
++ ltq_spi_reg_setbit(hw, bm, LTQ_SPI_CON);
++}
++
++static void ltq_spi_speed_set(struct spi_device *spi)
++{
++ struct ltq_spi *hw = ltq_spi_to_hw(spi);
++ u32 br, max_speed_hz, spi_clk;
++ u32 speed_hz = spi->max_speed_hz;
++
++ /*
++ * Use either default value of SPI device or value
++ * from current transfer.
++ */
++ if (hw->curr_transfer && hw->curr_transfer->speed_hz)
++ speed_hz = hw->curr_transfer->speed_hz;
++
++ /*
++ * SPI module clock is derived from FPI bus clock dependent on
++ * divider value in CLC.RMS which is always set to 1.
++ */
++ spi_clk = clk_get_rate(hw->clk);
++
++ /*
++ * Maximum SPI clock frequency in master mode is half of
++ * SPI module clock frequency. Maximum reload value of
++ * baudrate generator BR is 2^16.
++ */
++ max_speed_hz = spi_clk / 2;
++ if (speed_hz >= max_speed_hz)
++ br = 0;
++ else
++ br = (max_speed_hz / speed_hz) - 1;
++
++ if (br > 0xFFFF)
++ br = 0xFFFF;
++
++ ltq_spi_reg_write(hw, br, LTQ_SPI_BRT);
++}
++
++static void ltq_spi_clockmode_set(struct spi_device *spi)
++{
++ struct ltq_spi *hw = ltq_spi_to_hw(spi);
++ u32 con;
++
++ con = ltq_spi_reg_read(hw, LTQ_SPI_CON);
++
++ /*
++ * SPI mode mapping in CON register:
++ * Mode CPOL CPHA CON.PO CON.PH
++ * 0 0 0 0 1
++ * 1 0 1 0 0
++ * 2 1 0 1 1
++ * 3 1 1 1 0
++ */
++ if (spi->mode & SPI_CPHA)
++ con &= ~LTQ_SPI_CON_PH;
++ else
++ con |= LTQ_SPI_CON_PH;
++
++ if (spi->mode & SPI_CPOL)
++ con |= LTQ_SPI_CON_PO;
++ else
++ con &= ~LTQ_SPI_CON_PO;
++
++ /* Set heading control */
++ if (spi->mode & SPI_LSB_FIRST)
++ con &= ~LTQ_SPI_CON_HB;
++ else
++ con |= LTQ_SPI_CON_HB;
++
++ ltq_spi_reg_write(hw, con, LTQ_SPI_CON);
++}
++
++static void ltq_spi_xmit_set(struct ltq_spi *hw, struct spi_transfer *t)
++{
++ u32 con;
++
++ con = ltq_spi_reg_read(hw, LTQ_SPI_CON);
++
++ if (t) {
++ if (t->tx_buf && t->rx_buf) {
++ con &= ~(LTQ_SPI_CON_TXOFF | LTQ_SPI_CON_RXOFF);
++ } else if (t->rx_buf) {
++ con &= ~LTQ_SPI_CON_RXOFF;
++ con |= LTQ_SPI_CON_TXOFF;
++ } else if (t->tx_buf) {
++ con &= ~LTQ_SPI_CON_TXOFF;
++ con |= LTQ_SPI_CON_RXOFF;
++ }
++ } else
++ con |= (LTQ_SPI_CON_TXOFF | LTQ_SPI_CON_RXOFF);
++
++ ltq_spi_reg_write(hw, con, LTQ_SPI_CON);
++}
++
++static void ltq_spi_gpio_cs_activate(struct spi_device *spi)
++{
++ struct ltq_spi_controller_data *cdata = spi->controller_data;
++ int val = spi->mode & SPI_CS_HIGH ? 1 : 0;
++
++ gpio_set_value(cdata->gpio, val);
++}
++
++static void ltq_spi_gpio_cs_deactivate(struct spi_device *spi)
++{
++ struct ltq_spi_controller_data *cdata = spi->controller_data;
++ int val = spi->mode & SPI_CS_HIGH ? 0 : 1;
++
++ gpio_set_value(cdata->gpio, val);
++}
++
++static void ltq_spi_internal_cs_activate(struct spi_device *spi)
++{
++ struct ltq_spi *hw = ltq_spi_to_hw(spi);
++ u32 fgpo;
++
++ fgpo = (1 << (spi->chip_select + LTQ_SPI_FGPO_CLROUTN_SHIFT));
++ ltq_spi_reg_setbit(hw, fgpo, LTQ_SPI_FGPO);
++}
++
++static void ltq_spi_internal_cs_deactivate(struct spi_device *spi)
++{
++ struct ltq_spi *hw = ltq_spi_to_hw(spi);
++ u32 fgpo;
++
++ fgpo = (1 << (spi->chip_select + LTQ_SPI_FGPO_SETOUTN_SHIFT));
++ ltq_spi_reg_setbit(hw, fgpo, LTQ_SPI_FGPO);
++}
++
++static void ltq_spi_chipselect(struct spi_device *spi, int cs)
++{
++ struct ltq_spi *hw = ltq_spi_to_hw(spi);
++ struct ltq_spi_controller_state *cstate = spi->controller_state;
++
++ switch (cs) {
++ case BITBANG_CS_ACTIVE:
++ ltq_spi_bits_per_word_set(spi);
++ ltq_spi_speed_set(spi);
++ ltq_spi_clockmode_set(spi);
++ ltq_spi_run_mode_set(hw);
++
++ cstate->cs_activate(spi);
++ break;
++
++ case BITBANG_CS_INACTIVE:
++ cstate->cs_deactivate(spi);
++
++ ltq_spi_config_mode_set(hw);
++
++ break;
++ }
++}
++
++static int ltq_spi_setup_transfer(struct spi_device *spi,
++ struct spi_transfer *t)
++{
++ struct ltq_spi *hw = ltq_spi_to_hw(spi);
++ u8 bits_per_word = spi->bits_per_word;
++
++ hw->curr_transfer = t;
++
++ if (t && t->bits_per_word)
++ bits_per_word = t->bits_per_word;
++
++ if (bits_per_word > 32)
++ return -EINVAL;
++
++ ltq_spi_config_mode_set(hw);
++
++ return 0;
++}
++
++static const struct ltq_spi_cs_gpio_map ltq_spi_cs[] = {
++ { 15, 1, 0 },
++ { 22, 1, 0 },
++ { 13, 0, 1 },
++ { 10, 0, 1 },
++ { 9, 0, 1 },
++ { 11, 1, 1 },
++};
++
++static int ltq_spi_setup(struct spi_device *spi)
++{
++ struct ltq_spi *hw = ltq_spi_to_hw(spi);
++ struct ltq_spi_controller_data *cdata = spi->controller_data;
++ struct ltq_spi_controller_state *cstate;
++ u32 gpocon, fgpo;
++ int ret;
++
++ /* Set default word length to 8 if not set */
++ if (!spi->bits_per_word)
++ spi->bits_per_word = 8;
++
++ if (spi->bits_per_word > 32)
++ return -EINVAL;
++
++ if (!spi->controller_state) {
++ cstate = kzalloc(sizeof(struct ltq_spi_controller_state),
++ GFP_KERNEL);
++ if (!cstate)
++ return -ENOMEM;
++
++ spi->controller_state = cstate;
++ } else
++ return 0;
++
++ /*
++ * Up to six GPIOs can be connected to the SPI module
++ * via GPIO alternate function to control the chip select lines.
++ * For more flexibility in board layout this driver can also control
++ * the CS lines via GPIO API. If GPIOs should be used, board setup code
++ * have to register the SPI device with struct ltq_spi_controller_data
++ * attached.
++ */
++ if (cdata && cdata->gpio) {
++ ret = gpio_request(cdata->gpio, "spi-cs");
++ if (ret)
++ return -EBUSY;
++
++ ret = spi->mode & SPI_CS_HIGH ? 0 : 1;
++ gpio_direction_output(cdata->gpio, ret);
++
++ cstate->cs_activate = ltq_spi_gpio_cs_activate;
++ cstate->cs_deactivate = ltq_spi_gpio_cs_deactivate;
++ } else {
++ ret = ltq_gpio_request(ltq_spi_cs[spi->chip_select].gpio,
++ ltq_spi_cs[spi->chip_select].altsel0,
++ ltq_spi_cs[spi->chip_select].altsel1,
++ 1, "spi-cs");
++ if (ret)
++ return -EBUSY;
++
++ gpocon = (1 << (spi->chip_select +
++ LTQ_SPI_GPOCON_ISCSBN_SHIFT));
++
++ if (spi->mode & SPI_CS_HIGH)
++ gpocon |= (1 << spi->chip_select);
++
++ fgpo = (1 << (spi->chip_select + LTQ_SPI_FGPO_SETOUTN_SHIFT));
++
++ ltq_spi_reg_setbit(hw, gpocon, LTQ_SPI_GPOCON);
++ ltq_spi_reg_setbit(hw, fgpo, LTQ_SPI_FGPO);
++
++ cstate->cs_activate = ltq_spi_internal_cs_activate;
++ cstate->cs_deactivate = ltq_spi_internal_cs_deactivate;
++ }
++
++ return 0;
++}
++
++static void ltq_spi_cleanup(struct spi_device *spi)
++{
++ struct ltq_spi_controller_data *cdata = spi->controller_data;
++ struct ltq_spi_controller_state *cstate = spi->controller_state;
++ unsigned gpio;
++
++ if (cdata && cdata->gpio)
++ gpio = cdata->gpio;
++ else
++ gpio = ltq_spi_cs[spi->chip_select].gpio;
++
++ gpio_free(gpio);
++ kfree(cstate);
++}
++
++static void ltq_spi_txfifo_write(struct ltq_spi *hw)
++{
++ u32 fstat, data;
++ u16 fifo_space;
++
++ /* Determine how much FIFOs are free for TX data */
++ fstat = ltq_spi_reg_read(hw, LTQ_SPI_FSTAT);
++ fifo_space = hw->txfs - ((fstat >> LTQ_SPI_FSTAT_TXFFL_SHIFT) &
++ LTQ_SPI_FSTAT_TXFFL_MASK);
++
++ if (!fifo_space)
++ return;
++
++ while (hw->tx_cnt < hw->len && fifo_space) {
++ data = hw->get_tx(hw);
++ ltq_spi_reg_write(hw, data, LTQ_SPI_TB);
++ fifo_space--;
++ }
++}
++
++static void ltq_spi_rxfifo_read(struct ltq_spi *hw)
++{
++ u32 fstat, data, *rx32;
++ u16 fifo_fill;
++ u8 rxbv, shift, *rx8;
++
++ /* Determine how much FIFOs are filled with RX data */
++ fstat = ltq_spi_reg_read(hw, LTQ_SPI_FSTAT);
++ fifo_fill = ((fstat >> LTQ_SPI_FSTAT_RXFFL_SHIFT)
++ & LTQ_SPI_FSTAT_RXFFL_MASK);
++
++ if (!fifo_fill)
++ return;
++
++ /*
++ * The 32 bit FIFO is always used completely independent from the
++ * bits_per_word value. Thus four bytes have to be read at once
++ * per FIFO.
++ */
++ rx32 = (u32 *) hw->rx;
++ while (hw->len - hw->rx_cnt >= 4 && fifo_fill) {
++ *rx32++ = ltq_spi_reg_read(hw, LTQ_SPI_RB);
++ hw->rx_cnt += 4;
++ hw->rx += 4;
++ fifo_fill--;
++ }
++
++ /*
++ * If there are remaining bytes, read byte count from STAT.RXBV
++ * register and read the data byte-wise.
++ */
++ while (fifo_fill && hw->rx_cnt < hw->len) {
++ rxbv = (ltq_spi_reg_read(hw, LTQ_SPI_STAT) >>
++ LTQ_SPI_STAT_RXBV_SHIFT) & LTQ_SPI_STAT_RXBV_MASK;
++ data = ltq_spi_reg_read(hw, LTQ_SPI_RB);
++
++ shift = (rxbv - 1) * 8;
++ rx8 = hw->rx;
++
++ while (rxbv) {
++ *rx8++ = (data >> shift) & 0xFF;
++ rxbv--;
++ shift -= 8;
++ hw->rx_cnt++;
++ hw->rx++;
++ }
++
++ fifo_fill--;
++ }
++}
++
++static void ltq_spi_rxreq_set(struct ltq_spi *hw)
++{
++ u32 rxreq, rxreq_max, rxtodo;
++
++ rxtodo = ltq_spi_reg_read(hw, LTQ_SPI_RXCNT) & LTQ_SPI_RXCNT_TODO_MASK;
++
++ /*
++ * In RX-only mode the serial clock is activated only after writing
++ * the expected amount of RX bytes into RXREQ register.
++ * To avoid receive overflows at high clocks it is better to request
++ * only the amount of bytes that fits into all FIFOs. This value
++ * depends on the FIFO size implemented in hardware.
++ */
++ rxreq = hw->len - hw->rx_cnt;
++ rxreq_max = hw->rxfs << 2;
++ rxreq = min(rxreq_max, rxreq);
++
++ if (!rxtodo && rxreq)
++ ltq_spi_reg_write(hw, rxreq, LTQ_SPI_RXREQ);
++}
++
++static inline void ltq_spi_complete(struct ltq_spi *hw)
++{
++ complete(&hw->done);
++}
++
++irqreturn_t ltq_spi_tx_irq(int irq, void *data)
++{
++ struct ltq_spi *hw = data;
++ unsigned long flags;
++ int completed = 0;
++
++ spin_lock_irqsave(&hw->lock, flags);
++
++ if (hw->tx_cnt < hw->len)
++ ltq_spi_txfifo_write(hw);
++
++ if (hw->tx_cnt == hw->len)
++ completed = 1;
++
++ spin_unlock_irqrestore(&hw->lock, flags);
++
++ if (completed)
++ ltq_spi_complete(hw);
++
++ return IRQ_HANDLED;
++}
++
++irqreturn_t ltq_spi_rx_irq(int irq, void *data)
++{
++ struct ltq_spi *hw = data;
++ unsigned long flags;
++ int completed = 0;
++
++ spin_lock_irqsave(&hw->lock, flags);
++
++ if (hw->rx_cnt < hw->len) {
++ ltq_spi_rxfifo_read(hw);
++
++ if (hw->tx && hw->tx_cnt < hw->len)
++ ltq_spi_txfifo_write(hw);
++ }
++
++ if (hw->rx_cnt == hw->len)
++ completed = 1;
++ else if (!hw->tx)
++ ltq_spi_rxreq_set(hw);
++
++ spin_unlock_irqrestore(&hw->lock, flags);
++
++ if (completed)
++ ltq_spi_complete(hw);
++
++ return IRQ_HANDLED;
++}
++
++irqreturn_t ltq_spi_err_irq(int irq, void *data)
++{
++ struct ltq_spi *hw = data;
++ unsigned long flags;
++
++ spin_lock_irqsave(&hw->lock, flags);
++
++ /* Disable all interrupts */
++ ltq_spi_reg_clearbit(hw, LTQ_SPI_IRNEN_ALL, LTQ_SPI_IRNEN);
++
++ /* Clear all error flags */
++ ltq_spi_reg_write(hw, LTQ_SPI_WHBSTATE_CLR_ERRORS, LTQ_SPI_WHBSTATE);
++
++ /* Flush FIFOs */
++ ltq_spi_reg_setbit(hw, LTQ_SPI_RXFCON_RXFLU, LTQ_SPI_RXFCON);
++ ltq_spi_reg_setbit(hw, LTQ_SPI_TXFCON_TXFLU, LTQ_SPI_TXFCON);
++
++ hw->status = -EIO;
++ spin_unlock_irqrestore(&hw->lock, flags);
++
++ ltq_spi_complete(hw);
++
++ return IRQ_HANDLED;
++}
++
++static int ltq_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
++{
++ struct ltq_spi *hw = ltq_spi_to_hw(spi);
++ u32 irq_flags = 0;
++
++ hw->tx = t->tx_buf;
++ hw->rx = t->rx_buf;
++ hw->len = t->len;
++ hw->tx_cnt = 0;
++ hw->rx_cnt = 0;
++ hw->status = 0;
++ INIT_COMPLETION(hw->done);
++
++ ltq_spi_xmit_set(hw, t);
++
++ /* Enable error interrupts */
++ ltq_spi_reg_setbit(hw, LTQ_SPI_IRNEN_E, LTQ_SPI_IRNEN);
++
++ if (hw->tx) {
++ /* Initially fill TX FIFO with as much data as possible */
++ ltq_spi_txfifo_write(hw);
++ irq_flags |= LTQ_SPI_IRNEN_T;
++
++ /* Always enable RX interrupt in Full Duplex mode */
++ if (hw->rx)
++ irq_flags |= LTQ_SPI_IRNEN_R;
++ } else if (hw->rx) {
++ /* Start RX clock */
++ ltq_spi_rxreq_set(hw);
++
++ /* Enable RX interrupt to receive data from RX FIFOs */
++ irq_flags |= LTQ_SPI_IRNEN_R;
++ }
++
++ /* Enable TX or RX interrupts */
++ ltq_spi_reg_setbit(hw, irq_flags, LTQ_SPI_IRNEN);
++ wait_for_completion_interruptible(&hw->done);
++
++ /* Disable all interrupts */
++ ltq_spi_reg_clearbit(hw, LTQ_SPI_IRNEN_ALL, LTQ_SPI_IRNEN);
++
++ /*
++ * Return length of current transfer for bitbang utility code if
++ * no errors occured during transmission.
++ */
++ if (!hw->status)
++ hw->status = hw->len;
++
++ return hw->status;
++}
++
++static const struct ltq_spi_irq_map ltq_spi_irqs[] = {
++ { "spi_tx", ltq_spi_tx_irq },
++ { "spi_rx", ltq_spi_rx_irq },
++ { "spi_err", ltq_spi_err_irq },
++};
++
++static int __init ltq_spi_probe(struct platform_device *pdev)
++{
++ struct spi_master *master;
++ struct resource *r;
++ struct ltq_spi *hw;
++ struct ltq_spi_platform_data *pdata = pdev->dev.platform_data;
++ int ret, i;
++ u32 data, id;
++
++ master = spi_alloc_master(&pdev->dev, sizeof(struct ltq_spi));
++ if (!master) {
++ dev_err(&pdev->dev, "spi_alloc_master\n");
++ ret = -ENOMEM;
++ goto err;
++ }
++
++ hw = spi_master_get_devdata(master);
++
++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (r == NULL) {
++ dev_err(&pdev->dev, "platform_get_resource\n");
++ ret = -ENOENT;
++ goto err_master;
++ }
++
++ r = devm_request_mem_region(&pdev->dev, r->start, resource_size(r),
++ pdev->name);
++ if (!r) {
++ dev_err(&pdev->dev, "devm_request_mem_region\n");
++ ret = -ENXIO;
++ goto err_master;
++ }
++
++ hw->base = devm_ioremap_nocache(&pdev->dev, r->start, resource_size(r));
++ if (!hw->base) {
++ dev_err(&pdev->dev, "devm_ioremap_nocache\n");
++ ret = -ENXIO;
++ goto err_master;
++ }
++
++ hw->clk = clk_get(&pdev->dev, "fpi");
++ if (IS_ERR(hw->clk)) {
++ dev_err(&pdev->dev, "clk_get\n");
++ ret = PTR_ERR(hw->clk);
++ goto err_master;
++ }
++
++ memset(hw->irq, 0, sizeof(hw->irq));
++ for (i = 0; i < ARRAY_SIZE(ltq_spi_irqs); i++) {
++ ret = platform_get_irq_byname(pdev, ltq_spi_irqs[i].name);
++ if (0 > ret) {
++ dev_err(&pdev->dev, "platform_get_irq_byname\n");
++ goto err_irq;
++ }
++
++ hw->irq[i] = ret;
++ ret = request_irq(hw->irq[i], ltq_spi_irqs[i].handler,
++ 0, ltq_spi_irqs[i].name, hw);
++ if (ret) {
++ dev_err(&pdev->dev, "request_irq\n");
++ goto err_irq;
++ }
++ }
++
++ hw->bitbang.master = spi_master_get(master);
++ hw->bitbang.chipselect = ltq_spi_chipselect;
++ hw->bitbang.setup_transfer = ltq_spi_setup_transfer;
++ hw->bitbang.txrx_bufs = ltq_spi_txrx_bufs;
++
++ master->bus_num = pdev->id;
++ master->num_chipselect = pdata->num_chipselect;
++ master->setup = ltq_spi_setup;
++ master->cleanup = ltq_spi_cleanup;
++
++ hw->dev = &pdev->dev;
++ init_completion(&hw->done);
++ spin_lock_init(&hw->lock);
++
++ /* Set GPIO alternate functions to SPI */
++ ltq_gpio_request(LTQ_SPI_GPIO_DI, 1, 0, 0, "spi-di");
++ ltq_gpio_request(LTQ_SPI_GPIO_DO, 1, 0, 1, "spi-do");
++ ltq_gpio_request(LTQ_SPI_GPIO_CLK, 1, 0, 1, "spi-clk");
++
++ ltq_spi_hw_enable(hw);
++
++ /* Read module capabilities */
++ id = ltq_spi_reg_read(hw, LTQ_SPI_ID);
++ hw->txfs = (id >> LTQ_SPI_ID_TXFS_SHIFT) & LTQ_SPI_ID_TXFS_MASK;
++ hw->rxfs = (id >> LTQ_SPI_ID_TXFS_SHIFT) & LTQ_SPI_ID_TXFS_MASK;
++ hw->dma_support = (id & LTQ_SPI_ID_CFG) ? 1 : 0;
++
++ ltq_spi_config_mode_set(hw);
++
++ /* Enable error checking, disable TX/RX, set idle value high */
++ data = LTQ_SPI_CON_RUEN | LTQ_SPI_CON_AEN |
++ LTQ_SPI_CON_TEN | LTQ_SPI_CON_REN |
++ LTQ_SPI_CON_TXOFF | LTQ_SPI_CON_RXOFF | LTQ_SPI_CON_IDLE;
++ ltq_spi_reg_write(hw, data, LTQ_SPI_CON);
++
++ /* Enable master mode and clear error flags */
++ ltq_spi_reg_write(hw, LTQ_SPI_WHBSTATE_SETMS |
++ LTQ_SPI_WHBSTATE_CLR_ERRORS, LTQ_SPI_WHBSTATE);
++
++ /* Reset GPIO/CS registers */
++ ltq_spi_reg_write(hw, 0x0, LTQ_SPI_GPOCON);
++ ltq_spi_reg_write(hw, 0xFF00, LTQ_SPI_FGPO);
++
++ /* Enable and flush FIFOs */
++ ltq_spi_reset_fifos(hw);
++
++ ret = spi_bitbang_start(&hw->bitbang);
++ if (ret) {
++ dev_err(&pdev->dev, "spi_bitbang_start\n");
++ goto err_bitbang;
++ }
++
++ platform_set_drvdata(pdev, hw);
++
++ pr_info("Lantiq SoC SPI controller rev %u (TXFS %u, RXFS %u, DMA %u)\n",
++ id & LTQ_SPI_ID_REV_MASK, hw->txfs, hw->rxfs, hw->dma_support);
++
++ return 0;
++
++err_bitbang:
++ ltq_spi_hw_disable(hw);
++
++err_irq:
++ clk_put(hw->clk);
++
++ for (; i > 0; i--)
++ free_irq(hw->irq[i], hw);
++
++err_master:
++ spi_master_put(master);
++
++err:
++ return ret;
++}
++
++static int __exit ltq_spi_remove(struct platform_device *pdev)
++{
++ struct ltq_spi *hw = platform_get_drvdata(pdev);
++ int ret, i;
++
++ ret = spi_bitbang_stop(&hw->bitbang);
++ if (ret)
++ return ret;
++
++ platform_set_drvdata(pdev, NULL);
++
++ ltq_spi_config_mode_set(hw);
++ ltq_spi_hw_disable(hw);
++
++ for (i = 0; i < ARRAY_SIZE(hw->irq); i++)
++ if (0 < hw->irq[i])
++ free_irq(hw->irq[i], hw);
++
++ gpio_free(LTQ_SPI_GPIO_DI);
++ gpio_free(LTQ_SPI_GPIO_DO);
++ gpio_free(LTQ_SPI_GPIO_CLK);
++
++ clk_put(hw->clk);
++ spi_master_put(hw->bitbang.master);
++
++ return 0;
++}
++
++static struct platform_driver ltq_spi_driver = {
++ .driver = {
++ .name = "ltq-spi",
++ .owner = THIS_MODULE,
++ },
++ .remove = __exit_p(ltq_spi_remove),
++};
++
++static int __init ltq_spi_init(void)
++{
++ return platform_driver_probe(<q_spi_driver, ltq_spi_probe);
++}
++module_init(ltq_spi_init);
++
++static void __exit ltq_spi_exit(void)
++{
++ platform_driver_unregister(<q_spi_driver);
++}
++module_exit(ltq_spi_exit);
++
++MODULE_DESCRIPTION("Lantiq SoC SPI controller driver");
++MODULE_AUTHOR("Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:ltq-spi");
--- /dev/null
+From c7881d8d2b3aed9a90aa37dcf797328a9cfbe7b6 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Wed, 10 Aug 2011 15:32:16 +0200
+Subject: [PATCH 15/24] MIPS: lantiq: adds etop support for ase/ar9
+
+Extend the driver to handle the different DMA channel layout for AR9 and
+SoCs. The patch also adds support for the integrated PHY found on Amazon-SE
+and the gigabit switch found inside the AR9.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Signed-off-by: Thomas Langer <thomas.langer@lantiq.com>
+---
+ .../mips/include/asm/mach-lantiq/xway/lantiq_irq.h | 22 +---
+ .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 10 ++
+ arch/mips/lantiq/xway/devices.c | 11 +-
+ arch/mips/lantiq/xway/mach-easy50601.c | 5 +
+ drivers/net/lantiq_etop.c | 172 ++++++++++++++++++--
+ 5 files changed, 180 insertions(+), 40 deletions(-)
+
+Index: linux-3.0.3/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h
+===================================================================
+--- linux-3.0.3.orig/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h 2011-10-04 20:05:23.000000000 +0200
++++ linux-3.0.3/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h 2011-10-04 20:05:44.146312365 +0200
+@@ -40,26 +40,8 @@
+
+ #define MIPS_CPU_TIMER_IRQ 7
+
+-#define LTQ_DMA_CH0_INT &n