]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge omap historic
authorTony Lindgren <tony@atomide.com>
Thu, 1 Mar 2007 07:24:24 +0000 (23:24 -0800)
committerTony Lindgren <tony@atomide.com>
Thu, 1 Mar 2007 07:24:24 +0000 (23:24 -0800)
219 files changed:
Documentation/arm/OMAP/README [new file with mode: 0644]
Documentation/arm/OMAP/gpio [new file with mode: 0644]
Makefile
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/boot/.gitignore [new file with mode: 0644]
arch/arm/boot/compressed/.gitignore [new file with mode: 0644]
arch/arm/boot/compressed/Makefile
arch/arm/boot/compressed/head-omap.S [new file with mode: 0644]
arch/arm/configs/ams_delta_defconfig [new file with mode: 0644]
arch/arm/configs/n770_defconfig [new file with mode: 0644]
arch/arm/configs/n800_defconfig [new file with mode: 0644]
arch/arm/configs/omap_2430sdp_defconfig [new file with mode: 0644]
arch/arm/configs/omap_apollon_2420_defconfig [new file with mode: 0644]
arch/arm/configs/omap_generic_1510_defconfig [new file with mode: 0644]
arch/arm/configs/omap_generic_1610_defconfig [new file with mode: 0644]
arch/arm/configs/omap_generic_1710_defconfig [new file with mode: 0644]
arch/arm/configs/omap_generic_2420_defconfig [new file with mode: 0644]
arch/arm/configs/omap_h2_1610_defconfig
arch/arm/configs/omap_h3_1710_defconfig [new file with mode: 0644]
arch/arm/configs/omap_h4_2420_defconfig [new file with mode: 0644]
arch/arm/configs/omap_innovator_1510_defconfig [new file with mode: 0644]
arch/arm/configs/omap_innovator_1610_defconfig [new file with mode: 0644]
arch/arm/configs/omap_osk_5912_defconfig
arch/arm/configs/omap_perseus2_730_defconfig [new file with mode: 0644]
arch/arm/configs/palmte_defconfig [new file with mode: 0644]
arch/arm/configs/palmtt_defconfig [new file with mode: 0644]
arch/arm/configs/palmz71_defconfig [new file with mode: 0644]
arch/arm/configs/sx1_defconfig [new file with mode: 0644]
arch/arm/mach-omap1/board-h2.c
arch/arm/mach-omap1/clock.c
arch/arm/mach-omap1/devices.c
arch/arm/mach-omap1/time.c
arch/arm/mach-omap2/board-2430sdp.c
arch/arm/mach-omap2/board-h4.c
arch/arm/oprofile/Makefile
arch/arm/oprofile/common.c
arch/arm/oprofile/op_arm_model.h
arch/arm/oprofile/op_model_v6.c [new file with mode: 0644]
arch/arm/plat-omap/Kconfig
arch/arm/plat-omap/Makefile
arch/arm/plat-omap/bootreason.c [new file with mode: 0644]
arch/arm/plat-omap/clock.c
arch/arm/plat-omap/common.c
arch/arm/plat-omap/component-version.c [new file with mode: 0644]
arch/arm/plat-omap/devices.c
arch/arm/plat-omap/dsp/dsp.h [new file with mode: 0644]
arch/arm/plat-omap/dsp/dsp_common.c
arch/arm/plat-omap/dsp/dsp_core.c [new file with mode: 0644]
arch/arm/plat-omap/dsp/dsp_ctl.c [new file with mode: 0644]
arch/arm/plat-omap/dsp/dsp_ctl_core.c [new file with mode: 0644]
arch/arm/plat-omap/dsp/dsp_mbcmd.h [new file with mode: 0644]
arch/arm/plat-omap/dsp/dsp_mem.c [new file with mode: 0644]
arch/arm/plat-omap/dsp/error.c [new file with mode: 0644]
arch/arm/plat-omap/dsp/fifo.h [new file with mode: 0644]
arch/arm/plat-omap/dsp/ioctl.h [new file with mode: 0644]
arch/arm/plat-omap/dsp/ipbuf.c [new file with mode: 0644]
arch/arm/plat-omap/dsp/ipbuf.h [new file with mode: 0644]
arch/arm/plat-omap/dsp/mblog.c [new file with mode: 0644]
arch/arm/plat-omap/dsp/proclist.h [new file with mode: 0644]
arch/arm/plat-omap/dsp/task.c [new file with mode: 0644]
arch/arm/plat-omap/dsp/taskwatch.c [new file with mode: 0644]
arch/arm/plat-omap/dsp/uaccess_dsp.S [new file with mode: 0644]
arch/arm/plat-omap/dsp/uaccess_dsp.h [new file with mode: 0644]
arch/arm/plat-omap/gpio-switch.c [new file with mode: 0644]
arch/arm/plat-omap/gpio.c
arch/arm/plat-omap/mailbox.c
arch/arm/plat-omap/sti/Makefile [new file with mode: 0644]
arch/arm/plat-omap/sti/sti-console.c [new file with mode: 0644]
arch/arm/plat-omap/sti/sti-fifo.c [new file with mode: 0644]
arch/arm/plat-omap/sti/sti-netlink.c [new file with mode: 0644]
arch/arm/plat-omap/sti/sti.c [new file with mode: 0644]
arch/arm/plat-omap/timer32k.c
drivers/Kconfig
drivers/Makefile
drivers/bluetooth/Kconfig
drivers/bluetooth/Makefile
drivers/bluetooth/brf6150.c [new file with mode: 0644]
drivers/bluetooth/brf6150.h [new file with mode: 0644]
drivers/cbus/Kconfig
drivers/cbus/retu-pwrbutton.c
drivers/cbus/tahvo-usb.c
drivers/char/Kconfig
drivers/char/Makefile
drivers/char/hw_random/omap-rng.c
drivers/char/omap-rng.c [new file with mode: 0644]
drivers/char/omap-rtc.c [new file with mode: 0644]
drivers/char/omap-rtc.h [new file with mode: 0644]
drivers/char/watchdog/Makefile
drivers/hwmon/hwmon.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/innovator_ps2.c [new file with mode: 0644]
drivers/input/keyboard/omap-keypad.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/omap/Makefile [new file with mode: 0644]
drivers/input/touchscreen/omap/omap_ts.c [new file with mode: 0644]
drivers/input/touchscreen/omap/omap_ts.h [new file with mode: 0644]
drivers/input/touchscreen/omap/ts_hx.c [new file with mode: 0644]
drivers/input/touchscreen/tsc2102_ts.c [new file with mode: 0644]
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-omap-pwm.c [new file with mode: 0644]
drivers/leds/leds-omap.c [new file with mode: 0644]
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/omap/Kconfig [new file with mode: 0644]
drivers/media/video/omap/Makefile [new file with mode: 0644]
drivers/media/video/omap/camera_core.c [new file with mode: 0644]
drivers/media/video/omap/camera_core.h [new file with mode: 0644]
drivers/media/video/omap/camera_hw_if.h [new file with mode: 0644]
drivers/media/video/omap/h3_sensor_power.c [new file with mode: 0644]
drivers/media/video/omap/h3sensorpower.h [new file with mode: 0644]
drivers/media/video/omap/h4_sensor_power.c [new file with mode: 0644]
drivers/media/video/omap/h4sensorpower.h [new file with mode: 0644]
drivers/media/video/omap/omap16xxcam.c [new file with mode: 0644]
drivers/media/video/omap/omap16xxcam.h [new file with mode: 0644]
drivers/media/video/omap/ov9640.h [new file with mode: 0644]
drivers/media/video/omap/sensor_if.h [new file with mode: 0644]
drivers/media/video/omap/sensor_ov9640.c [new file with mode: 0644]
drivers/mmc/omap.c
drivers/mtd/cmdlinepart.c
drivers/mtd/maps/omap_nor.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/omap-hw.c [new file with mode: 0644]
drivers/mtd/nand/omap-nand-flash.c [new file with mode: 0644]
drivers/net/irda/Kconfig
drivers/net/irda/Makefile
drivers/net/irda/omap-ir.c [new file with mode: 0644]
drivers/rtc/rtc-omap.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/omap2_mcspi.c [new file with mode: 0644]
drivers/spi/omap_uwire.c [new file with mode: 0644]
drivers/spi/tsc2102.c [new file with mode: 0644]
drivers/ssi/Kconfig [new file with mode: 0644]
drivers/ssi/Makefile [new file with mode: 0644]
drivers/ssi/omap-tsc2101.c [new file with mode: 0644]
drivers/ssi/omap-tsc2101.h [new file with mode: 0644]
drivers/ssi/omap-uwire.c [new file with mode: 0644]
drivers/ssi/omap-uwire.h [new file with mode: 0644]
drivers/usb/Kconfig
drivers/usb/gadget/Kconfig
drivers/usb/gadget/omap_udc.c
drivers/usb/host/ohci-omap.c
drivers/usb/musb/Kconfig [new file with mode: 0644]
drivers/usb/musb/Makefile [new file with mode: 0644]
drivers/usb/musb/cppi_dma.c [new file with mode: 0644]
drivers/usb/musb/cppi_dma.h [new file with mode: 0644]
drivers/usb/musb/davinci.c [new file with mode: 0644]
drivers/usb/musb/davinci.h [new file with mode: 0644]
drivers/usb/musb/debug.h [new file with mode: 0644]
drivers/usb/musb/dma.h [new file with mode: 0644]
drivers/usb/musb/g_ep0.c [new file with mode: 0644]
drivers/usb/musb/musb_gadget.c [new file with mode: 0644]
drivers/usb/musb/musb_gadget.h [new file with mode: 0644]
drivers/usb/musb/musb_host.c [new file with mode: 0644]
drivers/usb/musb/musb_host.h [new file with mode: 0644]
drivers/usb/musb/musb_procfs.c [new file with mode: 0644]
drivers/usb/musb/musbdefs.h [new file with mode: 0644]
drivers/usb/musb/musbhdrc.h [new file with mode: 0644]
drivers/usb/musb/musbhsdma.c [new file with mode: 0644]
drivers/usb/musb/omap2430.c [new file with mode: 0644]
drivers/usb/musb/omap2430.h [new file with mode: 0644]
drivers/usb/musb/plat_arc.h [new file with mode: 0644]
drivers/usb/musb/plat_uds.c [new file with mode: 0644]
drivers/usb/musb/tusb6010.c [new file with mode: 0644]
drivers/usb/musb/tusb6010.h [new file with mode: 0644]
drivers/usb/musb/tusb6010_omap.c [new file with mode: 0644]
drivers/usb/musb/virthub.c [new file with mode: 0644]
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/backlight/Kconfig
drivers/video/backlight/Makefile
drivers/video/backlight/omap_bl.c [new file with mode: 0644]
drivers/video/omap/Kconfig
include/asm-arm/.gitignore [new file with mode: 0644]
include/asm-arm/arch-omap/omap-alsa.h
include/asm-arm/arch-omap/sti.h [new file with mode: 0644]
include/asm-arm/mach/flash.h
include/asm-arm/setup.h
include/linux/connector.h
include/linux/fb.h
include/linux/input.h
include/linux/spi/ads7846.h
include/linux/spi/tsc2102.h [new file with mode: 0644]
include/linux/spi/tsc2301.h [new file with mode: 0644]
include/linux/usb/musb.h [new file with mode: 0644]
kernel/printk.c
sound/arm/Kconfig
sound/arm/Makefile
sound/arm/omap/Makefile [new file with mode: 0644]
sound/arm/omap/omap-alsa-aic23-mixer.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-aic23.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-aic23.h [new file with mode: 0644]
sound/arm/omap/omap-alsa-dma.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-dma.h [new file with mode: 0644]
sound/arm/omap/omap-alsa-sx1-mixer.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-sx1-mixer.h [new file with mode: 0644]
sound/arm/omap/omap-alsa-sx1.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-sx1.h [new file with mode: 0644]
sound/arm/omap/omap-alsa-tsc2101-mixer.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-tsc2101-mixer.h [new file with mode: 0644]
sound/arm/omap/omap-alsa-tsc2101.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-tsc2101.h [new file with mode: 0644]
sound/arm/omap/omap-alsa-tsc2102-mixer.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-tsc2102.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-tsc2102.h [new file with mode: 0644]
sound/arm/omap/omap-alsa.c [new file with mode: 0644]
sound/oss/Makefile
sound/oss/omap-audio-aic23.c [new file with mode: 0644]
sound/oss/omap-audio-dma-intfc.c [new file with mode: 0644]
sound/oss/omap-audio-dma-intfc.h [new file with mode: 0644]
sound/oss/omap-audio-tsc2101.c [new file with mode: 0644]
sound/oss/omap-audio.c [new file with mode: 0644]
sound/oss/omap-audio.h [new file with mode: 0644]

diff --git a/Documentation/arm/OMAP/README b/Documentation/arm/OMAP/README
new file mode 100644 (file)
index 0000000..f8ffb68
--- /dev/null
@@ -0,0 +1,415 @@
+
+                  README for ARM based OMAP processor from TI
+                  ===========================================
+
+This is the README for Linux 2.6 on ARM based TI OMAP processors.
+
+In the first section it gives some general hints how to start with OMAP Linux.
+When successfully build a OMAP Linux kernel with help of first section and no 
+bootloader is already on the board, section 2 gives some tips how to use
+commercial JTAG tools. 
+
+In March 2004 the Linux Kernel 2.6 for ARM based TI OMAP processors was cleaned.
+The goal was to send clean patches to RMK's official ARM tree and to make it 
+easier to add new OMAP processors or boards to the kernel tree. To keep the
+kernel tree clean now, this document describes also some steps how 
+to add code for a new OMAP processor or OMAP based board to the OMAP Linux 2.6 
+kernel tree. This is what the third section of this document is about.
+
+Section 4 of this README reports some rules to be followed to write 
+clean code to make it ready for easy inclusion into public OMAP Linux kernel.
+
+For more information also see TI's 'Linux Community for Texas Instruments OMAP
+Processors' web page:
+
+http://linux.omap.com
+
+There, various downloads and resources can be found (e.g. documentation how
+to build the kernel, how to use u-boot with OMAP Linux, pre-built tool chain
+etc.).
+
+The mailing list for OMAP Linux is hosted there, too:
+
+http://linux.omap.com/mailman/listinfo
+
+
+1. General hints how to start with OMAP Linux
+--------------------------------------------------------------
+
+The minimal setup is a arm-linux-gcc cross compiler, make, and some editor.
+You will also most likely need a JTAG to flash the bootloader for the first
+time.
+
+The first step is to get a bootloader for your board, u-boot is the
+recommended one:
+
+http://www.denx.de/en/Software/GIT
+
+Then you need to compile it with the same cross compiler as you would use
+for the Linux kernel. Then you need to flash it to the board either via the
+serial port, or by using a JTAG.
+
+Once you have the bootloader running, you can compile the kernel.
+
+You can get the OMAP sources either from the OMAP GIT tree, or by
+applying patches. The OMAP GIT tree has the most up to date sources
+and is the recommended one.
+
+- Using GIT and cloning OMAP GIT tree please follow the README at:
+
+http://www.muru.com/linux/omap/README_OMAP_GIT
+
+Hint: If you are sitting behind a firewall and have to use a proxy for 
+internet access, you can access GIT by http by setting the
+http_proxy envirionment variable:
+
+http_proxy=http://proxy_username:proxy_password@proxy_name:proxy_port/
+
+If you use bash shell, then this might look like:
+
+export http_proxy=http://foo:123@abc.host.com:8080/
+
+with:
+
+foo: Your user name for the proxy
+123: Your password for the proxy
+abc.host.com: The name of your proxy you use for internet access
+8080: The port used on to access the proxy
+
+
+- Using Patches:
+
+If you don't want to use GIT, then you can do the same thing with patch.
+
+Download the latest OMAP Linux patch from:
+
+http://www.muru.com/linux/omap/
+
+Get a matching Linux kernel from:
+
+ftp://ftp.kernel.org/pub/linux/kernel/v2.6/
+
+For example, if you download Linux-2.6.4-omap1 from muru.com, then you need
+linux-2.6.4 kernel from kernel.org:
+
+$ wget ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.4.tar.bz2
+$ tar xjf linux-2.6.4.tar.bz2
+$ cd linux-2.6.4
+$ cat ../Linux-2.6.4-omap1 | patch -p1
+
+Note: If OMAP patch from muru.com is against a kernel release candidate, 
+marked by -rcX, then kernel can be found on kernel.org under v2.6/testing/
+
+Now, if you have a local kernel tree, either by GIT or by patch, you
+should look into arch/arm/configs/ to see which of the various omap_xxx
+configurations there you want to use. For example, if you have a OMAP1510
+based Innovator board, you select omap_innovator_1510_defconfig by 
+
+$ make omap_innovator_1510_defconfig
+
+at top level directory (linux-2.6.4 in the example above).
+
+Then you can compile the kernel with
+
+$ make vmlinux
+
+Or make Image or make zImage or make uImage.
+
+Once you have the kernel compiled, you can upload it to the board via serial
+port or JTAG (see below).
+
+Then you need a root file system either as initrd or on the flash.
+
+Once you have the system booting to Linux, you can use pretty much any Linux
+applications cross compiled for ARM.
+
+
+2. JTAG usage
+--------------------------------------------------------------
+
+If the flash of your board is really 'empty' and no bootloader is on the board
+(e.g. u-boot) then you need a JTAG connection. With JTAG you can write
+a bootloader to board's flash or download OMAP Linux kernel. For OMAP
+commercial JTAG tools are available, so you have to pay for it.
+
+Examples are TI's Code Composer Studio (CCS) or Lauterbach's TRACE32 JTAG.
+
+- Linux kernel download with CCS
+
+You can use CCS to directly load an ELF file to your board. For example, use  
+arch/arm/boot/compressed/vmlinux. zImage isn't suited because it is not an ELF
+file. CCS looks for .out files, so copy arch/arm/boot/compressed/vmlinux 
+to vmlinux.out and load it using CCS. Or use the filter *.* to select
+vmlinux directly. Remember to run arm-linux-strip on ELF file first as CCS 
+get stroppy about unstripped ELF files.
+
+If you want vmlinux to be linked to run at a specific address, you can use 
+the CONFIG_ZBOOT options in the kernel build. But first try without
+CONFIG_ZBOOT as the compressed image should be able to run from address
+zero (if your CCS .gel files map address zero.)
+
+Otherwise, use something like this:
+
+CONFIG_ZBOOT_ROM=y
+CONFIG_ZBOOT_ROM_TEXT=10408000
+CONFIG_ZBOOT_ROM_BSS=10800000
+
+Also note that CCS is pretty useless for debugging Linux as it doesn't
+properly handle virtual memory. In other words, once the MMU is
+turned on and Linux is using virtual memory, CCS can no longer
+properly disassemble, set breakpoints or read memory.
+
+
+- Linux kernel download with Lauterbach TRACE32
+
+To be done.
+
+
+3. How to add new processor or board to OMAP Linux kernel tree
+--------------------------------------------------------------
+
+It is assumed that the OMAP processor to be added is based on an already 
+supported ARM core (e.g. ARM925 or ARM926). How to add support for new ARM 
+processor core that is not supported by ARM Linux is not scope of this document.
+
+1. If a new OMAP processor should be added, identify the ARM core of this 
+processor. E.g. at time of writing this document in March 2004 OMAP730 (ARM926 
+core), OMAP1510 (ARM925 core) and OMAP1610 (ARM926 core) are supported.
+
+For a new board or device, identify the OMAP processor on the board. E.g. at 
+time of writing this document in March 2004 four boards are supported: 
+Innovator1510 (OMAP1510 processor), Innovator1610 (OMAP1610 processor), 
+Perseus2 (OMAP730 processor) and H2 (OMAP1610 processor).
+
+Please refer http://www.muru.com/linux/omap/ to get latest information on the
+list of boards supported.
+
+/* Discussion needed: How to handle the tons of compatible processors? 
+E.g. what to do if OMAP16xx is mainly identical with OMAP16yy? */
+
+2. Start with arch/arm/mach-omap[1/2]/Kconfig and add a new processor or board
+option.
+
+To add a new processor add a new config option to the "OMAP Core Type" choice. 
+See examples for the syntax. The config option has to be called "ARCH_OMAPxxxx" 
+where xxxx is the number of OMAP processor. Don't forget to select a existing
+clock frequency or to add a new one in "OMAP Feature Selections" section for
+your new processor. 
+
+To add a new board or device, add a new config option to the "OMAP Board Type" 
+choice. See examples for the syntax. The config option for boards has to be 
+called "MACH_OMAP_yyyy" where yyyy is the board name. Don't forget to add a 
+short help.
+
+Note: Kernel 2.6 Kconfig system will automatically expand the configuration 
+names with a leading "CONFIG_". So "ARCH_OMAPxxxx" will be expanded to 
+"CONFIG_ARCH_OMAPxxxx" and "MACH_OMAP_yyy" will expand to 
+"CONFIG_MACH_OMAP_yyyy". In code this can then be used by macros like 
+"#ifdef CONFIG_ARCH_OMAPxxxx" and "#ifdef CONFIG_MACH_OMAP_yyyy".
+
+Note: How to handle boards which are compatible or extensions of other boards? 
+See MACH_OMAP_H2 for example. The H2 depends on MACH_OMAP_INNOVATOR and expands 
+it. This is done by an additional select MACH_OMAP_INNOVATOR in MACH_OMAP_H2
+configuration option. With this the whole MACH_OMAP_INNOVATOR configuration is
+selected and an additional symbol CONFIG_MACH_OMAP_H2 is available to
+distinguish between INNOVATOR and H2 where necessary. 
+
+3a. Only for new processors: Add the ARCH_OMAPxxxx to the correct ARM core in 
+arch/arm/mm/Kconfig. E.g. ARCH_OMAP730 in CPU_ARM926T configuration.
+
+3b. Only for new boards: Register the board within ARM Linux machine 
+registration system from RMK. For the CONFIG_ section use the same name like 
+in arch/arm/mach-omap[1/2]/Kconfig. E.g. MACH_OMAP_yyyy. For MACH_TYPE_ section use
+OMAP_yyyy where yyyy is the board name like above.
+
+Note: The elements of RMKs machine registration are used in 
+arch/arm/tools/mach-types. While kernel compilation
+include/asm-arm/mach-types.h is generated automagically from this file. The
+content of mach-types.h then is used for machine identification by kernel
+bootcode and can be used for board identification.
+
+Note: The ARM Linux machine registration system from RMK can be found under:
+
+www.arm.linux.org.uk/developer/machines/
+
+Note: Only OMAP based boards should be registered to RMKs registration
+system. Not processors.
+
+4. Add a processor or board specific header file in include/asm-arm/arch-omap/. 
+Use board-yyyy.h with yyyy board name or omapxxxx.h with xxxx processor number.
+
+5. Add a processor or board specific section into include/asm-arm/arch-omap/
+hardware.h. Use examples for syntax and use CONFIG_ names as defined in 
+arch/arm/mach-omap[1/2]/Kconfig.
+
+6. Add processor or board specific macros to board-yyyy.h or omapxxxx.h. The
+macros to these specific files have to be named OMAPxxxx_ with xxxx processor
+number to make them unique.
+
+7a. Only for new boards: Add a file board-yyyy.c with yyyy board name to 
+arch/arm/mach-omap[1/2]/. Put board specific initialization code and resource
+description into this file. The first element of MACHINE_START must be equal to 
+MACH_TYPE_ section of machine registration (see arch/arm/tools/mach-types after 
+machine registration at RMKs registration system).
+
+Put only code into this file that is board specific and not common. See other 
+board files for examples.
+
+7b. Only for new processors: Add processor specific IO description and
+iotable_init() to arch/arm/mach-omap[1/2]/io.c. See examples for the syntax.
+
+If you have introduced new clock definition in 2., add support for this new
+clock in include/asm-arm/arch-omap/clocks.h and arch/arm/mach-omap[1/2]/clocks.c.
+
+8. Only for new boards: Add "obj-$(CONFIG_MACH_OMAP_yyyy) += board-yyyy.o" with 
+yyyy board name to arch/arm/mach-omap[1/2]/Makefile. This is used to compile your new
+board specific initialization code from 7a.
+
+9. Check if other of the existing files have to be adjusted for the new 
+processor or board. Things to check:
+
+- Pin multiplexing
+- GPIO configuration
+- Power Management
+- Clocking
+- Interrupt controller and interrupt configuration
+- Additional board specific things (e.g. FPGAs)
+
+If other existing files or device drivers have to be changed, use the following 
+mechanism for processor specific things:
+
+#ifdef CONFIG_ARCH_OMAPxxxx
+       if (cpu_is_omapxxxx()) {
+               /* Do the OMAPxxxx processor specific magic */
+       }
+#endif
+
+Note: cpu_is_omapxxxx() macro is defined in include/asm-arm/arch-omap/hardware.h
+and uses OMAP_ID_REG for runtime processor identifcation.
+
+For board differentiation use board macro from include/asm-arm/mach-types.h:
+
+#ifdef CONFIG_MACH_OMAP_yyyy
+       if (machine_is_omap_yyyy()) {
+               /* Do the board specific magic */
+       }
+#endif
+
+Note: If technically possible and already implemented the OMAP Linux kernel
+has support for a "one binary fits all" machanism. That is, the goal is to be
+able to enable support for multiple OMAP processors and/or boards in Kconfig
+system. Then it is decided by bootparameters and at runtime on which processor 
+and/or board the kernel is actually running on. With this machanism it is 
+possible to use the same kernel binary on different OMAP processors or boards 
+without recompiling. This is achived by the cpu_is_omapxxxx() and
+machine_is_omap_yyyy() macros.
+
+On the other hand, for memory limited embedded systems it should be possible
+to compile the kernel with support for only one processor/board combination.
+For this a kernel binary is necessary which isn't bloated with code for all
+other (unused) processors and boards. This is achived by using the preprocessor
+CONFIG_ARCH_OMAPxxxx and CONFIG_MACH_OMAP_yyyy macros around the runtime
+cpu_is_omapxxxx() and machine_is_omap_yyyy() selection.
+
+At the moment, the price for this flexibility is a increased number of #ifdef's
+throughout the code.
+
+10. Configure the kernel by make menuconfig or make xconfig and select the new 
+processor or board.
+
+11. Compile the kernel by an appropriate cross compilation toolchain. Make this
+until the code compiles error and warning free. The kernel should also be 
+compiled with the various debug checking thingies enabled (e.g.
+CONFIG_DEBUG_SPINLOCK,  CONFIG_DEBUG_PAGEALLOC etc.).
+
+/* ToDo: Anything to say about toolchain? */
+
+12. Download the kernel image to the board and test it until it works ;-)
+
+It's not in the scope of this document how to do this (use a appropriate 
+bootloader or JTAG download).
+
+Note: The kernel initialization code expects some special values in the
+registers R0, R1 and R2 of the ARM processor. These registers have to be
+written by bootloader or debugger before starting the kernel. R0 has to be
+zero, R1 has to contain the machine number from machine registration in
+arch/arm/tools/mach-types. R2 points to the physical address of tagged list
+in system RAM. For more information see Documentation/arm/Booting.
+
+While testing a new processor or board configuration, it is recommended to 
+enable low level debugging. This uses low level output functions to print kernel
+messages on serial line before console is working. Enable it by 
+
+Kernel hacking -> Kernel debugging -> Kernel low-level debugging functions
+
+in kernel configuration system.
+
+13. Check that no other processors or boards are broken by the new code. A first
+test is to successful compile the other omap_xxx configurations from 
+arch/arm/configs/. Do this by e.g.
+
+cd linux
+make omap_innovator_1510_defconfig
+Compile the kernel
+
+Even better: Enable support for several processors and boards in Kconfig
+system and compile kernel successfully.
+
+14. Only for new boards: Add a new default board configuration to 
+arch/arm/configs. Use omap_yyyy_xxxx_defconfig with yyyy boardname and xxxx 
+processornumber as filename.
+
+15. If the new code works, compiles without warnings and seems to break no other
+configurations, post a patch to linux-omap-open-source@list.ti.com.
+
+With sending a patch to the community, it is reviewed, can be used and tested by
+other users. It then can be included into the public OMAP kernel tree. 
+
+16. Then adapt device drivers or write additional drivers for non-existing 
+processor peripherals or board devices. Improve and maintain the code for your 
+new processor or board.
+
+
+4. General guidelines to write clean and OMAP Linux compatible code
+-------------------------------------------------------------------
+
+- For register access use the __REG8/16/32() macros. At the moment, see first
+example in include/asm-arm/arch-omap/hardware.h.
+
+Allegedly __REG() makes at least some versions of GCC emit tighter code
+than the more direct wrappers. Presumably by making it easier to use certain 
+addressing modes. 
+
+Make sure that the registers names are clearly marked as being registers
+(and not addresses of registers). This has to be done by adding a '_REG'
+suffix. E.g.
+
+#define OMAP_ID_REG  (__REG32(0xfffed400))
+#define DPLL_CTL_REG (__REG16(0xfffecf00))
+
+__raw_read[bwl] and __raw_write[bwl] are deprecated. They will converted to
+__REG8/16/32() syntax, soon. Don't use anything else like own pointer
+definitions or in[bwl]/out[bwl] etc., too.
+
+- Make read-modify-write register access preemption save. Use spin_lock() and 
+spin_unlock() where necessary. If an IRQ handler can access the registers, 
+use spin_lock_irqsave(), too. 
+
+- Functions declared as __init shouldn't have any references after the kernel 
+initialization phase is complete. Usually they should be static as well.
+
+- Don't use return statements at end of void functions.
+
+- Use consistent indentation style. Don't use space indentations. Use tab 
+indentations.
+
+- In general use Linux formatting style. See Documentation/CodingStyle for more
+information. If you use GNU emacs, see also chapter 8 of that document how to
+add a linux-c-mode to emacs.
+
+
+------------------------------------------------------------------
+Last modified 15. March 2006
+The OMAP Linux Kernel Team
+Dirk Behme <dirk.behme@de.bosch.com>
diff --git a/Documentation/arm/OMAP/gpio b/Documentation/arm/OMAP/gpio
new file mode 100644 (file)
index 0000000..fd6363c
--- /dev/null
@@ -0,0 +1,270 @@
+
+                         OMAP GPIO API's HowTo
+                         =====================
+
+This document is a short summary how to use OMAP Linux GPIO API. It is
+mainly focussed on OMAP5912 OSK, but should fit with extensions (more
+or less GPIOs) to other OMAP processors as well.
+
+If anything is missing, is wrong, needs extension or update, please send
+update to Linux-omap-open-source@linux.omap.com.
+
+I. GPIO Modules/Banks
+---------------------
+
+OMAP5912 OSK has 64 GPIOs (general purpose IO pins). These are organized
+in four modules (banks) with 16 pins each. OMAP GPIO API doesn't distinguish
+between modules and numbers the pins from 0 - 63:
+
+A) GPIO MODULE/BANK 0 - PIN  0-15
+B) GPIO MODULE/BANK 1 - PIN 16-31
+C) GPIO MODULE/BANK 2 - PIN 32-47
+D) GPIO MODULE/BANK 3 - PIN 48-63
+
+See
+
+http://www-s.ti.com/sc/psheets/spru767a/spru767a.pdf
+
+for more details.
+
+II. GPIO API's
+--------------
+
+A) Include
+
+#include <asm/arch/gpio.h>
+
+B) omap_cfg_reg(xxxx);
+
+Description: Configure pin mux.
+
+Parameter: Pin to be configured for GPIO.
+
+Note: This function may only be necessary for some GPIO pins. Because OMAP
+      chip itself has less real hardware pins than necessary to use all
+      its functionality at the same time, some pins share different
+      functions (called pin multiplexing, short pin mux). E.g. one pin may
+      be used for serial interface *or* GPIO. Check if this is the case for
+      the GPIO you want to use and if you have to configure the pin mux.
+
+C) omap_request_gpio(int gpio)
+
+Description: Request GPIO to be used.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+
+Note: Using this function, you dont have to worry about banks/modules where
+      the gpio pin is.
+
+D) omap_set_gpio_direction(int gpio, int is_input)
+
+Description: This function is responsible for setting the gpio pin direction
+             (input or output).
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+           int is_input - pin direction (0 = output, 1 = input)
+
+E) omap_set_gpio_dataout(int gpio, int enable)
+
+Description: This function is responsible for writing to a pin.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+           int enable - pin value (0 or 1)
+
+F) omap_get_gpio_datain(int gpio)
+
+Description: This function is responsible for reading pin values.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+
+G) omap_free_gpio(int gpio)
+
+Description: This function is responsible for freeing the pin used.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+
+H) OMAP_GPIO_IRQ(int gpio)
+
+Description: Returns the Interrupt number for the specified gpio pin.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+
+I) set_irq_type(unsigned int irq, unsigned int type)
+
+Description: This function is responsible for setting the type of interrupt
+             (RISING or FALLING).
+
+Parameter: unsigned int irq - The interrupt number for the gpio pin.
+           unsigned int type - (IRQT_RISING = rising, IRQT_FALLING= falling)
+
+
+III. Example
+------------
+
+1) Writing to gpio pin#3 a value 1 and reading the value of gpio pin#3.
+
+#include <asm/arch/gpio.h>
+
+int ret;                       /* Return value */
+
+omap_request_gpio(3);          /* Request for gpio pin */
+omap_set_gpio_direction(3,0);
+omap_set_set_dataout(3,1);     /* Writing a 1 to gpio pin # 3: */
+ret = omap_get_datain(3);      /* Reading the value of pin # 3 */
+printk("value of pin # 3 = %d\n",ret);
+omap_free_gpio(3);             /* Freeing gpio pin # 3 */
+
+2) Interrupt input by gpio pin#3
+
+#include <asm/arch/gpio.h>
+
+omap_request_gpio(3);         /* Request for gpio pin */
+omap_set_gpio_direction(3,0);
+set_irq_type(OMAP_GPIO_IRQ(3),IRQT_RISING); /* Setting up pin for interrupt */
+request_irq(OMAP_GPIO_IRQ(3), (void *)&my_int_handler, SA_SHIRQ,....);
+
+...                         /* Do stuff, handle interrupts in my_int_handler */
+
+free_irq(OMAP_GPIO_IRQ(3),&id); /*  Freeing interrupt and gpio pin */
+omap_free_gpio(3);
+
+------------------------------------------------------------------
+Last modified 14. August 2006
+The OMAP Linux Kernel Team
+Arnold <abo_gwapo@yahoo.com>
+Dirk Behme <dirk.behme@gmail.com>
+
+                         OMAP GPIO API's HowTo
+                         =====================
+
+This document is a short summary how to use OMAP Linux GPIO API. It is
+mainly focussed on OMAP5912 OSK, but should fit with extensions (more
+or less GPIOs) to other OMAP processors as well.
+
+If anything is missing, is wrong, needs extension or update, please send
+update to Linux-omap-open-source@linux.omap.com.
+
+I. GPIO Modules/Banks
+---------------------
+
+OMAP5912 OSK has 64 GPIOs (general purpose IO pins). These are organized
+in four modules (banks) with 16 pins each. OMAP GPIO API doesn't distinguish
+between modules and numbers the pins from 0 - 63:
+
+A) GPIO MODULE/BANK 0 - PIN  0-15
+B) GPIO MODULE/BANK 1 - PIN 16-31
+C) GPIO MODULE/BANK 2 - PIN 32-47
+D) GPIO MODULE/BANK 3 - PIN 48-63
+
+See
+
+http://www-s.ti.com/sc/psheets/spru767a/spru767a.pdf
+
+for more details.
+
+II. GPIO API's
+--------------
+
+A) Include
+
+#include <asm/arch/gpio.h>
+
+B) omap_cfg_reg(xxxx);
+
+Description: Configure pin mux.
+
+Parameter: Pin to be configured for GPIO.
+
+Note: This function may only be necessary for some GPIO pins. Because OMAP
+      chip itself has less real hardware pins than necessary to use all
+      its functionality at the same time, some pins share different
+      functions (called pin multiplexing, short pin mux). E.g. one pin may
+      be used for serial interface *or* GPIO. Check if this is the case for
+      the GPIO you want to use and if you have to configure the pin mux.
+
+C) omap_request_gpio(int gpio)
+
+Description: Request GPIO to be used.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+
+Note: Using this function, you dont have to worry about banks/modules where
+      the gpio pin is.
+
+D) omap_set_gpio_direction(int gpio, int is_input)
+
+Description: This function is responsible for setting the gpio pin direction
+             (input or output).
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+           int is_input - pin direction (0 = output, 1 = input)
+
+E) omap_set_gpio_dataout(int gpio, int enable)
+
+Description: This function is responsible for writing to a pin.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+           int enable - pin value (0 or 1)
+
+F) omap_get_gpio_datain(int gpio)
+
+Description: This function is responsible for reading pin values.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+
+G) omap_free_gpio(int gpio)
+
+Description: This function is responsible for freeing the pin used.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+
+H) OMAP_GPIO_IRQ(int gpio)
+
+Description: Returns the Interrupt number for the specified gpio pin.
+
+Parameter: int gpio - GPIO PIN (Pin 0-63)
+
+I) set_irq_type(unsigned int irq, unsigned int type)
+
+Description: This function is responsible for setting the type of interrupt
+             (RISING or FALLING).
+
+Parameter: unsigned int irq - The interrupt number for the gpio pin.
+           unsigned int type - (IRQT_RISING = rising, IRQT_FALLING= falling)
+
+
+III. Example
+------------
+
+1) Writing to gpio pin#3 a value 1 and reading the value of gpio pin#3.
+
+#include <asm/arch/gpio.h>
+
+int ret;                       /* Return value */
+
+omap_request_gpio(3);          /* Request for gpio pin */
+omap_set_gpio_direction(3,0);
+omap_set_set_dataout(3,1);     /* Writing a 1 to gpio pin # 3: */
+ret = omap_get_datain(3);      /* Reading the value of pin # 3 */
+printk("value of pin # 3 = %d\n",ret);
+omap_free_gpio(3);             /* Freeing gpio pin # 3 */
+
+2) Interrupt input by gpio pin#3
+
+#include <asm/arch/gpio.h>
+
+omap_request_gpio(3);         /* Request for gpio pin */
+omap_set_gpio_direction(3,0);
+set_irq_type(OMAP_GPIO_IRQ(3),IRQT_RISING); /* Setting up pin for interrupt */
+request_irq(OMAP_GPIO_IRQ(3), (void *)&my_int_handler, SA_SHIRQ,....);
+
+...                         /* Do stuff, handle interrupts in my_int_handler */
+
+free_irq(OMAP_GPIO_IRQ(3),&id); /*  Freeing interrupt and gpio pin */
+omap_free_gpio(3);
+
+------------------------------------------------------------------
+Last modified 14. August 2006
+The OMAP Linux Kernel Team
+Arnold <abo_gwapo@yahoo.com>
+Dirk Behme <dirk.behme@gmail.com>
index 7e2750f4ca707a8f009987810d6756a869128f6a..ff3d804e4e7a171ce1119a6f0d42f4bc9c2f90fa 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -16,6 +16,9 @@ NAME = Homicidal Dwarf Hamster
 # o  print "Entering directory ...";
 MAKEFLAGS += -rR --no-print-directory
 
+# Add custom flags here to avoid conflict with updates
+EXTRAVERSION := $(EXTRAVERSION)-omap1
+
 # We are using a recursive build, so we need to do a little thinking
 # to get the ordering right.
 #
@@ -163,6 +166,8 @@ SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
                                  -e s/s390x/s390/ -e s/parisc64/parisc/ \
                                  -e s/ppc.*/powerpc/ -e s/mips.*/mips/ )
 
+SUBARCH := arm
+
 # Cross compiling and selecting different set of gcc/bin-utils
 # ---------------------------------------------------------------------------
 #
@@ -183,7 +188,7 @@ SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
 # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile
 
 ARCH           ?= $(SUBARCH)
-CROSS_COMPILE  ?=
+CROSS_COMPILE  ?= arm-linux-
 
 # Architecture as present in compile.h
 UTS_MACHINE := $(ARCH)
index 8b0b9d1c718477a2a07a9458666d6210913b8da6..b5e8832e7b34e4484e0173ab88b81412841146df 100644 (file)
@@ -328,6 +328,7 @@ config ARCH_LH7A40X
 
 config ARCH_OMAP
        bool "TI OMAP"
+       select GENERIC_TIME
        help
          Support for TI's OMAP platform (OMAP1 and OMAP2).
 
@@ -620,8 +621,7 @@ config LEDS
          system, but the driver will do nothing.
 
 config LEDS_TIMER
-       bool "Timer LED" if (!ARCH_CDB89712 && !ARCH_OMAP) || \
-                           MACH_OMAP_H2 || MACH_OMAP_PERSEUS2
+       bool "Timer LED" if !ARCH_CDB89712
        depends on LEDS
        default y if ARCH_EBSA110
        help
@@ -636,8 +636,7 @@ config LEDS_TIMER
          will overrule the CPU usage LED.
 
 config LEDS_CPU
-       bool "CPU usage LED" if (!ARCH_CDB89712 && !ARCH_EBSA110 && \
-                       !ARCH_OMAP) || MACH_OMAP_H2 || MACH_OMAP_PERSEUS2
+       bool "CPU usage LED" if (!ARCH_CDB89712 && !ARCH_EBSA110)
        depends on LEDS
        help
          If you say Y here, the red LED will be used to give a good real
@@ -962,6 +961,8 @@ source "drivers/mmc/Kconfig"
 
 source "drivers/rtc/Kconfig"
 
+source "drivers/ssi/Kconfig"
+
 if ARCH_OMAP
 source "drivers/cbus/Kconfig"
 endif
index 000f1100b5538f9f69da886fc0054d2d16746864..ea39d8da957c2d6e45defda8fdcb7822f8677aec 100644 (file)
@@ -71,7 +71,7 @@ tune-$(CONFIG_CPU_SA110)      :=-mtune=strongarm110
 tune-$(CONFIG_CPU_SA1100)      :=-mtune=strongarm1100
 tune-$(CONFIG_CPU_XSCALE)      :=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale
 tune-$(CONFIG_CPU_XSC3)                :=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale
-tune-$(CONFIG_CPU_V6)          :=$(call cc-option,-mtune=arm1136j-s,-mtune=strongarm)
+tune-$(CONFIG_CPU_V6)          :=$(call cc-option,-mtune=arm1136j-s,-mtune=arm1136jfs)
 
 ifeq ($(CONFIG_AEABI),y)
 CFLAGS_ABI     :=-mabi=aapcs-linux -mno-thumb-interwork
diff --git a/arch/arm/boot/.gitignore b/arch/arm/boot/.gitignore
new file mode 100644 (file)
index 0000000..fc9b99c
--- /dev/null
@@ -0,0 +1,3 @@
+Image
+zImage
+uImage
diff --git a/arch/arm/boot/compressed/.gitignore b/arch/arm/boot/compressed/.gitignore
new file mode 100644 (file)
index 0000000..aefee20
--- /dev/null
@@ -0,0 +1 @@
+piggy.gz
index adddc71316852f5001314faf10678f5fc4e3ef8d..6bebde52d4066c410d211b9e271a6ba088076c8e 100644 (file)
@@ -50,6 +50,10 @@ ifeq ($(CONFIG_ARCH_AT91RM9200),y)
 OBJS           += head-at91rm9200.o
 endif
 
+ifeq ($(CONFIG_MACH_OMAP_PERSEUS2),y)
+OBJS           += head-omap.o
+endif
+
 ifeq ($(CONFIG_CPU_BIG_ENDIAN),y)
 ifeq ($(CONFIG_CPU_CP15),y)
 OBJS           += big-endian.o
diff --git a/arch/arm/boot/compressed/head-omap.S b/arch/arm/boot/compressed/head-omap.S
new file mode 100644 (file)
index 0000000..ba3ecca
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * linux/arch/arm/boot/compressed/head-omap.S
+ *
+ * OMAP specific tweaks.  This is merged into head.S by the linker.
+ *
+ */
+
+#include <linux/linkage.h>
+#include <asm/mach-types.h>
+
+               .section        ".start", "ax"
+
+__OMAP_start:
+#ifdef CONFIG_MACH_OMAP_PERSEUS2
+               /* support for booting without u-boot */
+               mov     r7, #(MACH_TYPE_OMAP_PERSEUS2 & ~0xf)
+               orr     r7, r7, #(MACH_TYPE_OMAP_PERSEUS2 & 0xf)
+#endif
diff --git a/arch/arm/configs/ams_delta_defconfig b/arch/arm/configs/ams_delta_defconfig
new file mode 100644 (file)
index 0000000..1986bca
--- /dev/null
@@ -0,0 +1,1217 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.18-omap1
+# Tue Oct 10 22:26:32 2006
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+# CONFIG_BLK_DEV_IO_TRACE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MCBSP=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+CONFIG_OMAP_DSP=m
+# CONFIG_OMAP_DSP_MBCMD_VERBOSE is not set
+# CONFIG_OMAP_DSP_TASK_MULTIOPEN is not set
+# CONFIG_OMAP_DSP_FBEXPORT is not set
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+CONFIG_ARCH_OMAP15XX=y
+# CONFIG_ARCH_OMAP16XX is not set
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_VOICEBLUE is not set
+# CONFIG_MACH_OMAP_PALMTE is not set
+CONFIG_MACH_AMS_DELTA=y
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
+# CONFIG_OMAP_ARM_168MHZ is not set
+CONFIG_OMAP_ARM_150MHZ=y
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM925T=y
+CONFIG_CPU_32v4T=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+CONFIG_CPU_DCACHE_WRITETHROUGH=y
+
+#
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_PREEMPT=y
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="mem=32M console=ttyS0,115200n8 root=/dev/ram0 initrd=0x11c00000,4M"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+CONFIG_MTD_NAND_AMS_DELTA=y
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+# CONFIG_MTD_ONENAND_SYNC_READ is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+CONFIG_OMAP_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+CONFIG_I2C_OMAP=y
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# LED devices
+#
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+CONFIG_LEDS_AMS_DELTA=y
+# CONFIG_LEDS_OMAP is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_LCD_MIPID is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_8x16 is not set
+CONFIG_FONT_6x11=y
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_TOUCHSCREEN is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_CATC=y
+CONFIG_USB_KAWETH=y
+CONFIG_USB_PEGASUS=y
+CONFIG_USB_RTL8150=y
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=y
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=y
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+CONFIG_USB_NET_CDC_SUBSET=y
+# CONFIG_USB_ALI_M5632 is not set
+# CONFIG_USB_AN2720 is not set
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+# CONFIG_USB_EPSON2888 is not set
+CONFIG_USB_NET_ZAURUS=y
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_UWIRE is not set
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_CODEPAGE_852=y
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=y
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_RWSEMS is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_UNWIND_INFO is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
diff --git a/arch/arm/configs/n770_defconfig b/arch/arm/configs/n770_defconfig
new file mode 100644 (file)
index 0000000..ef33d82
--- /dev/null
@@ -0,0 +1,1342 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.16-rc2-omap1
+# Fri Feb 10 15:29:21 2006
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_UID16=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# Block layer
+#
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_AT91RM9200 is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+CONFIG_OMAP_RESET_CLOCKS=y
+CONFIG_OMAP_BOOT_TAG=y
+CONFIG_OMAP_BOOT_REASON=y
+CONFIG_OMAP_COMPONENT_VERSION=y
+CONFIG_OMAP_GPIO_SWITCH=y
+# CONFIG_OMAP_MUX is not set
+CONFIG_OMAP_STI=y
+CONFIG_OMAP_STI_CONSOLE=y
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+# CONFIG_ARCH_OMAP15XX is not set
+CONFIG_ARCH_OMAP16XX=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_OMAP_H2 is not set
+# CONFIG_MACH_OMAP_H3 is not set
+# CONFIG_MACH_OMAP_OSK is not set
+CONFIG_MACH_NOKIA770=y
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER=y
+CONFIG_OMAP_ARM_216MHZ=y
+# CONFIG_OMAP_ARM_192MHZ is not set
+# CONFIG_OMAP_ARM_168MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+CONFIG_OMAP_DSP=y
+# CONFIG_OMAP_DSP_MBCMD_VERBOSE is not set
+CONFIG_OMAP_DSP_TASK_MULTIOPEN=y
+CONFIG_OMAP_DSP_FBEXPORT=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+
+#
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_NO_IDLE_HZ=y
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=1f03 rootfstype=jffs2 time"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_LEGACY is not set
+# CONFIG_PM_DEBUG is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=y
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+# CONFIG_NF_CONNTRACK is not set
+# CONFIG_NETFILTER_XTABLES is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_CONNTRACK is not set
+# CONFIG_IP_NF_QUEUE is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+# CONFIG_BT_BNEP_MC_FILTER is not set
+# CONFIG_BT_BNEP_PROTO_FILTER is not set
+CONFIG_BT_HIDP=y
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BT_HCIUSB is not set
+# CONFIG_BT_HCIUART is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+CONFIG_BT_HCIBRF6150=y
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+CONFIG_CONNECTOR=y
+# CONFIG_PROC_EVENTS is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_TOTO is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+CONFIG_MTD_NAND_OMAP_HW=y
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+# CONFIG_MTD_ONENAND_SYNC_READ is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+# CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=y
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+# CONFIG_ATMEL is not set
+# CONFIG_HOSTAP is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=y
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_OMAP is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+CONFIG_OMAP_RNG=y
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_OMAP_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+CONFIG_I2C_OMAP=y
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_TPS65010 is not set
+CONFIG_SENSORS_TLV320AIC23=y
+# CONFIG_GPIOEXPANDER_OMAP is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_OMAP_UWIRE=y
+
+#
+# SPI Protocol Masters
+#
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+CONFIG_FB_OMAP_LCDC_EXTERNAL=y
+CONFIG_FB_OMAP_LCDC_HWA742=y
+CONFIG_FB_OMAP_MANUAL_UPDATE=y
+CONFIG_FB_OMAP_LCD_LPH8923=y
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_HWDEP=y
+CONFIG_SND_RAWMIDI=y
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+CONFIG_SND_DUMMY=y
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# ALSA ARM devices
+#
+CONFIG_SND_OMAP_AIC23=y
+
+#
+# USB devices
+#
+CONFIG_SND_USB_AUDIO=y
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_BANDWIDTH=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_ITMTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+
+#
+# Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_USBNET=y
+# CONFIG_USB_NET_AX8817X is not set
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=y
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+CONFIG_USB_NET_ZAURUS=y
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_MON is not set
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_CONSOLE=y
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_AIRPRIME is not set
+# CONFIG_USB_SERIAL_ANYDATA is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP2101 is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+CONFIG_USB_SERIAL_PL2303=y
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+CONFIG_USB_GADGET_OMAP=y
+CONFIG_USB_OMAP=y
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FILE_STORAGE=m
+CONFIG_USB_FILE_STORAGE_TEST=y
+# CONFIG_USB_G_SERIAL is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BROKEN_RFD=y
+CONFIG_MMC_BULKTRANSFER=y
+CONFIG_MMC_OMAP=y
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+CONFIG_OMAP_UWIRE=y
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# CBUS support
+#
+CONFIG_CBUS=y
+CONFIG_CBUS_TAHVO=y
+CONFIG_CBUS_TAHVO_USER=y
+CONFIG_CBUS_TAHVO_USB=y
+# CONFIG_CBUS_TAHVO_USB_HOST_BY_DEFAULT is not set
+CONFIG_CBUS_RETU=y
+CONFIG_CBUS_RETU_USER=y
+CONFIG_CBUS_RETU_POWERBUTTON=y
+CONFIG_CBUS_RETU_RTC=y
+CONFIG_CBUS_RETU_WDT=y
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+# CONFIG_ROOT_NFS is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+CONFIG_NLS_CODEPAGE_852=y
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+CONFIG_NLS_ISO8859_15=y
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=y
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_CAPABILITIES is not set
+# CONFIG_SECURITY_ROOTPLUG is not set
+# CONFIG_SECURITY_SECLVL is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/n800_defconfig b/arch/arm/configs/n800_defconfig
new file mode 100644 (file)
index 0000000..6664184
--- /dev/null
@@ -0,0 +1,1495 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.20-rc5-omap1
+# Wed Jan 17 17:19:12 2007
+#
+CONFIG_ARM=y
+CONFIG_GENERIC_TIME=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+CONFIG_ARCH_OMAP2=y
+
+#
+# OMAP Feature Selections
+#
+CONFIG_OMAP_RESET_CLOCKS=y
+CONFIG_OMAP_BOOT_TAG=y
+CONFIG_OMAP_BOOT_REASON=y
+CONFIG_OMAP_COMPONENT_VERSION=y
+CONFIG_OMAP_GPIO_SWITCH=y
+# CONFIG_OMAP_MUX is not set
+CONFIG_OMAP_STI=y
+CONFIG_OMAP_STI_CONSOLE=y
+# CONFIG_OMAP_MCBSP is not set
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+CONFIG_OMAP_LL_DEBUG_UART3=y
+CONFIG_OMAP_DSP=y
+# CONFIG_OMAP_DSP_MBCMD_VERBOSE is not set
+CONFIG_OMAP_DSP_TASK_MULTIOPEN=y
+CONFIG_OMAP_DSP_FBEXPORT=y
+CONFIG_MACH_OMAP_GENERIC=y
+
+#
+# OMAP Core Type
+#
+CONFIG_ARCH_OMAP24XX=y
+CONFIG_ARCH_OMAP2420=y
+# CONFIG_ARCH_OMAP2430 is not set
+
+#
+# OMAP Board Type
+#
+CONFIG_MACH_NOKIA_N800=y
+CONFIG_MACH_OMAP2_TUSB6010=y
+# CONFIG_MACH_OMAP_H4 is not set
+# CONFIG_MACH_OMAP_2430SDP is not set
+# CONFIG_MACH_OMAP_APOLLON is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_V6=y
+# CONFIG_CPU_32v6K is not set
+CONFIG_CPU_32v6=y
+CONFIG_CPU_ABRT_EV6=y
+CONFIG_CPU_CACHE_V6=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V6=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+
+#
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_NO_IDLE_HZ=y
+CONFIG_HZ=128
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_LEDS=y
+# CONFIG_LEDS_TIMER is not set
+# CONFIG_LEDS_CPU is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x10C08000
+CONFIG_ZBOOT_ROM_BSS=0x10200000
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_CMDLINE="root=1f03 rootfstype=jffs2"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_LEGACY is not set
+# CONFIG_PM_DEBUG is not set
+# CONFIG_PM_SYSFS_DEPRECATED is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=y
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+# CONFIG_NF_CONNTRACK_ENABLED is not set
+CONFIG_NETFILTER_XTABLES=y
+# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_MAC is not set
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=y
+# CONFIG_IP_NF_MATCH_IPRANGE is not set
+# CONFIG_IP_NF_MATCH_TOS is not set
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_AH is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_MATCH_OWNER is not set
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+CONFIG_IP_NF_FILTER=y
+# CONFIG_IP_NF_TARGET_REJECT is not set
+# CONFIG_IP_NF_TARGET_LOG is not set
+# CONFIG_IP_NF_TARGET_ULOG is not set
+# CONFIG_IP_NF_TARGET_TCPMSS is not set
+CONFIG_IP_NF_TARGET_IDLETIMER=y
+# CONFIG_IP_NF_MANGLE is not set
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+# CONFIG_BT_BNEP_MC_FILTER is not set
+# CONFIG_BT_BNEP_PROTO_FILTER is not set
+CONFIG_BT_HIDP=y
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BT_HCIUSB is not set
+# CONFIG_BT_HCIUART is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIBRF6150 is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_IEEE80211 is not set
+CONFIG_WIRELESS_EXT=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+CONFIG_MTD_ONENAND=y
+# CONFIG_MTD_ONENAND_VERIFY_WRITE is not set
+# CONFIG_MTD_ONENAND_GENERIC is not set
+CONFIG_MTD_ONENAND_OMAP2=y
+CONFIG_MTD_ONENAND_OTP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=y
+
+#
+# PHY device support
+#
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+CONFIG_MII=y
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+# CONFIG_NET_WIRELESS_RTNETLINK is not set
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_HOSTAP is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=y
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_OMAP is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_TSC2102 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_OMAP_RNG=y
+# CONFIG_NVRAM is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+# CONFIG_GPIOEXPANDER_OMAP is not set
+CONFIG_MENELAUS=y
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_OMAP_UWIRE is not set
+CONFIG_SPI_OMAP24XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_TSC2102 is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+# CONFIG_TIFM_CORE is not set
+
+#
+# LED devices
+#
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_OMAP_DEBUG is not set
+# CONFIG_LEDS_OMAP is not set
+CONFIG_LEDS_OMAP_PWM=y
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+# CONFIG_VIDEO_V4L1 is not set
+# CONFIG_VIDEO_V4L1_COMPAT is not set
+CONFIG_VIDEO_V4L2=y
+
+#
+# Video Capture Adapters
+#
+
+#
+# Video Capture Adapters
+#
+# CONFIG_VIDEO_ADV_DEBUG is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+
+#
+# V4L USB devices
+#
+# CONFIG_VIDEO_PVRUSB2 is not set
+# CONFIG_VIDEO_USBVISION is not set
+# CONFIG_VIDEO_OMAP_CAMERA is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_USB_DSBR is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FIRMWARE_EDID is not set
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+CONFIG_FB_OMAP_LCDC_EXTERNAL=y
+# CONFIG_FB_OMAP_LCDC_HWA742 is not set
+CONFIG_FB_OMAP_MANUAL_UPDATE=y
+CONFIG_FB_OMAP_LCD_MIPID=y
+CONFIG_FB_OMAP_BOOTLOADER_INIT=y
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=4
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=y
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# ALSA ARM devices
+#
+# CONFIG_SND_OMAP_AIC23 is not set
+# CONFIG_SND_OMAP_TSC2101 is not set
+# CONFIG_SND_SX1 is not set
+# CONFIG_SND_OMAP_TSC2102 is not set
+
+#
+# USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+CONFIG_USB_DYNAMIC_MINORS=y
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_MULTITHREAD_PROBE is not set
+CONFIG_USB_OTG=y
+CONFIG_USB_OTG_WHITELIST=y
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_TUSB6010=y
+# CONFIG_USB_MUSB_HOST is not set
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+CONFIG_USB_MUSB_OTG=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_USB_INVENTRA_FIFO is not set
+# CONFIG_USB_INVENTRA_DMA is not set
+# CONFIG_USB_TI_CPPI_DMA is not set
+CONFIG_USB_TUSB_OMAP_DMA=y
+CONFIG_USB_INVENTRA_HCD_LOGGING=1
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+CONFIG_USB_LIBUSUAL=y
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_TOUCHSCREEN is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+CONFIG_USB_RTL8150=y
+# CONFIG_USB_USBNET_MII is not set
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=y
+CONFIG_USB_NET_PLUSB=y
+# CONFIG_USB_NET_MCS7830 is not set
+CONFIG_USB_NET_RNDIS_HOST=y
+CONFIG_USB_NET_CDC_SUBSET=y
+# CONFIG_USB_ALI_M5632 is not set
+# CONFIG_USB_AN2720 is not set
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+# CONFIG_USB_EPSON2888 is not set
+CONFIG_USB_NET_ZAURUS=y
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=y
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# CBUS support
+#
+CONFIG_CBUS=y
+CONFIG_CBUS_TAHVO=y
+CONFIG_CBUS_TAHVO_USER=y
+# CONFIG_CBUS_TAHVO_USB is not set
+CONFIG_CBUS_RETU=y
+CONFIG_CBUS_RETU_USER=y
+CONFIG_CBUS_RETU_POWERBUTTON=y
+CONFIG_CBUS_RETU_RTC=y
+CONFIG_CBUS_RETU_WDT=y
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=m
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=m
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=m
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+CONFIG_NLS_ISO8859_15=y
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=y
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+CONFIG_PRINTK_TIME=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_RWSEMS is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_CAPABILITIES is not set
+# CONFIG_SECURITY_ROOTPLUG is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
diff --git a/arch/arm/configs/omap_2430sdp_defconfig b/arch/arm/configs/omap_2430sdp_defconfig
new file mode 100644 (file)
index 0000000..404405f
--- /dev/null
@@ -0,0 +1,1106 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.19-omap1
+# Sun Dec  3 13:58:24 2006
+#
+CONFIG_ARM=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+# CONFIG_ARCH_OMAP1 is not set
+CONFIG_ARCH_OMAP2=y
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_BOOT_TAG=y
+# CONFIG_OMAP_BOOT_REASON is not set
+# CONFIG_OMAP_COMPONENT_VERSION is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+CONFIG_OMAP_MUX_DEBUG=y
+CONFIG_OMAP_MUX_WARNINGS=y
+# CONFIG_OMAP_STI is not set
+CONFIG_OMAP_MCBSP=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+CONFIG_OMAP_DM_TIMER=y
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+# CONFIG_OMAP_DSP is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP Core Type
+#
+CONFIG_ARCH_OMAP24XX=y
+# CONFIG_ARCH_OMAP2420 is not set
+CONFIG_ARCH_OMAP2430=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_H4 is not set
+CONFIG_MACH_OMAP_2430SDP=y
+# CONFIG_MACH_OMAP_APOLLON is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_V6=y
+# CONFIG_CPU_32v6K is not set
+CONFIG_CPU_32v6=y
+CONFIG_CPU_ABRT_EV6=y
+CONFIG_CPU_CACHE_V6=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V6=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+
+#
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/ram0 rw console=ttyS0,115200n8 initrd=0x80600000,8M ramdisk_size=8192"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_OMAP_NOR=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_OMAP=y
+# CONFIG_OMAP_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+# CONFIG_GPIOEXPANDER_OMAP is not set
+# CONFIG_MENELAUS is not set
+CONFIG_TWL4030_CORE=y
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+# CONFIG_TIFM_CORE is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_LCD_MIPID is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# Enable Host or Gadget support to see Inventra options
+#
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_OMAP=y
+# CONFIG_MMC_TIFM_SD is not set
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_RWSEMS is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_ERRORS is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
diff --git a/arch/arm/configs/omap_apollon_2420_defconfig b/arch/arm/configs/omap_apollon_2420_defconfig
new file mode 100644 (file)
index 0000000..2cef064
--- /dev/null
@@ -0,0 +1,1009 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.20-rc1-omap1
+# Fri Dec 22 14:31:47 2006
+#
+CONFIG_ARM=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+CONFIG_ARCH_OMAP2=y
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+# CONFIG_OMAP_STI is not set
+# CONFIG_OMAP_MCBSP is not set
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+# CONFIG_OMAP_DSP is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP Core Type
+#
+CONFIG_ARCH_OMAP24XX=y
+CONFIG_ARCH_OMAP2420=y
+# CONFIG_ARCH_OMAP2430 is not set
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_H4 is not set
+# CONFIG_MACH_OMAP_2430SDP is not set
+CONFIG_MACH_OMAP_APOLLON=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_V6=y
+# CONFIG_CPU_32v6K is not set
+CONFIG_CPU_32v6=y
+CONFIG_CPU_ABRT_EV6=y
+CONFIG_CPU_CACHE_V6=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V6=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+
+#
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_PREEMPT=y
+CONFIG_NO_IDLE_HZ=y
+CONFIG_HZ=128
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/ram0 rw mem=128M console=ttyS0,115200n8 initrd=0x80600000,8M ramdisk_size=8192"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_FPE_NWFPE is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+CONFIG_MTD_ONENAND=y
+# CONFIG_MTD_ONENAND_VERIFY_WRITE is not set
+CONFIG_MTD_ONENAND_GENERIC=y
+# CONFIG_MTD_ONENAND_OTP is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_OMAP=y
+# CONFIG_OMAP_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_OMAP_UWIRE is not set
+CONFIG_SPI_OMAP24XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_TSC2102 is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+# CONFIG_TIFM_CORE is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_LCD_MIPID is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+# CONFIG_HID is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+CONFIG_USB_GADGET_OMAP=y
+CONFIG_USB_OMAP=y
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_OMAP=y
+# CONFIG_MMC_TIFM_SD is not set
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=y
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_RWSEMS is not set
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
diff --git a/arch/arm/configs/omap_generic_1510_defconfig b/arch/arm/configs/omap_generic_1510_defconfig
new file mode 100644 (file)
index 0000000..5091946
--- /dev/null
@@ -0,0 +1,851 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_ADIFCC is not set
+# CONFIG_ARCH_ANAKIN is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_SHARK is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# CLPS711X/EP721X Implementations
+#
+
+#
+# Epxa10db
+#
+
+#
+# Footbridge Implementations
+#
+
+#
+# IOP3xx Implementation Options
+#
+# CONFIG_ARCH_IOP310 is not set
+# CONFIG_ARCH_IOP321 is not set
+
+#
+# IOP3xx Chipset Features
+#
+
+#
+# Intel PXA250/210 Implementations
+#
+
+#
+# SA11x0 Implementations
+#
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP15XX=y
+# CONFIG_ARCH_OMAP1610 is not set
+# CONFIG_OMAP_INNOVATOR is not set
+CONFIG_MACH_OMAP_GENERIC=y
+# CONFIG_INNOVATOR_MISSED_IRQS is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP1510_PM is not set
+CONFIG_OMAP_ARM_168MHZ=y
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM925T=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+CONFIG_CPU_DCACHE_WRITETHROUGH=y
+
+#
+# General setup
+#
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_PM=y
+CONFIG_PREEMPT=y
+# CONFIG_APM is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="mem=64M console=ttyS2,115200 root=0803 ro init=/bin/sh"
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_DCSSBLK is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_IPV6 is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IPV6_SCTP__=y
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_NET_VENDOR_SMC=y
+# CONFIG_SMC9194 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+CONFIG_PPP=y
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BT is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_REPORT_LUNS=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+CONFIG_OMAP_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_ELV is not set
+# CONFIG_I2C_ISA is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_VELLEMAN is not set
+CONFIG_I2C_OMAP1610=y
+
+#
+# I2C Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BROKEN_RFD=y
+CONFIG_MMC_OMAP=y
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+# CONFIG_ROOT_NFS is not set
+CONFIG_LOCKD=y
+# CONFIG_EXPORTFS is not set
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_GSS is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_NEC98_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Misc devices
+#
+
+#
+# USB support
+#
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_EHCI_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811HS is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_BLUETOOTH_TTY is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_DPCM=y
+CONFIG_USB_STORAGE_HP8200e=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_XPAD is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+
+#
+# Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+CONFIG_USB_RTL8150=y
+CONFIG_USB_USBNET=y
+
+#
+# USB Host-to-Host Cables
+#
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_GENESYS=y
+CONFIG_USB_NET1080=y
+CONFIG_USB_PL2301=y
+
+#
+# Intelligent USB Devices/Gadgets
+#
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_ZAURUS=y
+CONFIG_USB_CDCETHER=y
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_AX8817X=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_TIGL is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_BRLVGER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
diff --git a/arch/arm/configs/omap_generic_1610_defconfig b/arch/arm/configs/omap_generic_1610_defconfig
new file mode 100644 (file)
index 0000000..b772e7e
--- /dev/null
@@ -0,0 +1,883 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.9-rc3-omap1
+# Mon Oct  4 10:14:44 2004
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_IOMAP=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+# CONFIG_TINY_SHMEM is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_VERSATILE_PB is not set
+# CONFIG_ARCH_IMX is not set
+
+#
+# TI OMAP Implementations
+#
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+# CONFIG_ARCH_OMAP15XX is not set
+CONFIG_ARCH_OMAP16XX=y
+CONFIG_ARCH_OMAP_OTG=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_OMAP_H2 is not set
+# CONFIG_MACH_OMAP_H3 is not set
+# CONFIG_MACH_OMAP_H4 is not set
+# CONFIG_MACH_OMAP_OSK is not set
+CONFIG_MACH_OMAP_GENERIC=y
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_BOOT_TAG is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_ARM_192MHZ=y
+# CONFIG_OMAP_ARM_168MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+# CONFIG_OMAP_DSP is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+
+#
+# General setup
+#
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_DEBUG_DRIVER is not set
+CONFIG_PM=y
+CONFIG_PREEMPT=y
+# CONFIG_APM is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="mem=64M console=ttyS2,115200 root=0803 ro init=/bin/sh"
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_NET_VENDOR_SMC=y
+# CONFIG_SMC91X is not set
+# CONFIG_SMC9194 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_RAW is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_8250_OMAP is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_OMAP_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_ISA is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_PCA_ISA is not set
+# CONFIG_I2C_OMAP is not set
+
+#
+# Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+
+#
+# Other I2C Chip support
+#
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_GPIOEXPANDER_OMAP is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+# CONFIG_ROOT_NFS is not set
+CONFIG_LOCKD=y
+# CONFIG_EXPORTFS is not set
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Misc devices
+#
+
+#
+# USB support
+#
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_EHCI_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811HS is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_BLUETOOTH_TTY is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_RW_DETECT is not set
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_DPCM=y
+CONFIG_USB_STORAGE_HP8200e=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+
+#
+# Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+CONFIG_USB_RTL8150=y
+CONFIG_USB_USBNET=y
+
+#
+# USB Host-to-Host Cables
+#
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_GENESYS=y
+CONFIG_USB_NET1080=y
+CONFIG_USB_PL2301=y
+
+#
+# Intelligent USB Devices/Gadgets
+#
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_ZAURUS=y
+CONFIG_USB_CDCETHER=y
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_AX8817X=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_TIGL is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_UWIRE is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BROKEN_RFD=y
+CONFIG_MMC_OMAP=y
+# CONFIG_MMC_OMAP16XX_BLOCK1 is not set
+CONFIG_MMC_OMAP16XX_BLOCK2=y
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/arm/configs/omap_generic_1710_defconfig b/arch/arm/configs/omap_generic_1710_defconfig
new file mode 100644 (file)
index 0000000..579cff1
--- /dev/null
@@ -0,0 +1,853 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.9-rc3-omap1
+# Mon Oct  4 10:14:57 2004
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_IOMAP=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_HOTPLUG=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+# CONFIG_TINY_SHMEM is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_VERSATILE_PB is not set
+# CONFIG_ARCH_IMX is not set
+
+#
+# TI OMAP Implementations
+#
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+# CONFIG_ARCH_OMAP15XX is not set
+CONFIG_ARCH_OMAP16XX=y
+CONFIG_ARCH_OMAP_OTG=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_OMAP_H2 is not set
+# CONFIG_MACH_OMAP_H3 is not set
+# CONFIG_MACH_OMAP_H4 is not set
+# CONFIG_MACH_OMAP_OSK is not set
+CONFIG_MACH_OMAP_GENERIC=y
+
+#
+# OMAP Feature Selections
+#
+CONFIG_OMAP_BOOT_TAG=y
+# CONFIG_OMAP_BOOT_REASON is not set
+# CONFIG_OMAP_MUX is not set
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+CONFIG_OMAP_LL_DEBUG_UART3=y
+CONFIG_OMAP_ARM_192MHZ=y
+# CONFIG_OMAP_ARM_168MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+# CONFIG_OMAP_DSP is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+
+#
+# General setup
+#
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+
+#
+# PCMCIA/CardBus support
+#
+# CONFIG_PCMCIA is not set
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+CONFIG_PM=y
+# CONFIG_PREEMPT is not set
+# CONFIG_APM is not set
+CONFIG_ARTHUR=y
+CONFIG_CMDLINE="mem=64M console=tty0 console=ttyS2,115200 root=0801"
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_NET_VENDOR_SMC=y
+# CONFIG_SMC91X is not set
+# CONFIG_SMC9194 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+# CONFIG_ATMEL is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_RAW is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_8250_OMAP=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_OMAP_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+# CONFIG_ROOT_NFS is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_EXPORTFS is not set
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+CONFIG_NLS_CODEPAGE_852=y
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+CONFIG_NLS_ISO8859_15=y
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Misc devices
+#
+
+#
+# USB support
+#
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_BANDWIDTH=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_EHCI_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811HS is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_BLUETOOTH_TTY is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_RW_DETECT is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+
+#
+# Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_USBNET=y
+
+#
+# USB Host-to-Host Cables
+#
+CONFIG_USB_ALI_M5632=y
+# CONFIG_USB_AN2720 is not set
+# CONFIG_USB_BELKIN is not set
+# CONFIG_USB_GENESYS is not set
+# CONFIG_USB_NET1080 is not set
+# CONFIG_USB_PL2301 is not set
+
+#
+# Intelligent USB Devices/Gadgets
+#
+# CONFIG_USB_ARMLINUX is not set
+# CONFIG_USB_EPSON2888 is not set
+# CONFIG_USB_ZAURUS is not set
+# CONFIG_USB_CDCETHER is not set
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_AX8817X=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_TIGL is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_UWIRE is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+# CONFIG_MMC_BLOCK_BROKEN_RFD is not set
+CONFIG_MMC_OMAP=y
+# CONFIG_MMC_OMAP16XX_BLOCK1 is not set
+CONFIG_MMC_OMAP16XX_BLOCK2=y
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_SLAB=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+CONFIG_DEBUG_WAITQ=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+CONFIG_SECURITY=y
+# CONFIG_SECURITY_NETWORK is not set
+CONFIG_SECURITY_CAPABILITIES=y
+# CONFIG_SECURITY_ROOTPLUG is not set
+# CONFIG_SECURITY_SELINUX is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/arm/configs/omap_generic_2420_defconfig b/arch/arm/configs/omap_generic_2420_defconfig
new file mode 100644 (file)
index 0000000..94d4659
--- /dev/null
@@ -0,0 +1,555 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.13-rc6-omap1
+# Thu Aug 11 10:05:10 2005
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_HOTPLUG=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+
+#
+# TI OMAP Implementations
+#
+# CONFIG_ARCH_OMAP1 is not set
+CONFIG_ARCH_OMAP2=y
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_BOOT_TAG=y
+# CONFIG_OMAP_BOOT_REASON is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+# CONFIG_OMAP_MUX is not set
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+CONFIG_OMAP_LL_DEBUG_UART3=y
+CONFIG_MACH_OMAP_GENERIC=y
+
+#
+# OMAP Core Type
+#
+CONFIG_ARCH_OMAP24XX=y
+CONFIG_ARCH_OMAP2420=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_H4 is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_V6=y
+CONFIG_CPU_32v6=y
+CONFIG_CPU_ABRT_EV6=y
+CONFIG_CPU_CACHE_V6=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V6=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+
+#
+# Bus support
+#
+CONFIG_ISA_DMA_API=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_LEDS=y
+# CONFIG_LEDS_TIMER is not set
+# CONFIG_LEDS_CPU is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x10C08000
+CONFIG_ZBOOT_ROM_BSS=0x10200000
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+# CONFIG_NET is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+# CONFIG_I2C_SENSOR is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_ROMFS_FS=y
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
index 28816227f2507cab9ca2e8c20441014750ec52ec..65be6fb97d43b0f8381cb83b3c021fb5680bf1a0 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.19
-# Thu Dec  7 15:16:40 2006
+# Linux kernel version: 2.6.20-rc3-omap1
+# Thu Jan  4 16:07:28 2007
 #
 CONFIG_ARM=y
 # CONFIG_GENERIC_TIME is not set
@@ -11,6 +11,8 @@ CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 CONFIG_HARDIRQS_SW_RESEND=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_VECTORS_BASE=0xffff0000
@@ -21,7 +23,6 @@ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN_ON_SMP=y
-CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
@@ -38,7 +39,7 @@ CONFIG_SYSVIPC=y
 # CONFIG_UTS_NS is not set
 # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
-# CONFIG_SYSFS_DEPRECATED is not set
+CONFIG_SYSFS_DEPRECATED=y
 # CONFIG_RELAY is not set
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -47,6 +48,7 @@ CONFIG_SYSCTL=y
 CONFIG_UID16=y
 CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
@@ -113,6 +115,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
 # CONFIG_ARCH_IMX is not set
 # CONFIG_ARCH_IOP32X is not set
 # CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IOP13XX is not set
 # CONFIG_ARCH_IXP4XX is not set
 # CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_IXP23XX is not set
@@ -137,20 +140,23 @@ CONFIG_ARCH_OMAP1=y
 # OMAP Feature Selections
 #
 # CONFIG_OMAP_RESET_CLOCKS is not set
-# CONFIG_OMAP_BOOT_TAG is not set
+CONFIG_OMAP_BOOT_TAG=y
+# CONFIG_OMAP_BOOT_REASON is not set
+# CONFIG_OMAP_COMPONENT_VERSION is not set
 # CONFIG_OMAP_GPIO_SWITCH is not set
 CONFIG_OMAP_MUX=y
-# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_DEBUG=y
 CONFIG_OMAP_MUX_WARNINGS=y
+# CONFIG_OMAP_STI is not set
 CONFIG_OMAP_MCBSP=y
-# CONFIG_OMAP_MPU_TIMER is not set
-CONFIG_OMAP_32K_TIMER=y
-CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
 # CONFIG_OMAP_DM_TIMER is not set
 CONFIG_OMAP_LL_DEBUG_UART1=y
 # CONFIG_OMAP_LL_DEBUG_UART2 is not set
 # CONFIG_OMAP_LL_DEBUG_UART3 is not set
 CONFIG_OMAP_SERIAL_WAKE=y
+# CONFIG_OMAP_DSP is not set
 
 #
 # OMAP Core Type
@@ -174,10 +180,10 @@ CONFIG_MACH_OMAP_H2=y
 #
 # CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
 # CONFIG_OMAP_ARM_216MHZ is not set
-CONFIG_OMAP_ARM_192MHZ=y
+# CONFIG_OMAP_ARM_192MHZ is not set
 # CONFIG_OMAP_ARM_168MHZ is not set
 # CONFIG_OMAP_ARM_120MHZ is not set
-# CONFIG_OMAP_ARM_60MHZ is not set
+CONFIG_OMAP_ARM_60MHZ=y
 # CONFIG_OMAP_ARM_30MHZ is not set
 
 #
@@ -214,9 +220,9 @@ CONFIG_ARM_THUMB=y
 #
 # Kernel Features
 #
-CONFIG_PREEMPT=y
-CONFIG_NO_IDLE_HZ=y
-CONFIG_HZ=128
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_HZ=100
 # CONFIG_AEABI is not set
 # CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
 CONFIG_SELECT_MEMORY_MODEL=y
@@ -228,7 +234,9 @@ CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
 CONFIG_SPLIT_PTLOCK_CPUS=4096
 # CONFIG_RESOURCES_64BIT is not set
-# CONFIG_LEDS is not set
+CONFIG_LEDS=y
+# CONFIG_LEDS_TIMER is not set
+# CONFIG_LEDS_CPU is not set
 CONFIG_ALIGNMENT_TRAP=y
 
 #
@@ -236,24 +244,13 @@ CONFIG_ALIGNMENT_TRAP=y
 #
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="mem=32M console=ttyS0,115200n8 root=0801 ro init=/bin/sh"
+CONFIG_CMDLINE="mem=32M console=ttyS0,115200n8 root=/dev/ram0 rw initrd=0x10600000,8M ramdisk_size=8192"
 # CONFIG_XIP_KERNEL is not set
 
 #
 # CPU Frequency scaling
 #
-CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_TABLE=y
-# CONFIG_CPU_FREQ_DEBUG is not set
-CONFIG_CPU_FREQ_STAT=y
-# CONFIG_CPU_FREQ_STAT_DETAILS is not set
-# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
-CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
-# CONFIG_CPU_FREQ_GOV_PERFORMANCE is not set
-# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
-CONFIG_CPU_FREQ_GOV_USERSPACE=y
-# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
-# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+# CONFIG_CPU_FREQ is not set
 
 #
 # Floating point emulation
@@ -382,6 +379,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_FW_LOADER is not set
+CONFIG_DEBUG_DRIVER=y
 # CONFIG_SYS_HYPERVISOR is not set
 
 #
@@ -392,7 +390,85 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 #
 # Memory Technology Devices (MTD)
 #
-# CONFIG_MTD is not set
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=3
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_OMAP_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
 
 #
 # Parallel port support
@@ -410,55 +486,21 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CDROM_PKTCDVD is not set
-CONFIG_ATA_OVER_ETH=m
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # SCSI device support
 #
 # CONFIG_RAID_ATTRS is not set
-CONFIG_SCSI=y
-# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI is not set
 # CONFIG_SCSI_NETLINK is not set
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-# CONFIG_BLK_DEV_SD is not set
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
-# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-# CONFIG_SCSI_SCAN_ASYNC is not set
-
-#
-# SCSI Transports
-#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_ATTRS is not set
-# CONFIG_SCSI_SAS_LIBSAS is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_ISCSI_TCP is not set
-# CONFIG_SCSI_DEBUG is not set
 
 #
 # Serial ATA (prod) and Parallel ATA (experimental) drivers
@@ -628,8 +670,16 @@ CONFIG_WATCHDOG_NOWAYOUT=y
 #
 # CONFIG_SOFT_WATCHDOG is not set
 # CONFIG_OMAP_WATCHDOG is not set
-# CONFIG_HW_RANDOM is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_HW_RANDOM=m
+CONFIG_HW_RANDOM_OMAP=m
+# CONFIG_OMAP_RNG is not set
 # CONFIG_NVRAM is not set
+CONFIG_OMAP_RTC=y
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_RAW_DRIVER is not set
@@ -642,7 +692,43 @@ CONFIG_WATCHDOG_NOWAYOUT=y
 #
 # I2C support
 #
-# CONFIG_I2C is not set
+CONFIG_I2C=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+CONFIG_ISP1301_OMAP=y
+CONFIG_TPS65010=y
+# CONFIG_SENSORS_TLV320AIC23 is not set
+# CONFIG_GPIOEXPANDER_OMAP is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
 
 #
 # SPI support
@@ -661,8 +747,44 @@ CONFIG_WATCHDOG_NOWAYOUT=y
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
 # CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
 # CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
@@ -692,6 +814,7 @@ CONFIG_HWMON=y
 # Digital Video Broadcasting Devices
 #
 # CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
 
 #
 # Graphics support
@@ -707,6 +830,12 @@ CONFIG_FB_MODE_HELPERS=y
 # CONFIG_FB_TILEBLITTING is not set
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_LCD_MIPID is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_OMAP_DMA_TUNE is not set
 
 #
 # Console display driver support
@@ -715,17 +844,9 @@ CONFIG_FB_MODE_HELPERS=y
 CONFIG_DUMMY_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 # CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
-CONFIG_FONTS=y
+# CONFIG_FONTS is not set
 CONFIG_FONT_8x8=y
 CONFIG_FONT_8x16=y
-# CONFIG_FONT_6x11 is not set
-# CONFIG_FONT_7x14 is not set
-# CONFIG_FONT_PEARL_8x8 is not set
-# CONFIG_FONT_ACORN_8x8 is not set
-# CONFIG_FONT_MINI_4x6 is not set
-# CONFIG_FONT_SUN8x16 is not set
-# CONFIG_FONT_SUN12x22 is not set
-# CONFIG_FONT_10x18 is not set
 
 #
 # Logo configuration
@@ -739,19 +860,12 @@ CONFIG_LOGO_LINUX_CLUT224=y
 #
 # Sound
 #
-CONFIG_SOUND=y
-
-#
-# Advanced Linux Sound Architecture
-#
-# CONFIG_SND is not set
+# CONFIG_SOUND is not set
 
 #
-# Open Sound System
+# HID Devices
 #
-CONFIG_SOUND_PRIME=y
-# CONFIG_SOUND_MSNDCLAS is not set
-# CONFIG_SOUND_MSNDPIN is not set
+CONFIG_HID=y
 
 #
 # USB support
@@ -759,16 +873,142 @@ CONFIG_SOUND_PRIME=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 # CONFIG_USB_ARCH_HAS_EHCI is not set
-# CONFIG_USB is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_MULTITHREAD_PROBE is not set
+CONFIG_USB_OTG=y
+CONFIG_USB_OTG_WHITELIST=y
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
 
 #
 # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
 #
 
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+# CONFIG_USB_HID is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_TOUCHSCREEN is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
+# CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+CONFIG_USB_TEST=y
+
+#
+# USB DSL modem support
+#
+
 #
 # USB Gadget Support
 #
-# CONFIG_USB_GADGET is not set
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+CONFIG_USB_GADGET_OMAP=y
+CONFIG_USB_OMAP=y
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=y
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
 
 #
 # MMC/SD Card support
@@ -781,6 +1021,17 @@ CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_RTC_LIB=y
 # CONFIG_RTC_CLASS is not set
 
+#
+# Synchronous Serial Interfaces (SSI)
+#
+CONFIG_OMAP_UWIRE=y
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
 #
 # File systems
 #
@@ -841,6 +1092,15 @@ CONFIG_RAMFS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
 CONFIG_CRAMFS=y
 # CONFIG_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
@@ -852,18 +1112,15 @@ CONFIG_CRAMFS=y
 # Network File Systems
 #
 CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_NFS_V3_ACL is not set
-CONFIG_NFS_V4=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
 # CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
-CONFIG_SUNRPC_GSS=y
-CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
@@ -939,13 +1196,31 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 CONFIG_ENABLE_MUST_CHECK=y
 # CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_UNUSED_SYMBOLS is not set
-# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
 CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_RWSEMS is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
-# CONFIG_DEBUG_FS is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
 CONFIG_FRAME_POINTER=y
-# CONFIG_HEADERS_CHECK is not set
-# CONFIG_DEBUG_USER is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_LL is not set
 
 #
 # Security options
@@ -956,50 +1231,17 @@ CONFIG_FRAME_POINTER=y
 #
 # Cryptographic options
 #
-CONFIG_CRYPTO=y
-CONFIG_CRYPTO_ALGAPI=y
-CONFIG_CRYPTO_BLKCIPHER=y
-CONFIG_CRYPTO_MANAGER=y
-# CONFIG_CRYPTO_HMAC is not set
-# CONFIG_CRYPTO_XCBC is not set
-# CONFIG_CRYPTO_NULL is not set
-# CONFIG_CRYPTO_MD4 is not set
-CONFIG_CRYPTO_MD5=y
-# CONFIG_CRYPTO_SHA1 is not set
-# CONFIG_CRYPTO_SHA256 is not set
-# CONFIG_CRYPTO_SHA512 is not set
-# CONFIG_CRYPTO_WP512 is not set
-# CONFIG_CRYPTO_TGR192 is not set
-# CONFIG_CRYPTO_GF128MUL is not set
-CONFIG_CRYPTO_ECB=m
-CONFIG_CRYPTO_CBC=y
-# CONFIG_CRYPTO_LRW is not set
-CONFIG_CRYPTO_DES=y
-# CONFIG_CRYPTO_BLOWFISH is not set
-# CONFIG_CRYPTO_TWOFISH is not set
-# CONFIG_CRYPTO_SERPENT is not set
-# CONFIG_CRYPTO_AES is not set
-# CONFIG_CRYPTO_CAST5 is not set
-# CONFIG_CRYPTO_CAST6 is not set
-# CONFIG_CRYPTO_TEA is not set
-# CONFIG_CRYPTO_ARC4 is not set
-# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_ANUBIS is not set
-# CONFIG_CRYPTO_DEFLATE is not set
-# CONFIG_CRYPTO_MICHAEL_MIC is not set
-# CONFIG_CRYPTO_CRC32C is not set
-# CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
+# CONFIG_CRYPTO is not set
 
 #
 # Library routines
 #
+CONFIG_BITREVERSE=y
 # CONFIG_CRC_CCITT is not set
 # CONFIG_CRC16 is not set
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
 CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
diff --git a/arch/arm/configs/omap_h3_1710_defconfig b/arch/arm/configs/omap_h3_1710_defconfig
new file mode 100644 (file)
index 0000000..5e2c5b1
--- /dev/null
@@ -0,0 +1,1048 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.14-rc4-omap1
+# Tue Oct 18 17:58:27 2005
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+# CONFIG_OMAP_DM_TIMER is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+# CONFIG_ARCH_OMAP15XX is not set
+CONFIG_ARCH_OMAP16XX=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_OMAP_H2 is not set
+CONFIG_MACH_OMAP_H3=y
+# CONFIG_MACH_OMAP_OSK is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
+# CONFIG_OMAP_ARM_216MHZ is not set
+# CONFIG_OMAP_ARM_192MHZ is not set
+CONFIG_OMAP_ARM_168MHZ=y
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+# CONFIG_OMAP_DSP is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+
+#
+# Bus support
+#
+CONFIG_ISA_DMA_API=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_LEDS=y
+# CONFIG_LEDS_TIMER is not set
+# CONFIG_LEDS_CPU is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x10C08000
+CONFIG_ZBOOT_ROM_BSS=0x10200000
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_CMDLINE="mem=32M console=ttyS0,115200n8 initrd=0x10A00000,8M root=/dev/ram0 rw ip=dhcp devfs=mount"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_IRDA=y
+
+#
+# IrDA protocols
+#
+# CONFIG_IRLAN is not set
+# CONFIG_IRNET is not set
+# CONFIG_IRCOMM is not set
+# CONFIG_IRDA_ULTRA is not set
+
+#
+# IrDA options
+#
+# CONFIG_IRDA_CACHE_LAST_LSAP is not set
+# CONFIG_IRDA_FAST_RR is not set
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+# CONFIG_IRTTY_SIR is not set
+
+#
+# Dongle support
+#
+
+#
+# Old SIR device drivers
+#
+# CONFIG_IRPORT_SIR is not set
+
+#
+# Old Serial dongle support
+#
+
+#
+# FIR device drivers
+#
+# CONFIG_USB_IRDA is not set
+# CONFIG_SIGMATEL_FIR is not set
+# CONFIG_NSC_FIR is not set
+# CONFIG_WINBOND_FIR is not set
+CONFIG_OMAP1610_IR=y
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+# CONFIG_VIA_FIR is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPPOE is not set
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+# CONFIG_SLIP_SMART is not set
+# CONFIG_SLIP_MODE_SLIP6 is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+# CONFIG_OMAP_WATCHDOG is not set
+# CONFIG_OMAP_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_OMAP_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+CONFIG_I2C_OMAP=y
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+CONFIG_ISP1301_OMAP=m
+CONFIG_TPS65010=y
+# CONFIG_SENSORS_TLV320AIC23 is not set
+CONFIG_GPIOEXPANDER_OMAP=y
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_OVCAMCHIP is not set
+# CONFIG_VIDEO_OMAP_CAMERA is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_MAESTRO is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+CONFIG_FB_OMAP_LCDC_INTERNAL=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=y
+# CONFIG_SOUND_OMAP is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_TVMIXER is not set
+# CONFIG_SOUND_AD1980 is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
+# CONFIG_USB_BLUETOOTH_TTY is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+# CONFIG_USB_STORAGE is not set
+
+#
+# USB Input Devices
+#
+# CONFIG_USB_HID is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_ITMTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_PWC is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_LD is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+# CONFIG_MMC_BLOCK_BROKEN_RFD is not set
+# CONFIG_MMC_BULKTRANSFER is not set
+CONFIG_MMC_OMAP=y
+# CONFIG_MMC_WBSD is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+CONFIG_OMAP_UWIRE=y
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_ROMFS_FS=y
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_LL is not set
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/arm/configs/omap_h4_2420_defconfig b/arch/arm/configs/omap_h4_2420_defconfig
new file mode 100644 (file)
index 0000000..69e3c94
--- /dev/null
@@ -0,0 +1,1073 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.17-rc5-omap1
+# Tue Jun 13 22:02:07 2006
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_VECTORS_BASE=0xffff0000
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_UID16=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+# CONFIG_BLK_DEV_IO_TRACE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_AT91RM9200 is not set
+
+#
+# TI OMAP Implementations
+#
+# CONFIG_ARCH_OMAP1 is not set
+CONFIG_ARCH_OMAP2=y
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_BOOT_TAG=y
+# CONFIG_OMAP_BOOT_REASON is not set
+# CONFIG_OMAP_COMPONENT_VERSION is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+CONFIG_OMAP_MUX_DEBUG=y
+CONFIG_OMAP_MUX_WARNINGS=y
+# CONFIG_OMAP_STI is not set
+CONFIG_OMAP_MCBSP=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+CONFIG_OMAP_DM_TIMER=y
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP Core Type
+#
+CONFIG_ARCH_OMAP24XX=y
+CONFIG_ARCH_OMAP2420=y
+
+#
+# OMAP Board Type
+#
+CONFIG_MACH_OMAP_H4=y
+# CONFIG_MACH_OMAP_APOLLON is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_V6=y
+# CONFIG_CPU_32v6K is not set
+CONFIG_CPU_32v6=y
+CONFIG_CPU_ABRT_EV6=y
+CONFIG_CPU_CACHE_V6=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V6=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+
+#
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/ram0 rw console=ttyS0,115200n8 initrd=0x80600000,8M ramdisk_size=8192"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_IRDA=y
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=y
+CONFIG_IRCOMM=y
+# CONFIG_IRDA_ULTRA is not set
+
+#
+# IrDA options
+#
+# CONFIG_IRDA_CACHE_LAST_LSAP is not set
+# CONFIG_IRDA_FAST_RR is not set
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+# CONFIG_IRTTY_SIR is not set
+
+#
+# Dongle support
+#
+
+#
+# Old SIR device drivers
+#
+# CONFIG_IRPORT_SIR is not set
+
+#
+# Old Serial dongle support
+#
+
+#
+# FIR device drivers
+#
+CONFIG_OMAP_IR=y
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_OMAP_NOR=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+# CONFIG_MTD_ONENAND_SYNC_READ is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+# CONFIG_OMAP_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+CONFIG_I2C_OMAP=y
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+CONFIG_GPIOEXPANDER_OMAP=y
+CONFIG_MENELAUS=y
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_FIRMWARE_EDID=y
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_LCD_LPH8923 is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_OMAP=y
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_UNWIND_INFO is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_ERRORS is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/omap_innovator_1510_defconfig b/arch/arm/configs/omap_innovator_1510_defconfig
new file mode 100644 (file)
index 0000000..28c087e
--- /dev/null
@@ -0,0 +1,1082 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.14-rc4-omap1
+# Tue Oct 18 17:55:19 2005
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+CONFIG_ARCH_OMAP15XX=y
+# CONFIG_ARCH_OMAP16XX is not set
+
+#
+# OMAP Board Type
+#
+CONFIG_MACH_OMAP_INNOVATOR=y
+# CONFIG_MACH_VOICEBLUE is not set
+# CONFIG_MACH_NETSTAR is not set
+# CONFIG_MACH_OMAP_PALMTE is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
+CONFIG_OMAP_ARM_168MHZ=y
+# CONFIG_OMAP_ARM_150MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+# CONFIG_OMAP_DSP is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM925T=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+CONFIG_CPU_DCACHE_WRITETHROUGH=y
+
+#
+# Bus support
+#
+CONFIG_ISA_DMA_API=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_PREEMPT=y
+# CONFIG_NO_IDLE_HZ is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_LEDS=y
+# CONFIG_LEDS_TIMER is not set
+# CONFIG_LEDS_CPU is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttyS0,115200n8 root=/dev/nfs ip=bootp noinitrd"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=y
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=240
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=320
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_OMAP=y
+CONFIG_OMAP_PS2=m
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_OMAP_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+# CONFIG_I2C_OMAP is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+CONFIG_FB_OMAP_LCDC_INTERNAL=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_BLUETOOTH_TTY is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_DPCM=y
+# CONFIG_USB_STORAGE_USBAT is not set
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_ITMTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+
+#
+# Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+CONFIG_USB_RTL8150=y
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=y
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=y
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+CONFIG_USB_NET_ZAURUS=y
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BROKEN_RFD=y
+# CONFIG_MMC_BULKTRANSFER is not set
+CONFIG_MMC_OMAP=y
+# CONFIG_MMC_WBSD is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_UWIRE is not set
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/omap_innovator_1610_defconfig b/arch/arm/configs/omap_innovator_1610_defconfig
new file mode 100644 (file)
index 0000000..7baf3bc
--- /dev/null
@@ -0,0 +1,750 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.14-rc4-omap1
+# Tue Oct 18 17:55:48 2005
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+# CONFIG_OMAP_DM_TIMER is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+# CONFIG_ARCH_OMAP15XX is not set
+CONFIG_ARCH_OMAP16XX=y
+
+#
+# OMAP Board Type
+#
+CONFIG_MACH_OMAP_INNOVATOR=y
+# CONFIG_MACH_OMAP_H2 is not set
+# CONFIG_MACH_OMAP_H3 is not set
+# CONFIG_MACH_OMAP_OSK is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
+# CONFIG_OMAP_ARM_216MHZ is not set
+CONFIG_OMAP_ARM_192MHZ=y
+# CONFIG_OMAP_ARM_168MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+# CONFIG_OMAP_DSP is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+CONFIG_CPU_DCACHE_WRITETHROUGH=y
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+
+#
+# Bus support
+#
+CONFIG_ISA_DMA_API=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="mem=32M console=tty0 console=ttyS0,115200 initrd=0x10200000,8M root=/dev/ram0 rw"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=m
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_OMAP_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_OMAP_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+CONFIG_FB_OMAP_LCDC_INTERNAL=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_UWIRE is not set
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+# CONFIG_ROOT_NFS is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
index c4d46e4fb4e1d3c0b7907f4697eb7149162fbcbb..d190420599d426f8a38ff1f1a48b96c638a1b5d9 100644 (file)
@@ -1,25 +1,19 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.19
-# Thu Dec  7 16:32:04 2006
+# Linux kernel version: 2.6.14-rc4-omap1
+# Tue Oct 18 17:56:19 2005
 #
 CONFIG_ARM=y
-# CONFIG_GENERIC_TIME is not set
 CONFIG_MMU=y
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_TRACE_IRQFLAGS_SUPPORT=y
-CONFIG_HARDIRQS_SW_RESEND=y
-CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
-CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_VECTORS_BASE=0xffff0000
-CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 
@@ -30,37 +24,30 @@ CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
+CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
+CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
-# CONFIG_SYSFS_DEPRECATED is not set
-# CONFIG_RELAY is not set
 CONFIG_INITRAMFS_SOURCE=""
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_SYSCTL=y
 # CONFIG_EMBEDDED is not set
-CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
-CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
-CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SHMEM=y
-CONFIG_SLAB=y
-CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_RT_MUTEXES=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -68,55 +55,25 @@ CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
-#
-# Block layer
-#
-CONFIG_BLOCK=y
-# CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_LSF is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_DEFAULT_AS is not set
-# CONFIG_DEFAULT_DEADLINE is not set
-CONFIG_DEFAULT_CFQ=y
-# CONFIG_DEFAULT_NOOP is not set
-CONFIG_DEFAULT_IOSCHED="cfq"
-
 #
 # System Type
 #
-# CONFIG_ARCH_AAEC2000 is not set
-# CONFIG_ARCH_INTEGRATOR is not set
-# CONFIG_ARCH_REALVIEW is not set
-# CONFIG_ARCH_VERSATILE is not set
-# CONFIG_ARCH_AT91 is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
 # CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
-# CONFIG_ARCH_NETX is not set
-# CONFIG_ARCH_H720X is not set
-# CONFIG_ARCH_IMX is not set
-# CONFIG_ARCH_IOP32X is not set
-# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
 # CONFIG_ARCH_IXP4XX is not set
 # CONFIG_ARCH_IXP2000 is not set
-# CONFIG_ARCH_IXP23XX is not set
 # CONFIG_ARCH_L7200 is not set
-# CONFIG_ARCH_PNX4008 is not set
 # CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
@@ -124,6 +81,10 @@ CONFIG_DEFAULT_IOSCHED="cfq"
 # CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
 CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
 
 #
 # TI OMAP Implementations
@@ -137,11 +98,9 @@ CONFIG_ARCH_OMAP1=y
 #
 CONFIG_OMAP_RESET_CLOCKS=y
 # CONFIG_OMAP_BOOT_TAG is not set
-# CONFIG_OMAP_GPIO_SWITCH is not set
 CONFIG_OMAP_MUX=y
 # CONFIG_OMAP_MUX_DEBUG is not set
 CONFIG_OMAP_MUX_WARNINGS=y
-CONFIG_OMAP_MCBSP=y
 # CONFIG_OMAP_MPU_TIMER is not set
 CONFIG_OMAP_32K_TIMER=y
 CONFIG_OMAP_32K_TIMER_HZ=128
@@ -166,7 +125,6 @@ CONFIG_ARCH_OMAP16XX=y
 # CONFIG_MACH_OMAP_H3 is not set
 CONFIG_MACH_OMAP_OSK=y
 # CONFIG_OMAP_OSK_MISTRAL is not set
-# CONFIG_MACH_NOKIA770 is not set
 # CONFIG_MACH_OMAP_GENERIC is not set
 
 #
@@ -179,6 +137,7 @@ CONFIG_OMAP_ARM_192MHZ=y
 # CONFIG_OMAP_ARM_120MHZ is not set
 # CONFIG_OMAP_ARM_60MHZ is not set
 # CONFIG_OMAP_ARM_30MHZ is not set
+# CONFIG_OMAP_DSP is not set
 
 #
 # Processor Type
@@ -190,8 +149,6 @@ CONFIG_CPU_ABRT_EV5TJ=y
 CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_COPY_V4WB=y
 CONFIG_CPU_TLB_V4WBI=y
-CONFIG_CPU_CP15=y
-CONFIG_CPU_CP15_MMU=y
 
 #
 # Processor Features
@@ -205,6 +162,7 @@ CONFIG_CPU_CP15_MMU=y
 #
 # Bus support
 #
+CONFIG_ISA_DMA_API=y
 
 #
 # PCCARD (PCMCIA/CardBus) support
@@ -225,8 +183,6 @@ CONFIG_OMAP_CF=y
 #
 # CONFIG_PREEMPT is not set
 CONFIG_NO_IDLE_HZ=y
-CONFIG_HZ=128
-# CONFIG_AEABI is not set
 # CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
 CONFIG_SELECT_MEMORY_MODEL=y
 CONFIG_FLATMEM_MANUAL=y
@@ -235,8 +191,6 @@ CONFIG_FLATMEM_MANUAL=y
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
-CONFIG_SPLIT_PTLOCK_CPUS=4096
-# CONFIG_RESOURCES_64BIT is not set
 # CONFIG_LEDS is not set
 CONFIG_ALIGNMENT_TRAP=y
 
@@ -277,9 +231,6 @@ CONFIG_BINFMT_ELF=y
 # Power management options
 #
 CONFIG_PM=y
-# CONFIG_PM_LEGACY is not set
-# CONFIG_PM_DEBUG is not set
-# CONFIG_PM_SYSFS_DEPRECATED is not set
 # CONFIG_APM is not set
 
 #
@@ -290,13 +241,9 @@ CONFIG_NET=y
 #
 # Networking options
 #
-# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=m
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
-CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
-# CONFIG_XFRM_SUB_POLICY is not set
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
@@ -314,21 +261,12 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_XFRM_TUNNEL is not set
 # CONFIG_INET_TUNNEL is not set
-CONFIG_INET_XFRM_MODE_TRANSPORT=y
-CONFIG_INET_XFRM_MODE_TUNNEL=y
-CONFIG_INET_XFRM_MODE_BEET=y
 CONFIG_INET_DIAG=y
 CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_CUBIC=y
-CONFIG_DEFAULT_TCP_CONG="cubic"
-# CONFIG_TCP_MD5SIG is not set
+CONFIG_TCP_CONG_BIC=y
 # CONFIG_IPV6 is not set
-# CONFIG_INET6_XFRM_TUNNEL is not set
-# CONFIG_INET6_TUNNEL is not set
-# CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
 
 #
@@ -340,11 +278,6 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # SCTP Configuration (EXPERIMENTAL)
 #
 # CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
-# CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
@@ -354,13 +287,11 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
@@ -381,12 +312,6 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 CONFIG_FW_LOADER=y
-# CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
-# CONFIG_CONNECTOR is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -407,8 +332,6 @@ CONFIG_MTD_BLOCK=y
 # CONFIG_FTL is not set
 # CONFIG_NFTL is not set
 # CONFIG_INFTL is not set
-# CONFIG_RFD_FTL is not set
-# CONFIG_SSFDC is not set
 
 #
 # RAM/ROM/Flash chip drivers
@@ -434,7 +357,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -442,6 +365,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
 # CONFIG_MTD_PHYSMAP is not set
 # CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_EDB7312 is not set
 CONFIG_MTD_OMAP_NOR=y
 # CONFIG_MTD_PLATRAM is not set
 
@@ -451,6 +375,7 @@ CONFIG_MTD_OMAP_NOR=y
 # CONFIG_MTD_SLRAM is not set
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
 # CONFIG_MTD_BLOCK2MTD is not set
 
 #
@@ -465,11 +390,6 @@ CONFIG_MTD_OMAP_NOR=y
 #
 # CONFIG_MTD_NAND is not set
 
-#
-# OneNAND Flash Device Drivers
-#
-# CONFIG_MTD_ONENAND is not set
-
 #
 # Parallel port support
 #
@@ -489,9 +409,16 @@ CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
 # CONFIG_ATA_OVER_ETH is not set
 
 #
@@ -526,12 +453,6 @@ CONFIG_BLK_DEV_IDECS=m
 #
 # CONFIG_RAID_ATTRS is not set
 # CONFIG_SCSI is not set
-# CONFIG_SCSI_NETLINK is not set
-
-#
-# Serial ATA (prod) and Parallel ATA (experimental) drivers
-#
-# CONFIG_ATA is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -606,10 +527,8 @@ CONFIG_PPP_MULTILINK=y
 # CONFIG_PPP_SYNC_TTY is not set
 # CONFIG_PPP_DEFLATE is not set
 # CONFIG_PPP_BSDCOMP is not set
-# CONFIG_PPP_MPPE is not set
 # CONFIG_PPPOE is not set
 # CONFIG_SLIP is not set
-CONFIG_SLHC=y
 # CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
@@ -624,7 +543,6 @@ CONFIG_SLHC=y
 # Input device support
 #
 CONFIG_INPUT=y
-# CONFIG_INPUT_FF_MEMLESS is not set
 
 #
 # Userland interfaces
@@ -647,7 +565,6 @@ CONFIG_INPUT_KEYBOARD=y
 # CONFIG_KEYBOARD_LKKBD is not set
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
-# CONFIG_KEYBOARD_STOWAWAY is not set
 CONFIG_KEYBOARD_OMAP=y
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_INPUT_JOYSTICK is not set
@@ -656,9 +573,7 @@ CONFIG_INPUT_TOUCHSCREEN=y
 # CONFIG_TOUCHSCREEN_ELO is not set
 # CONFIG_TOUCHSCREEN_MTOUCH is not set
 # CONFIG_TOUCHSCREEN_MK712 is not set
-# CONFIG_TOUCHSCREEN_PENMOUNT is not set
-# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
-# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+CONFIG_TOUCHSCREEN_OMAP=y
 # CONFIG_INPUT_MISC is not set
 
 #
@@ -673,7 +588,6 @@ CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 CONFIG_HW_CONSOLE=y
-# CONFIG_VT_HW_CONSOLE_BINDING is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
@@ -683,7 +597,6 @@ CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 # CONFIG_SERIAL_8250_CS is not set
 CONFIG_SERIAL_8250_NR_UARTS=4
-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -704,24 +617,26 @@ CONFIG_LEGACY_PTY_COUNT=256
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-CONFIG_HW_RANDOM=m
-CONFIG_HW_RANDOM_OMAP=m
+# CONFIG_OMAP_RNG is not set
 # CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_OMAP_RTC is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 
+#
+# Ftape, the floppy tape device driver
+#
+
 #
 # PCMCIA character devices
 #
 # CONFIG_SYNCLINK_CS is not set
-# CONFIG_CARDMAN_4000 is not set
-# CONFIG_CARDMAN_4040 is not set
 # CONFIG_RAW_DRIVER is not set
 
 #
 # TPM devices
 #
-# CONFIG_TCG_TPM is not set
 
 #
 # I2C support
@@ -739,11 +654,10 @@ CONFIG_I2C_CHARDEV=y
 #
 # I2C Hardware Bus support
 #
-# CONFIG_I2C_OCORES is not set
-CONFIG_I2C_OMAP=y
 # CONFIG_I2C_PARPORT_LIGHT is not set
 # CONFIG_I2C_STUB is not set
 # CONFIG_I2C_PCA_ISA is not set
+CONFIG_I2C_OMAP=y
 
 #
 # Miscellaneous I2C Chip support
@@ -754,31 +668,22 @@ CONFIG_I2C_OMAP=y
 # CONFIG_SENSORS_PCF8574 is not set
 # CONFIG_SENSORS_PCA9539 is not set
 # CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
 # CONFIG_ISP1301_OMAP is not set
 CONFIG_TPS65010=y
+# CONFIG_SENSORS_TLV320AIC23 is not set
+# CONFIG_GPIOEXPANDER_OMAP is not set
 # CONFIG_SENSORS_MAX6875 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
 # CONFIG_I2C_DEBUG_CHIP is not set
 
-#
-# SPI support
-#
-# CONFIG_SPI is not set
-# CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
-# CONFIG_W1 is not set
-
 #
 # Hardware Monitoring support
 #
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
-# CONFIG_SENSORS_ABITUGURU is not set
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
 # CONFIG_SENSORS_ADM1026 is not set
@@ -787,7 +692,6 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_ASB100 is not set
 # CONFIG_SENSORS_ATXP1 is not set
 # CONFIG_SENSORS_DS1621 is not set
-# CONFIG_SENSORS_F71805F is not set
 # CONFIG_SENSORS_FSCHER is not set
 # CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_GL518SM is not set
@@ -806,11 +710,8 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
-# CONFIG_SENSORS_SMSC47M192 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
-# CONFIG_SENSORS_VT1211 is not set
 # CONFIG_SENSORS_W83781D is not set
-# CONFIG_SENSORS_W83791D is not set
 # CONFIG_SENSORS_W83792D is not set
 # CONFIG_SENSORS_W83L785TS is not set
 # CONFIG_SENSORS_W83627HF is not set
@@ -820,19 +721,9 @@ CONFIG_HWMON=y
 #
 # Misc devices
 #
-# CONFIG_TIFM_CORE is not set
-
-#
-# LED devices
-#
-# CONFIG_NEW_LEDS is not set
-
-#
-# LED drivers
-#
 
 #
-# LED Triggers
+# Multimedia Capabilities Port drivers
 #
 
 #
@@ -848,16 +739,19 @@ CONFIG_HWMON=y
 #
 # Graphics support
 #
-CONFIG_FIRMWARE_EDID=y
 CONFIG_FB=y
 # CONFIG_FB_CFB_FILLRECT is not set
 # CONFIG_FB_CFB_COPYAREA is not set
 # CONFIG_FB_CFB_IMAGEBLIT is not set
+CONFIG_FB_SOFT_CURSOR=y
 # CONFIG_FB_MACMODES is not set
-# CONFIG_FB_BACKLIGHT is not set
 CONFIG_FB_MODE_HELPERS=y
 # CONFIG_FB_TILEBLITTING is not set
 # CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+CONFIG_FB_OMAP_LCDC_INTERNAL=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_DMA_TUNE is not set
 # CONFIG_FB_VIRTUAL is not set
 
 #
@@ -866,7 +760,6 @@ CONFIG_FB_MODE_HELPERS=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
-# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
 CONFIG_FONTS=y
 CONFIG_FONT_8x8=y
 # CONFIG_FONT_8x16 is not set
@@ -898,13 +791,8 @@ CONFIG_LOGO_LINUX_CLUT224=y
 #
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
-# CONFIG_USB_ARCH_HAS_EHCI is not set
 # CONFIG_USB is not set
 
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
-#
-
 #
 # USB Gadget Support
 #
@@ -916,10 +804,10 @@ CONFIG_USB_ARCH_HAS_OHCI=y
 # CONFIG_MMC is not set
 
 #
-# Real Time Clock
+# Synchronous Serial Interfaces (SSI)
 #
-CONFIG_RTC_LIB=y
-# CONFIG_RTC_CLASS is not set
+CONFIG_OMAP_UWIRE=y
+CONFIG_OMAP_TSC2101=y
 
 #
 # File systems
@@ -928,17 +816,14 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_EXT4DEV_FS is not set
+# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
-# CONFIG_GFS2_FS is not set
-# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
-CONFIG_INOTIFY_USER=y
 # CONFIG_QUOTA is not set
 CONFIG_DNOTIFY=y
 CONFIG_AUTOFS_FS=y
@@ -965,12 +850,11 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # Pseudo filesystems
 #
 CONFIG_PROC_FS=y
-CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
 # CONFIG_TMPFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
-# CONFIG_CONFIGFS_FS is not set
+# CONFIG_RELAYFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -986,8 +870,6 @@ CONFIG_RAMFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
-# CONFIG_JFFS2_SUMMARY is not set
-# CONFIG_JFFS2_FS_XATTR is not set
 # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
 CONFIG_JFFS2_ZLIB=y
 CONFIG_JFFS2_RTIME=y
@@ -1072,11 +954,6 @@ CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_KOI8_U is not set
 # CONFIG_NLS_UTF8 is not set
 
-#
-# Distributed Lock Manager
-#
-# CONFIG_DLM is not set
-
 #
 # Profiling support
 #
@@ -1086,15 +963,10 @@ CONFIG_NLS_ISO8859_1=m
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
-CONFIG_ENABLE_MUST_CHECK=y
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_UNUSED_SYMBOLS is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_DEBUG_BUGVERBOSE=y
-# CONFIG_DEBUG_FS is not set
 CONFIG_FRAME_POINTER=y
-# CONFIG_HEADERS_CHECK is not set
 # CONFIG_DEBUG_USER is not set
 
 #
@@ -1108,6 +980,10 @@ CONFIG_FRAME_POINTER=y
 #
 # CONFIG_CRYPTO is not set
 
+#
+# Hardware crypto devices
+#
+
 #
 # Library routines
 #
@@ -1117,4 +993,3 @@ CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
-CONFIG_PLIST=y
diff --git a/arch/arm/configs/omap_perseus2_730_defconfig b/arch/arm/configs/omap_perseus2_730_defconfig
new file mode 100644 (file)
index 0000000..7e08ad3
--- /dev/null
@@ -0,0 +1,811 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.14-rc4-omap1
+# Tue Oct 18 17:57:11 2005
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+
+#
+# OMAP Core Type
+#
+CONFIG_ARCH_OMAP730=y
+# CONFIG_ARCH_OMAP15XX is not set
+# CONFIG_ARCH_OMAP16XX is not set
+
+#
+# OMAP Board Type
+#
+CONFIG_MACH_OMAP_PERSEUS2=y
+
+#
+# OMAP CPU Speed
+#
+# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
+# CONFIG_OMAP_ARM_195MHZ is not set
+CONFIG_OMAP_ARM_182MHZ=y
+# CONFIG_OMAP_ARM_168MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+
+#
+# Bus support
+#
+CONFIG_ISA_DMA_API=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_PREEMPT=y
+# CONFIG_NO_IDLE_HZ is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+CONFIG_LEDS_CPU=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="mem=32M console=ttyS0,115200 ip=dhcp"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_EDB7312 is not set
+CONFIG_MTD_OMAP_NOR=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_OMAP=y
+# CONFIG_MTD_NAND_TOTO is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_OMAP_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+CONFIG_FB_OMAP_LCDC_INTERNAL=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+CONFIG_FB_VIRTUAL=y
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+CONFIG_OMAP_UWIRE=y
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/palmte_defconfig b/arch/arm/configs/palmte_defconfig
new file mode 100644 (file)
index 0000000..26a8999
--- /dev/null
@@ -0,0 +1,648 @@
+#
+# Palm Tungsten E default kernel configuration
+# Created by Romain Goyet <palmtelinux-developpers@lists.sf.net>
+# Linux kernel version: 2.6.13-rc6-omap1
+# Fri Aug 26 16:01:18 2005
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_CLEAN_COMPILE is not set
+CONFIG_BROKEN=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+CONFIG_HOTPLUG=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+CONFIG_ARCH_OMAP15XX=y
+# CONFIG_ARCH_OMAP16XX is not set
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_VOICEBLUE is not set
+# CONFIG_MACH_NETSTAR is not set
+CONFIG_MACH_OMAP_PALMTE=y
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER=y
+# CONFIG_OMAP_ARM_168MHZ is not set
+# CONFIG_OMAP_ARM_150MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+# CONFIG_OMAP_DSP is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM925T=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+
+#
+# Bus support
+#
+CONFIG_ISA_DMA_API=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+# CONFIG_NET is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=320
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=320
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_OMAP_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+# CONFIG_I2C_SENSOR is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+CONFIG_FB_OMAP_INTERNAL_LCDC=y
+# CONFIG_FB_OMAP_EXTERNAL_LCDC is not set
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+CONFIG_USB_GADGET_OMAP=y
+CONFIG_USB_OMAP=y
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+CONFIG_USB_ZERO=y
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+# CONFIG_MMC_BLOCK_BROKEN_RFD is not set
+# CONFIG_MMC_BULKTRANSFER is not set
+CONFIG_MMC_OMAP=y
+# CONFIG_MMC_WBSD is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_UWIRE is not set
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=850
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=y
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
diff --git a/arch/arm/configs/palmtt_defconfig b/arch/arm/configs/palmtt_defconfig
new file mode 100644 (file)
index 0000000..4a5fcb4
--- /dev/null
@@ -0,0 +1,844 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.19-rc3-omap1
+# Sun Oct 29 00:36:12 2006
+#
+CONFIG_ARM=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MCBSP=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+CONFIG_OMAP_LL_DEBUG_UART2=y
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+CONFIG_OMAP_DSP=y
+# CONFIG_OMAP_DSP_MBCMD_VERBOSE is not set
+# CONFIG_OMAP_DSP_TASK_MULTIOPEN is not set
+CONFIG_OMAP_DSP_FBEXPORT=y
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+CONFIG_ARCH_OMAP15XX=y
+# CONFIG_ARCH_OMAP16XX is not set
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_VOICEBLUE is not set
+# CONFIG_MACH_OMAP_PALMTE is not set
+# CONFIG_MACH_OMAP_PALMZ71 is not set
+CONFIG_MACH_OMAP_PALMTT=y
+# CONFIG_MACH_AMS_DELTA is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER=y
+# CONFIG_OMAP_ARM_168MHZ is not set
+# CONFIG_OMAP_ARM_150MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM925T=y
+CONFIG_CPU_32v4T=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+
+#
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/mmcblk0p2 rw init=/init"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_MISC=y
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+# CONFIG_NETDEVICES is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=320
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=320
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_TSDEV=y
+CONFIG_INPUT_TSDEV_SCREEN_X=320
+CONFIG_INPUT_TSDEV_SCREEN_Y=320
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_TSC2102 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+# CONFIG_OMAP_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_OMAP_UWIRE=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_TSC2102 is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
+# LED devices
+#
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+CONFIG_LEDS_OMAP=y
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_LCD_MIPID is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_DEVICE=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_DEVICE=y
+CONFIG_BACKLIGHT_OMAP=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# Enable Host or Gadget support to see Inventra options
+#
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+
+#
+# RTC drivers
+#
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+CONFIG_RTC_DRV_OMAP=y
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_UWIRE is not set
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_UNWIND_INFO is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_USER is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=y
+CONFIG_PLIST=y
diff --git a/arch/arm/configs/palmz71_defconfig b/arch/arm/configs/palmz71_defconfig
new file mode 100644 (file)
index 0000000..ec32035
--- /dev/null
@@ -0,0 +1,809 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.18-omap1
+# Fri Oct 20 22:04:08 2006
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION="-z71"
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Block layer
+#
+# CONFIG_BLK_DEV_IO_TRACE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MCBSP=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+# CONFIG_OMAP_DSP is not set
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+CONFIG_ARCH_OMAP15XX=y
+# CONFIG_ARCH_OMAP16XX is not set
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_VOICEBLUE is not set
+# CONFIG_MACH_OMAP_PALMTE is not set
+CONFIG_MACH_OMAP_PALMZ71=y
+# CONFIG_MACH_AMS_DELTA is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER=y
+# CONFIG_OMAP_ARM_168MHZ is not set
+# CONFIG_OMAP_ARM_150MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM925T=y
+CONFIG_CPU_32v4T=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+
+#
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_MISC=y
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+# CONFIG_NETDEVICES is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=320
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=320
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_TSDEV=y
+CONFIG_INPUT_TSDEV_SCREEN_X=320
+CONFIG_INPUT_TSDEV_SCREEN_Y=320
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=16
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+CONFIG_OMAP_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_OMAP_UWIRE=y
+
+#
+# SPI Protocol Masters
+#
+
+#
+# Dallas's 1-wire bus
+#
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_LCD_MIPID is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_DEVICE=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_DEVICE=y
+CONFIG_BACKLIGHT_OMAP=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# Enable Host or Gadget support to see Inventra options
+#
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_OMAP=y
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+CONFIG_OMAP_UWIRE=y
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_UNWIND_INFO is not set
+# CONFIG_DEBUG_USER is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=y
+CONFIG_PLIST=y
diff --git a/arch/arm/configs/sx1_defconfig b/arch/arm/configs/sx1_defconfig
new file mode 100644 (file)
index 0000000..f6aa4c6
--- /dev/null
@@ -0,0 +1,1037 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.19-rc6-omap1
+# Sat Nov 18 19:03:38 2006
+#
+CONFIG_ARM=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+# CONFIG_IKCONFIG_PROC is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_KALLSYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+# CONFIG_ELF_CORE is not set
+# CONFIG_BASE_FULL is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+# CONFIG_SHMEM is not set
+# CONFIG_SLAB is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_RT_MUTEXES=y
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=1
+CONFIG_SLOB=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_BOOT_TAG=y
+# CONFIG_OMAP_BOOT_REASON is not set
+# CONFIG_OMAP_COMPONENT_VERSION is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MCBSP=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+CONFIG_OMAP_LL_DEBUG_UART3=y
+CONFIG_OMAP_SERIAL_WAKE=y
+CONFIG_OMAP_DSP=y
+# CONFIG_OMAP_DSP_MBCMD_VERBOSE is not set
+# CONFIG_OMAP_DSP_TASK_MULTIOPEN is not set
+# CONFIG_OMAP_DSP_FBEXPORT is not set
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+CONFIG_ARCH_OMAP15XX=y
+# CONFIG_ARCH_OMAP16XX is not set
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_VOICEBLUE is not set
+# CONFIG_MACH_OMAP_PALMTE is not set
+# CONFIG_MACH_OMAP_PALMZ71 is not set
+# CONFIG_MACH_OMAP_PALMTT is not set
+CONFIG_MACH_SX1=y
+# CONFIG_MACH_AMS_DELTA is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
+CONFIG_OMAP_ARM_168MHZ=y
+# CONFIG_OMAP_ARM_150MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM925T=y
+CONFIG_CPU_32v4T=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+
+#
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_PREEMPT=y
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+CONFIG_CONNECTOR=y
+# CONFIG_PROC_EVENTS is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=m
+CONFIG_BLK_DEV_RAM_COUNT=2
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_FIXED_PHY is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_CONSOLE is not set
+CONFIG_SERIAL_8250_NR_UARTS=3
+CONFIG_SERIAL_8250_RUNTIME_UARTS=3
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+CONFIG_OMAP_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+# CONFIG_TIFM_CORE is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FIRMWARE_EDID is not set
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_LCD_MIPID is not set
+CONFIG_FB_OMAP_BOOTLOADER_INIT=y
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+CONFIG_FONT_MINI_4x6=y
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# ALSA ARM devices
+#
+# CONFIG_SND_OMAP_AIC23 is not set
+# CONFIG_SND_OMAP_TSC2101 is not set
+CONFIG_SND_SX1=y
+# CONFIG_SND_OMAP_TSC2102 is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+CONFIG_USB_GADGET_OMAP=y
+CONFIG_USB_OMAP=y
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=y
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_OMAP=y
+# CONFIG_MMC_TIFM_SD is not set
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_UWIRE is not set
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=866
+CONFIG_FAT_DEFAULT_IOCHARSET="koi8-r"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=y
+# CONFIG_CRAMFS_LINEAR is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+CONFIG_NLS_CODEPAGE_866=y
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+CONFIG_NLS_CODEPAGE_1251=y
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+CONFIG_NLS_ISO8859_5=y
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+CONFIG_NLS_KOI8_R=y
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=y
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHEDSTATS is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_RWSEMS is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_FRAME_POINTER is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
index d97ff6338682bbe818eb0f48debae6f75ab4dcef..f1a824e9cf7bf35c00dc497e5f5d2fdf83b54455 100644 (file)
@@ -139,8 +139,6 @@ static struct platform_device h2_nor_device = {
        .resource       = &h2_nor_resource,
 };
 
-#if 0  /* REVISIT: Enable when nand_platform_data is applied */
-
 static struct mtd_partition h2_nand_partitions[] = {
 #if 0
        /* REVISIT:  enable these partitions if you make NAND BOOT
@@ -197,7 +195,6 @@ static struct platform_device h2_nand_device = {
        .num_resources  = 1,
        .resource       = &h2_nand_resource,
 };
-#endif
 
 static struct resource h2_smc91x_resources[] = {
        [0] = {
@@ -334,7 +331,7 @@ static struct platform_device h2_mcbsp1_device = {
 
 static struct platform_device *h2_devices[] __initdata = {
        &h2_nor_device,
-       //&h2_nand_device,
+       &h2_nand_device,
        &h2_smc91x_device,
        &h2_irda_device,
        &h2_kp_device,
@@ -419,12 +416,10 @@ static void __init h2_init(void)
        h2_nor_resource.end = h2_nor_resource.start = omap_cs3_phys();
        h2_nor_resource.end += SZ_32M - 1;
 
-#if 0  /* REVISIT: Enable when nand_platform_data is applied */
        h2_nand_resource.end = h2_nand_resource.start = OMAP_CS2B_PHYS;
        h2_nand_resource.end += SZ_4K - 1;
        if (!(omap_request_gpio(H2_NAND_RB_GPIO_PIN)))
                h2_nand_data.dev_ready = h2_nand_dev_ready;
-#endif
 
        omap_cfg_reg(L3_1610_FLASH_CS2B_OE);
        omap_cfg_reg(M8_1610_FLASH_CS2B_WE);
index f625f6dd228a5187598d115b7293afdee924c755..7e3b24fccff13a0299293b403f9ca1875df9a8f8 100644 (file)
@@ -651,7 +651,7 @@ int __init omap1_clk_init(void)
 
 #ifdef CONFIG_DEBUG_LL
        /* Resets some clocks that may be left on from bootloader,
-        * but leaves serial clocks on.
+        * but leaves serial clocks on.
         */
        omap_writel(0x3 << 29, MOD_CONF_CTRL_0);
 #endif
index da8a3ac47e136c52dfc122641d866d207f1233b7..497c8bb5e69b5b47853672a47c4b3b21eb49d451 100644 (file)
@@ -26,7 +26,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-#if defined(CONFIG_RTC_DRV_OMAP) || defined(CONFIG_RTC_DRV_OMAP_MODULE)
+#if defined(CONFIG_OMAP_RTC) || defined(CONFIG_RTC_DRV_OMAP) || defined(CONFIG_RTC_DRV_OMAP_MODULE)
 
 #define        OMAP_RTC_BASE           0xfffb4800
 
index 1b7e4a506c2646e66788aaa47f8056147ba4da4a..64fefff5d99f61ac5348526df6e304f926d1ae08 100644 (file)
@@ -39,6 +39,9 @@
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/clocksource.h>
 
 #include <asm/system.h>
 #include <asm/hardware.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
 
-struct sys_timer omap_timer;
 
-/*
- * ---------------------------------------------------------------------------
- * MPU timer
- * ---------------------------------------------------------------------------
- */
 #define OMAP_MPU_TIMER_BASE            OMAP_MPU_TIMER1_BASE
 #define OMAP_MPU_TIMER_OFFSET          0x100
 
@@ -88,21 +85,6 @@ static inline unsigned long long cycles_2_ns(unsigned long long cyc)
        return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
 }
 
-/*
- * MPU_TICKS_PER_SEC must be an even number, otherwise machinecycles_to_usecs
- * will break. On P2, the timer count rate is 6.5 MHz after programming PTV
- * with 0. This divides the 13MHz input by 2, and is undocumented.
- */
-#if defined(CONFIG_MACH_OMAP_PERSEUS2) || defined(CONFIG_MACH_OMAP_FSAMPLE)
-/* REVISIT: This ifdef construct should be replaced by a query to clock
- * framework to see if timer base frequency is 12.0, 13.0 or 19.2 MHz.
- */
-#define MPU_TICKS_PER_SEC              (13000000 / 2)
-#else
-#define MPU_TICKS_PER_SEC              (12000000 / 2)
-#endif
-
-#define MPU_TIMER_TICK_PERIOD          ((MPU_TICKS_PER_SEC / HZ) - 1)
 
 typedef struct {
        u32 cntl;                       /* CNTL_TIMER, R/W */
@@ -131,87 +113,94 @@ static inline void omap_mpu_timer_start(int nr, unsigned long load_val)
        timer->cntl = (MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_AR | MPU_TIMER_ST);
 }
 
-unsigned long omap_mpu_timer_ticks_to_usecs(unsigned long nr_ticks)
+/*
+ * ---------------------------------------------------------------------------
+ * MPU timer 1 ... count down to zero, interrupt, reload
+ * ---------------------------------------------------------------------------
+ */
+static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id)
 {
-       unsigned long long nsec;
+       write_seqlock(&xtime_lock);
+       /* NOTE:  no lost-tick detection/handling! */
+       timer_tick();
+       write_sequnlock(&xtime_lock);
 
-       nsec = cycles_2_ns((unsigned long long)nr_ticks);
-       return (unsigned long)nsec / 1000;
+       return IRQ_HANDLED;
 }
 
-/*
- * Last processed system timer interrupt
- */
-static unsigned long omap_mpu_timer_last = 0;
+static struct irqaction omap_mpu_timer1_irq = {
+       .name           = "mpu_timer1",
+       .flags          = IRQF_DISABLED | IRQF_TIMER,
+       .handler        = omap_mpu_timer1_interrupt,
+};
 
-/*
- * Returns elapsed usecs since last system timer interrupt
- */
-static unsigned long omap_mpu_timer_gettimeoffset(void)
+static __init void omap_init_mpu_timer(unsigned long rate)
 {
-       unsigned long now = 0 - omap_mpu_timer_read(0);
-       unsigned long elapsed = now - omap_mpu_timer_last;
+       set_cyc2ns_scale(rate / 1000);
 
-       return omap_mpu_timer_ticks_to_usecs(elapsed);
+       setup_irq(INT_TIMER1, &omap_mpu_timer1_irq);
+       omap_mpu_timer_start(0, (rate / HZ) - 1);
 }
 
 /*
- * Elapsed time between interrupts is calculated using timer0.
- * Latency during the interrupt is calculated using timer1.
- * Both timer0 and timer1 are counting at 6MHz (P2 6.5MHz).
+ * ---------------------------------------------------------------------------
+ * MPU timer 2 ... free running 32-bit clock source and scheduler clock
+ * ---------------------------------------------------------------------------
  */
-static irqreturn_t omap_mpu_timer_interrupt(int irq, void *dev_id)
-{
-       unsigned long now, latency;
 
-       write_seqlock(&xtime_lock);
-       now = 0 - omap_mpu_timer_read(0);
-       latency = MPU_TICKS_PER_SEC / HZ - omap_mpu_timer_read(1);
-       omap_mpu_timer_last = now - latency;
-       timer_tick();
-       write_sequnlock(&xtime_lock);
+static unsigned long omap_mpu_timer2_overflows;
 
+static irqreturn_t omap_mpu_timer2_interrupt(int irq, void *dev_id)
+{
+       omap_mpu_timer2_overflows++;
        return IRQ_HANDLED;
 }
 
-static struct irqaction omap_mpu_timer_irq = {
-       .name           = "mpu timer",
-       .flags          = IRQF_DISABLED | IRQF_TIMER,
-       .handler        = omap_mpu_timer_interrupt,
+static struct irqaction omap_mpu_timer2_irq = {
+       .name           = "mpu_timer2",
+       .flags          = IRQF_DISABLED,
+       .handler        = omap_mpu_timer2_interrupt,
 };
 
-static unsigned long omap_mpu_timer1_overflows;
-static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id)
+static cycle_t mpu_read(void)
 {
-       omap_mpu_timer1_overflows++;
-       return IRQ_HANDLED;
+       return ~omap_mpu_timer_read(1);
 }
 
-static struct irqaction omap_mpu_timer1_irq = {
-       .name           = "mpu timer1 overflow",
-       .flags          = IRQF_DISABLED,
-       .handler        = omap_mpu_timer1_interrupt,
+static struct clocksource clocksource_mpu = {
+       .name           = "mpu_timer2",
+       .rating         = 300,
+       .read           = mpu_read,
+       .mask           = CLOCKSOURCE_MASK(32),
+       .shift          = 24,
+       .is_continuous  = 1,
 };
 
-static __init void omap_init_mpu_timer(void)
+static void __init omap_init_clocksource(unsigned long rate)
 {
-       set_cyc2ns_scale(MPU_TICKS_PER_SEC / 1000);
-       omap_timer.offset = omap_mpu_timer_gettimeoffset;
-       setup_irq(INT_TIMER1, &omap_mpu_timer1_irq);
-       setup_irq(INT_TIMER2, &omap_mpu_timer_irq);
-       omap_mpu_timer_start(0, 0xffffffff);
-       omap_mpu_timer_start(1, MPU_TIMER_TICK_PERIOD);
+       static char err[] __initdata = KERN_ERR
+                       "%s: can't register clocksource!\n";
+
+       clocksource_mpu.mult
+               = clocksource_khz2mult(rate/1000, clocksource_mpu.shift);
+
+       setup_irq(INT_TIMER2, &omap_mpu_timer2_irq);
+       omap_mpu_timer_start(1, ~0);
+
+       if (clocksource_register(&clocksource_mpu))
+               printk(err, clocksource_mpu.name);
 }
 
+
 /*
  * Scheduler clock - returns current time in nanosec units.
  */
 unsigned long long sched_clock(void)
 {
-       unsigned long ticks = 0 - omap_mpu_timer_read(0);
+       unsigned long ticks = 0 - omap_mpu_timer_read(1);
        unsigned long long ticks64;
 
-       ticks64 = omap_mpu_timer1_overflows;
+       ticks64 = omap_mpu_timer2_overflows;
        ticks64 <<= 32;
        ticks64 |= ticks;
 
@@ -225,10 +214,21 @@ unsigned long long sched_clock(void)
  */
 static void __init omap_timer_init(void)
 {
-       omap_init_mpu_timer();
+       struct clk      *ck_ref = clk_get(NULL, "ck_ref");
+       unsigned long   rate;
+
+       BUG_ON(IS_ERR(ck_ref));
+
+       rate = clk_get_rate(ck_ref);
+       clk_put(ck_ref);
+
+       /* PTV = 0 */
+       rate /= 2;
+
+       omap_init_mpu_timer(rate);
+       omap_init_clocksource(rate);
 }
 
 struct sys_timer omap_timer = {
        .init           = omap_timer_init,
-       .offset         = NULL,         /* Initialized later */
 };
index 7e76fbf19b5d934dcfa76fc938f89eb157e6dd72..7ccc3c141dbdc7413403a95858df753436cab3aa 100644 (file)
@@ -37,7 +37,6 @@
 
 #include <asm/io.h>
 
-
 #define        SDP2430_FLASH_CS        0
 #define        SDP2430_SMC91X_CS       5
 
index e85bbebe900cb2dc62bbab673d561ec1b8229ae4..df9f3bed35174e105e18567d03259fb198562e1d 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/input.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/delay.h>
 
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
index 6a94e54848fd7a965294c1be8fc72e350878aaee..b20411139401ff110b136a3a2cb5199dbe91978e 100644 (file)
@@ -8,4 +8,5 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
 
 oprofile-y                             := $(DRIVER_OBJS) common.o backtrace.o
 oprofile-$(CONFIG_CPU_XSCALE)          += op_model_xscale.o
+oprofile-$(CONFIG_CPU_V6)              += op_model_v6.o
 
index 6f833358cd0612c4c13e5d59619e86ccee2749e5..f4661725b48d787169fcefcdde552f576e28c56a 100644 (file)
@@ -135,6 +135,10 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
        spec = &op_xscale_spec;
 #endif
 
+#ifdef CONFIG_CPU_V6
+       spec = &op_arm11_spec;
+#endif
+
        if (spec) {
                ret = spec->init();
                if (ret < 0)
index 38c6ad158547e2e615620888c59848be57784f46..b45efa5299453f904fabf91885d8829a90b4178e 100644 (file)
@@ -24,6 +24,10 @@ struct op_arm_model_spec {
 extern struct op_arm_model_spec op_xscale_spec;
 #endif
 
+#ifdef CONFIG_CPU_V6
+extern struct op_arm_model_spec op_arm11_spec;
+#endif
+
 extern void arm_backtrace(struct pt_regs * const regs, unsigned int depth);
 
 extern int __init op_arm_init(struct oprofile_operations *ops, struct op_arm_model_spec *spec);
diff --git a/arch/arm/oprofile/op_model_v6.c b/arch/arm/oprofile/op_model_v6.c
new file mode 100644 (file)
index 0000000..63f3818
--- /dev/null
@@ -0,0 +1,280 @@
+/**
+ * @file op_model_v6.c
+ * ARM11 Performance Monitor Driver
+ *
+ * Based on op_model_xscale.c
+ *
+ * @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com>
+ * @remark Copyright 2000-2004 MontaVista Software Inc
+ * @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com>
+ * @remark Copyright 2004 Intel Corporation
+ * @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk>
+ * @remark Copyright 2004 OProfile Authors
+ *
+ * @remark Read the file COPYING
+ *
+ * @author Tony Lindgren <tony@atomide.com>
+ */
+
+/* #define DEBUG */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/oprofile.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include "op_counter.h"
+#include "op_arm_model.h"
+
+#define        PMU_ENABLE      0x001   /* Enable counters */
+#define PMN_RESET      0x002   /* Reset event counters */
+#define        CCNT_RESET      0x004   /* Reset clock counter */
+#define        PMU_RESET       (CCNT_RESET | PMN_RESET)
+#define PMU_CNT64      0x008   /* Make CCNT count every 64th cycle */
+
+/*
+ * Different types of events that can be counted by the XScale PMU
+ * as used by Oprofile userspace. Here primarily for documentation
+ * purposes.
+ */
+
+#define EVT_ICACHE_MISS                        0x00
+#define        EVT_ICACHE_NO_DELIVER           0x01
+#define        EVT_DATA_STALL                  0x02
+#define        EVT_ITLB_MISS                   0x03
+#define        EVT_DTLB_MISS                   0x04
+#define        EVT_BRANCH                      0x05
+#define        EVT_BRANCH_MISS                 0x06
+#define        EVT_INSTRUCTION                 0x07
+#define        EVT_DCACHE_FULL_STALL           0x08
+#define        EVT_DCACHE_FULL_STALL_CONTIG    0x09
+#define        EVT_DCACHE_ACCESS               0x0A
+#define        EVT_DCACHE_MISS                 0x0B
+#define        EVT_DCACE_WRITE_BACK            0x0C
+#define        EVT_PC_CHANGED                  0x0D
+#define        EVT_BCU_REQUEST                 0x10
+#define        EVT_BCU_FULL                    0x11
+#define        EVT_BCU_DRAIN                   0x12
+#define        EVT_BCU_ECC_NO_ELOG             0x14
+#define        EVT_BCU_1_BIT_ERR               0x15
+#define        EVT_RMW                         0x16
+/* EVT_CCNT is not hardware defined */
+#define EVT_CCNT                       0xFE
+#define EVT_UNUSED                     0xFF
+
+struct pmu_counter {
+       volatile unsigned long ovf;
+       unsigned long reset_counter;
+};
+
+enum { CCNT, PMN0, PMN1, PMN2, PMN3, MAX_COUNTERS };
+
+static struct pmu_counter results[MAX_COUNTERS];
+
+enum { PMU_ARM11 };
+
+struct pmu_type {
+       int id;
+       char *name;
+       int num_counters;
+       int interrupt;
+       unsigned int int_enable;
+       unsigned int cnt_ovf[MAX_COUNTERS];
+       unsigned int int_mask[MAX_COUNTERS];
+};
+
+static struct pmu_type pmu_parms[] = {
+       {
+               .id             = PMU_ARM11,
+               .name           = "arm/arm11",
+               .num_counters   = 3,
+#ifdef CONFIG_ARCH_OMAP2
+               .interrupt      = 3,
+#else
+               .interrupt      = -1,
+#endif
+               .int_mask       = { [PMN0] = 0x10, [PMN1] = 0x20,
+                                       [CCNT] = 0x40 },
+               .cnt_ovf        = { [CCNT] = 0x400, [PMN0] = 0x100,
+                                       [PMN1] = 0x200},
+       },
+};
+
+static struct pmu_type *pmu;
+
+static void write_pmnc(u32 val)
+{
+       __asm__ __volatile__ ("mcr p15, 0, %0, c15, c12, 0" : : "r" (val));
+}
+
+static u32 read_pmnc(void)
+{
+       u32 val;
+
+       __asm__ __volatile__ ("mrc p15, 0, %0, c15, c12, 0" : "=r" (val));
+
+       return val;
+}
+
+static u32 read_counter(int counter)
+{
+       u32 val = 0;
+
+       switch (counter) {
+       case CCNT:
+               __asm__ __volatile__ ("mrc p15, 0, %0, c15, c12, 1" : "=r" (val));
+               break;
+       case PMN0:
+               __asm__ __volatile__ ("mrc p15, 0, %0, c15, c12, 2" : "=r" (val));
+               break;
+       case PMN1:
+               __asm__ __volatile__ ("mrc p15, 0, %0, c15, c12, 3" : "=r" (val));
+               break;
+       }
+
+       return val;
+}
+
+static void write_counter(int counter, u32 val)
+{
+       switch (counter) {
+       case CCNT:
+               __asm__ __volatile__ ("mcr p15, 0, %0, c15, c12, 1" : : "r" (val));
+               break;
+       case PMN0:
+               __asm__ __volatile__ ("mcr p15, 0, %0, c15, c12, 2" : : "r" (val));
+               break;
+       case PMN1:
+               __asm__ __volatile__ ("mcr p15, 0, %0, c15, c12, 3" : : "r" (val));
+               break;
+       }
+}
+
+static int arm11_setup_ctrs(void)
+{
+       u32 pmnc;
+       int i;
+
+       for (i = CCNT; i < MAX_COUNTERS; i++) {
+               if (counter_config[i].enabled)
+                       continue;
+
+               counter_config[i].event = EVT_UNUSED;
+       }
+
+       pmnc = (counter_config[PMN1].event << 20)
+                       | (counter_config[PMN0].event << 12);
+       pr_debug("arm11_setup_ctrs: pmnc: %#08x\n", pmnc);
+       write_pmnc(pmnc);
+
+       for (i = CCNT; i < MAX_COUNTERS; i++) {
+               if (counter_config[i].event == EVT_UNUSED) {
+                       counter_config[i].event = 0;
+                       pmu->int_enable &= ~pmu->int_mask[i];
+                       continue;
+               }
+
+               results[i].reset_counter = counter_config[i].count;
+               write_counter(i, -(u32)counter_config[i].count);
+               pmu->int_enable |= pmu->int_mask[i];
+               pr_debug("arm11_setup_ctrs: counter%d %#08x from %#08lx\n", i,
+                       read_counter(i), counter_config[i].count);
+       }
+
+       return 0;
+}
+
+static void inline __arm11_check_ctrs(void)
+{
+       int i;
+       u32 pmnc = read_pmnc();
+
+       /* Write the value back to clear the overflow flags. Overflow */
+       /* flags remain in pmnc for use below */
+       write_pmnc(pmnc & ~PMU_ENABLE);
+
+       for (i = CCNT; i <= PMN1; i++) {
+               if (!(pmu->int_mask[i] & pmu->int_enable))
+                       continue;
+
+               if (pmnc & pmu->cnt_ovf[i])
+                       results[i].ovf++;
+       }
+}
+
+static irqreturn_t arm11_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
+{
+       int i;
+       u32 pmnc;
+
+       __arm11_check_ctrs();
+
+       for (i = CCNT; i < MAX_COUNTERS; i++) {
+               if (!results[i].ovf)
+                       continue;
+
+               write_counter(i, -(u32)results[i].reset_counter);
+               oprofile_add_sample(regs, i);
+               results[i].ovf--;
+       }
+
+       pmnc = read_pmnc() | PMU_ENABLE;
+       write_pmnc(pmnc);
+
+       return IRQ_HANDLED;
+}
+
+static void arm11_pmu_stop(void)
+{
+       u32 pmnc = read_pmnc();
+
+       pmnc &= ~PMU_ENABLE;
+       write_pmnc(pmnc);
+
+       if (pmu->interrupt >= 0)
+               free_irq(pmu->interrupt, results);
+}
+
+static int arm11_pmu_start(void)
+{
+       int ret;
+       u32 pmnc = read_pmnc();
+
+       if (pmu->interrupt >= 0) {
+               ret = request_irq(pmu->interrupt, arm11_pmu_interrupt,
+                       IRQF_DISABLED, "ARM11 PMU", (void *)results);
+               if (ret < 0) {
+                       printk(KERN_ERR "oprofile: unable to request IRQ%d "
+                               "for ARM11 PMU\n", pmu->interrupt);
+                       return ret;
+               }
+
+               pmnc |= pmu->int_enable;
+       }
+
+       pmnc |= PMU_ENABLE;
+       write_pmnc(pmnc);
+       pr_debug("arm11_pmu_start: pmnc: %#08x mask: %08x\n",
+                       pmnc, pmu->int_enable);
+       return 0;
+}
+
+static int arm11_detect_pmu(void)
+{
+       pmu = &pmu_parms[PMU_ARM11];
+
+       op_arm11_spec.name = pmu->name;
+       op_arm11_spec.num_counters = pmu->num_counters;
+       pr_debug("arm11_detect_pmu: detected %s PMU\n", pmu->name);
+
+       return 0;
+}
+
+struct op_arm_model_spec op_arm11_spec = {
+       .init           = arm11_detect_pmu,
+       .setup_ctrs     = arm11_setup_ctrs,
+       .start          = arm11_pmu_start,
+       .stop           = arm11_pmu_stop,
+};
index b917206ee9068036f6e17570162595a16afbdf38..3114d8271b55a305a1464d81a267e79c90923c0c 100644 (file)
@@ -41,6 +41,39 @@ config OMAP_RESET_CLOCKS
          probably do not want this option enabled until your
          device drivers work properly.
 
+config OMAP_BOOT_TAG
+       bool "OMAP bootloader information passing"
+        depends on ARCH_OMAP
+        default n
+        help
+          Say Y, if you have a bootloader which passes information
+          about your board and its peripheral configuration.
+
+config OMAP_BOOT_REASON
+       bool "Support for boot reason"
+        depends on OMAP_BOOT_TAG
+        default n
+        help
+          Say Y, if you want to have a procfs entry for reading the boot
+          reason in user-space.
+
+config OMAP_COMPONENT_VERSION
+       bool "Support for component version display"
+       depends on OMAP_BOOT_TAG && PROC_FS
+       default n
+       help
+         Say Y, if you want to have a procfs entry for reading component
+         versions (supplied by the bootloader) in user-space.
+
+config OMAP_GPIO_SWITCH
+       bool "GPIO switch support"
+        default n
+        help
+          Say Y, if you want to have support for reporting of GPIO
+          switches (e.g. cover switches) via sysfs. Your bootloader has
+          to provide information about the switches to the kernel via the
+          ATAG_BOARD mechanism if they're not defined by the board config.
+
 config OMAP_MUX
        bool "OMAP multiplexing support"
         depends on ARCH_OMAP
@@ -67,6 +100,17 @@ config OMAP_MUX_WARNINGS
          to change the pin multiplexing setup.  When there are no warnings
          printed, it's safe to deselect OMAP_MUX for your product.
 
+config OMAP_STI
+       bool "STI/XTI support"
+       depends on ARCH_OMAP16XX || ARCH_OMAP24XX
+       default n
+
+config OMAP_STI_CONSOLE
+       bool "STI console support"
+       depends on OMAP_STI
+       help
+         This enables a console driver by way of STI/XTI.
+
 config OMAP_MCBSP
        bool "McBSP support"
        depends on ARCH_OMAP
@@ -138,6 +182,8 @@ config OMAP_SERIAL_WAKE
          to data on the serial RX line. This allows you to wake the
          system from serial console.
 
+source "arch/arm/plat-omap/dsp/Kconfig"
+
 endmenu
 
 endif
index 17656b6688c4b7a3c69ca96f252e0d733446491e..112708729ef4c5fc8cf0967c42ccf383b5c6be1c 100644 (file)
@@ -23,6 +23,7 @@ obj-$(CONFIG_CPU_FREQ) += cpu-omap.o
 obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o
 obj-$(CONFIG_OMAP_BOOT_REASON) += bootreason.o
 obj-$(CONFIG_OMAP_COMPONENT_VERSION) += component-version.o
+obj-$(CONFIG_OMAP_GPIO_SWITCH) += gpio-switch.o
 obj-$(CONFIG_OMAP_DEBUG_DEVICES) += debug-devices.o
 obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o
 
diff --git a/arch/arm/plat-omap/bootreason.c b/arch/arm/plat-omap/bootreason.c
new file mode 100644 (file)
index 0000000..253dfcf
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * linux/arch/arm/plat-omap/bootreason.c
+ *
+ * OMAP Bootreason passing
+ *
+ * Copyright (c) 2004 Nokia
+ *
+ * Written by David Weinehall <david.weinehall@nokia.com>
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.
+ */
+#include <linux/proc_fs.h>
+#include <linux/errno.h>
+#include <asm/arch/board.h>
+
+static char boot_reason[16];
+
+static int omap_bootreason_read_proc(char *page, char **start, off_t off,
+                                        int count, int *eof, void *data)
+{
+       int len = 0;
+
+       len += sprintf(page + len, "%s\n", boot_reason);
+
+       *start = page + off;
+
+       if (len > off)
+               len -= off;
+       else
+               len = 0;
+
+       return len < count ? len  : count;
+}
+
+static int __init bootreason_init(void)
+{
+       const struct omap_boot_reason_config *cfg;
+       int reason_valid = 0;
+
+       cfg = omap_get_config(OMAP_TAG_BOOT_REASON, struct omap_boot_reason_config);
+       if (cfg != NULL) {
+               strncpy(boot_reason, cfg->reason_str, sizeof(cfg->reason_str));
+               boot_reason[sizeof(cfg->reason_str)] = 0;
+               reason_valid = 1;
+       } else {
+               /* Read the boot reason from the OMAP registers */
+       }
+
+       if (!reason_valid)
+               return -ENOENT;
+
+       printk(KERN_INFO "Bootup reason: %s\n", boot_reason);
+
+       if (!create_proc_read_entry("bootreason", S_IRUGO, NULL,
+                                       omap_bootreason_read_proc, NULL))
+               return -ENOMEM;
+
+       return 0;
+}
+
+late_initcall(bootreason_init);
index 3d017b04784bc76265a4e22841df6e8e7dc1f6b0..a463fa2f7d375667b463b2adf8fbbc14c95d8b67 100644 (file)
@@ -394,3 +394,65 @@ int __init clk_init(struct clk_functions * custom_clocks)
 
        return 0;
 }
+
+#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_PROC_FS)
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+static void *omap_ck_start(struct seq_file *m, loff_t *pos)
+{
+       return *pos < 1 ? (void *)1 : NULL;
+}
+
+static void *omap_ck_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       ++*pos;
+       return NULL;
+}
+
+static void omap_ck_stop(struct seq_file *m, void *v)
+{
+}
+
+int omap_ck_show(struct seq_file *m, void *v)
+{
+       struct clk *cp;
+
+       list_for_each_entry(cp, &clocks, node)
+               seq_printf(m,"%s %ld %d\n", cp->name, cp->rate, cp->usecount);
+
+       return 0;
+}
+
+static struct seq_operations omap_ck_op = {
+       .start =        omap_ck_start,
+       .next =         omap_ck_next,
+       .stop =         omap_ck_stop,
+       .show =         omap_ck_show
+};
+
+static int omap_ck_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &omap_ck_op);
+}
+
+static struct file_operations proc_omap_ck_operations = {
+       .open           = omap_ck_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+int __init omap_ck_init(void)
+{
+    struct proc_dir_entry *entry;
+
+       entry = create_proc_entry("omap_clocks", 0, NULL);
+       if (entry)
+               entry->proc_fops = &proc_omap_ck_operations;
+       return 0;
+
+}
+__initcall(omap_ck_init);
+#endif
+
index ffb94aa164ad5414d1c9d120eff959d02a459c19..2a72b9a4401937902ef14121c4fc1d92a666138f 100644 (file)
@@ -40,6 +40,26 @@ int omap_bootloader_tag_len;
 struct omap_board_config_kernel *omap_board_config;
 int omap_board_config_size;
 
+#ifdef CONFIG_OMAP_BOOT_TAG
+
+static int __init parse_tag_omap(const struct tag *tag)
+{
+       u32 size = tag->hdr.size - (sizeof(tag->hdr) >> 2);
+
+        size <<= 2;
+       if (size > sizeof(omap_bootloader_tag))
+               return -1;
+
+       memcpy(omap_bootloader_tag, tag->u.omap.data, size);
+       omap_bootloader_tag_len = size;
+
+        return 0;
+}
+
+__tagtable(ATAG_BOARD, parse_tag_omap);
+
+#endif
+
 static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out)
 {
        struct omap_board_config_kernel *kinfo = NULL;
@@ -160,3 +180,55 @@ static int __init omap_add_serial_console(void)
        return add_preferred_console("ttyS", line, opt);
 }
 console_initcall(omap_add_serial_console);
+
+
+/*
+ * 32KHz clocksource ... always available, on pretty most chips except
+ * OMAP 730 and 1510.  Other timers could be used as clocksources, with
+ * higher resolution in free-running counter modes (e.g. 12 MHz xtal),
+ * but systems won't necessarily want to spend resources that way.
+ */
+
+#if defined(CONFIG_ARCH_OMAP16XX)
+#define TIMER_32K_SYNCHRONIZED         0xfffbc410
+#elif defined(CONFIG_ARCH_OMAP2420)
+#define TIMER_32K_SYNCHRONIZED         0x48004010
+#elif defined(CONFIG_ARCH_OMAP2430)
+#define TIMER_32K_SYNCHRONIZED         0x49020010
+#endif
+
+#ifdef TIMER_32K_SYNCHRONIZED
+
+#include <linux/clocksource.h>
+
+static cycle_t omap_32k_read(void)
+{
+       return omap_readl(TIMER_32K_SYNCHRONIZED);
+}
+
+static struct clocksource clocksource_32k = {
+       .name           = "32k_counter",
+       .rating         = 250,
+       .read           = omap_32k_read,
+       .mask           = CLOCKSOURCE_MASK(32),
+       .shift          = 10,
+       .is_continuous  = 1,
+};
+
+static int __init omap_init_clocksource_32k(void)
+{
+       static char err[] __initdata = KERN_ERR
+                       "%s: can't register clocksource!\n";
+
+       if (cpu_is_omap16xx() || cpu_is_omap24xx()) {
+               clocksource_32k.mult = clocksource_hz2mult(32768,
+                                           clocksource_32k.shift);
+
+               if (clocksource_register(&clocksource_32k))
+                       printk(err, clocksource_32k.name);
+       }
+       return 0;
+}
+arch_initcall(omap_init_clocksource_32k);
+
+#endif /* TIMER_32K_SYNCHRONIZED */
diff --git a/arch/arm/plat-omap/component-version.c b/arch/arm/plat-omap/component-version.c
new file mode 100644 (file)
index 0000000..a9fe63d
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ *  linux/arch/arm/plat-omap/component-version.c
+ *
+ *  Copyright (C) 2005 Nokia Corporation
+ *  Written by Juha Yrjölä <juha.yrjola@nokia.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/init.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/proc_fs.h>
+#include <asm/arch/board.h>
+#include <asm/arch/board-nokia.h>
+
+static int component_version_read_proc(char *page, char **start, off_t off,
+                                      int count, int *eof, void *data)
+{
+       int len, i;
+       const struct omap_version_config *ver;
+       char *p;
+
+       i = 0;
+       p = page;
+       while ((ver = omap_get_nr_config(OMAP_TAG_VERSION_STR,
+                                        struct omap_version_config, i)) != NULL) {
+               p += sprintf(p, "%-12s%s\n", ver->component, ver->version);
+               i++;
+       }
+
+       len = (p - page) - off;
+       if (len < 0)
+               len = 0;
+
+       *eof = (len <= count) ? 1 : 0;
+       *start = page + off;
+
+       return len;
+}
+
+static int __init component_version_init(void)
+{
+       if (omap_get_config(OMAP_TAG_VERSION_STR, struct omap_version_config) == NULL)
+               return -ENODEV;
+       if (!create_proc_read_entry("component_version", S_IRUGO, NULL,
+                                   component_version_read_proc, NULL))
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void __exit component_version_exit(void)
+{
+       remove_proc_entry("component_version", NULL);
+}
+
+late_initcall(component_version_init);
+module_exit(component_version_exit);
+
+MODULE_AUTHOR("Juha Yrjölä <juha.yrjola@nokia.com>");
+MODULE_DESCRIPTION("Component version driver");
+MODULE_LICENSE("GPL");
index 2e0419fd976ff3c97d24daf5c9e18f016d96c92a..93bf7c767542ac324cc85d3e97633decf2672e03 100644 (file)
@@ -77,7 +77,7 @@ int dsp_kfunc_device_register(struct dsp_kfunc_device *kdev)
        mutex_init(&kdev->lock);
 
        mutex_lock(&dsp_pdata_lock);
-       list_add_tail(&kdev->entry, &dsp_pdata.kdev_list);
+       list_add_tail(&kdev->entry, &dsp_pdata.kdev_list);
        mutex_unlock(&dsp_pdata_lock);
 
        return 0;
diff --git a/arch/arm/plat-omap/dsp/dsp.h b/arch/arm/plat-omap/dsp/dsp.h
new file mode 100644 (file)
index 0000000..3535659
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "hardware_dsp.h"
+#include "dsp_common.h"
+
+/*
+ * MAJOR device number: !! allocated arbitrary !!
+ */
+#define OMAP_DSP_CTL_MAJOR             96
+#define OMAP_DSP_TASK_MAJOR            97
+
+#define OLD_BINARY_SUPPORT     y
+
+#ifdef OLD_BINARY_SUPPORT
+#define MBREV_3_0      0x0017
+#define MBREV_3_2      0x0018
+#endif
+
+#define DSP_INIT_PAGE  0xfff000
+
+#ifdef CONFIG_ARCH_OMAP1
+/* idle program will be placed at IDLEPG_BASE. */
+#define IDLEPG_BASE    0xfffe00
+#define IDLEPG_SIZE    0x100
+#endif /* CONFIG_ARCH_OMAP1 */
+
+/* timeout value for DSP response */
+#define DSP_TIMEOUT    (10 * HZ)
+
+enum dsp_mem_type_e {
+       MEM_TYPE_CROSSING = -1,
+       MEM_TYPE_NONE = 0,
+       MEM_TYPE_DARAM,
+       MEM_TYPE_SARAM,
+       MEM_TYPE_EXTERN,
+};
+
+
+typedef int __bitwise arm_dsp_dir_t;
+#define DIR_A2D        ((__force arm_dsp_dir_t) 1)
+#define DIR_D2A        ((__force arm_dsp_dir_t) 2)
+
+enum cfgstat_e {
+       CFGSTAT_CLEAN = 0,
+       CFGSTAT_READY,
+       CFGSTAT_SUSPEND,
+       CFGSTAT_RESUME, /* request only */
+       CFGSTAT_MAX
+};
+
+enum errcode_e {
+       ERRCODE_WDT = 0,
+       ERRCODE_MMU,
+       ERRCODE_MAX
+};
+
+/* keep 2 entries for TID_FREE and TID_ANON */
+#define TASKDEV_MAX    254
+
+#define MK32(uw,lw)    (((u32)(uw)) << 16 | (lw))
+#define MKLONG(uw,lw)  (((unsigned long)(uw)) << 16 | (lw))
+#define MKVIRT(uw,lw)  dspword_to_virt(MKLONG((uw), (lw)));
+
+struct sync_seq {
+       u16 da_dsp;
+       u16 da_arm;
+       u16 ad_dsp;
+       u16 ad_arm;
+};
+
+struct mem_sync_struct {
+       struct sync_seq *DARAM;
+       struct sync_seq *SARAM;
+       struct sync_seq *SDRAM;
+};
+
+/* struct mbcmd and union mbcmd_hw must be compatible */
+struct mbcmd {
+       u32 data:16;
+       u32 cmd_l:8;
+       u32 cmd_h:7;
+       u32 seq:1;
+};
+
+#define MBCMD_INIT(h, l, d) { \
+               .cmd_h = (h), \
+               .cmd_l = (l), \
+               .data  = (d), \
+       }
+
+struct mb_exarg {
+       u8 tid;
+       int argc;
+       u16 *argv;
+};
+
+extern void dsp_mbox_start(void);
+extern void dsp_mbox_stop(void);
+extern int dsp_mbox_config(void *p);
+extern int sync_with_dsp(u16 *syncwd, u16 tid, int try_cnt);
+extern int __dsp_mbcmd_send_exarg(struct mbcmd *mb, struct mb_exarg *arg,
+                                 int recovery_flag);
+#define dsp_mbcmd_send(mb)             __dsp_mbcmd_send_exarg((mb), NULL, 0)
+#define dsp_mbcmd_send_exarg(mb, arg)  __dsp_mbcmd_send_exarg((mb), (arg), 0)
+extern int dsp_mbcmd_send_and_wait_exarg(struct mbcmd *mb, struct mb_exarg *arg,
+                                        wait_queue_head_t *q);
+#define dsp_mbcmd_send_and_wait(mb, q) \
+       dsp_mbcmd_send_and_wait_exarg((mb), NULL, (q))
+
+static __inline__ int __mbcompose_send_exarg(u8 cmd_h, u8 cmd_l, u16 data,
+                                            struct mb_exarg *arg,
+                                            int recovery_flag)
+{
+       struct mbcmd mb = MBCMD_INIT(cmd_h, cmd_l, data);
+       return __dsp_mbcmd_send_exarg(&mb, arg, recovery_flag);
+}
+#define mbcompose_send(cmd_h, cmd_l, data) \
+       __mbcompose_send_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), NULL, 0)
+#define mbcompose_send_exarg(cmd_h, cmd_l, data, arg) \
+       __mbcompose_send_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), arg, 0)
+#define mbcompose_send_recovery(cmd_h, cmd_l, data) \
+       __mbcompose_send_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), NULL, 1)
+
+static __inline__ int __mbcompose_send_and_wait_exarg(u8 cmd_h, u8 cmd_l,
+                                                     u16 data,
+                                                     struct mb_exarg *arg,
+                                                     wait_queue_head_t *q)
+{
+       struct mbcmd mb = MBCMD_INIT(cmd_h, cmd_l, data);
+       return dsp_mbcmd_send_and_wait_exarg(&mb, arg, q);
+}
+#define mbcompose_send_and_wait(cmd_h, cmd_l, data, q) \
+       __mbcompose_send_and_wait_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), \
+                                       NULL, (q))
+#define mbcompose_send_and_wait_exarg(cmd_h, cmd_l, data, arg, q) \
+       __mbcompose_send_and_wait_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), \
+                                       (arg), (q))
+
+extern struct ipbuf_head *bid_to_ipbuf(u16 bid);
+extern void ipbuf_start(void);
+extern void ipbuf_stop(void);
+extern int ipbuf_config(u16 ln, u16 lsz, void *base);
+extern int ipbuf_sys_config(void *p, arm_dsp_dir_t dir);
+extern int ipbuf_p_validate(void *p, arm_dsp_dir_t dir);
+extern struct ipbuf_head *get_free_ipbuf(u8 tid);
+extern void release_ipbuf(struct ipbuf_head *ipb_h);
+extern void balance_ipbuf(void);
+extern void unuse_ipbuf(struct ipbuf_head *ipb_h);
+extern void unuse_ipbuf_nowait(struct ipbuf_head *ipb_h);
+
+#define release_ipbuf_pvt(ipbuf_pvt) \
+       do { \
+               (ipbuf_pvt)->s = TID_FREE; \
+       } while(0)
+
+extern int mbox_revision;
+
+extern int dsp_cfgstat_request(enum cfgstat_e st);
+extern enum cfgstat_e dsp_cfgstat_get_stat(void);
+extern int dsp_set_runlevel(u8 level);
+
+extern int dsp_task_config_all(u8 n);
+extern void dsp_task_unconfig_all(void);
+extern u8 dsp_task_count(void);
+extern int dsp_taskmod_busy(void);
+extern int dsp_mkdev(char *name);
+extern int dsp_rmdev(char *name);
+extern int dsp_tadd_minor(unsigned char minor, dsp_long_t adr);
+extern int dsp_tdel_minor(unsigned char minor);
+extern int dsp_tkill_minor(unsigned char minor);
+extern long taskdev_state_stale(unsigned char minor);
+extern int dsp_dbg_config(u16 *buf, u16 sz, u16 lsz);
+extern void dsp_dbg_stop(void);
+
+extern int ipbuf_is_held(u8 tid, u16 bid);
+
+extern int dsp_mem_sync_inc(void);
+extern int dsp_mem_sync_config(struct mem_sync_struct *sync);
+extern enum dsp_mem_type_e dsp_mem_type(void *vadr, size_t len);
+extern int dsp_address_validate(void *p, size_t len, char *fmt, ...);
+extern int dsp_mem_enable(void *adr);
+extern void dsp_mem_disable(void *adr);
+#ifdef CONFIG_ARCH_OMAP1
+extern void dsp_mem_usecount_clear(void);
+#endif
+extern void exmap_use(void *vadr, size_t len);
+extern void exmap_unuse(void *vadr, size_t len);
+extern unsigned long dsp_virt_to_phys(void *vadr, size_t *len);
+extern void dsp_mem_start(void);
+extern void dsp_mem_stop(void);
+
+extern void dsp_twch_start(void);
+extern void dsp_twch_stop(void);
+extern void dsp_twch_touch(void);
+
+extern void dsp_err_start(void);
+extern void dsp_err_stop(void);
+extern void dsp_err_set(enum errcode_e code, unsigned long arg);
+extern void dsp_err_clear(enum errcode_e code);
+extern int dsp_err_isset(enum errcode_e code);
+
+enum cmd_l_type_e {
+       CMD_L_TYPE_NULL,
+       CMD_L_TYPE_TID,
+       CMD_L_TYPE_SUBCMD,
+};
+
+struct cmdinfo {
+       char *name;
+       enum cmd_l_type_e cmd_l_type;
+       void (*handler)(struct mbcmd *mb);
+};
+
+extern const struct cmdinfo *cmdinfo[];
+
+#define cmd_name(mb)   (cmdinfo[(mb).cmd_h]->name)
+extern char *subcmd_name(struct mbcmd *mb);
+
+extern void mblog_add(struct mbcmd *mb, arm_dsp_dir_t dir);
index 7924bd003919bfdbe54d8868d13bbe368479a85f..b998509cd5783fee476ff603253444ca94d7fc21 100644 (file)
@@ -273,7 +273,7 @@ static int __init omap_dsp_init(void)
 
        dspmem_size = 0;
 #ifdef CONFIG_ARCH_OMAP15XX
-       if (cpu_is_omap1510()) {
+       if (cpu_is_omap15xx()) {
                dspmem_base = OMAP1510_DSP_BASE;
                dspmem_size = OMAP1510_DSP_SIZE;
                daram_base = OMAP1510_DARAM_BASE;
@@ -507,7 +507,7 @@ out:
 /*
  * release_mem will be delayed.
  */
-static void do_release_mem(struct work_struct *work)
+static void do_release_mem(struct work_struct *dummy)
 {
        mutex_lock(&cpustat.lock);
        cpustat.usecount.mem_delayed = 0;
diff --git a/arch/arm/plat-omap/dsp/dsp_core.c b/arch/arm/plat-omap/dsp/dsp_core.c
new file mode 100644 (file)
index 0000000..2da959b
--- /dev/null
@@ -0,0 +1,685 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <asm/delay.h>
+#include <asm/arch/mailbox.h>
+#include <asm/arch/dsp_common.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.h"
+#include "dsp_common.h"
+
+MODULE_AUTHOR("Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>");
+MODULE_DESCRIPTION("OMAP DSP driver module");
+MODULE_LICENSE("GPL");
+
+static struct sync_seq *mbseq;
+static u16 mbseq_expect_tmp;
+static u16 *mbseq_expect = &mbseq_expect_tmp;
+
+extern void dsp_mem_late_init(void);
+
+/*
+ * mailbox commands
+ */
+extern void mbox_wdsnd(struct mbcmd *mb);
+extern void mbox_wdreq(struct mbcmd *mb);
+extern void mbox_bksnd(struct mbcmd *mb);
+extern void mbox_bkreq(struct mbcmd *mb);
+extern void mbox_bkyld(struct mbcmd *mb);
+extern void mbox_bksndp(struct mbcmd *mb);
+extern void mbox_bkreqp(struct mbcmd *mb);
+extern void mbox_tctl(struct mbcmd *mb);
+extern void mbox_poll(struct mbcmd *mb);
+#ifdef OLD_BINARY_SUPPORT
+/* v3.3 obsolete */
+extern void mbox_wdt(struct mbcmd *mb);
+#endif
+extern void mbox_suspend(struct mbcmd *mb);
+static void mbox_kfunc(struct mbcmd *mb);
+extern void mbox_tcfg(struct mbcmd *mb);
+extern void mbox_tadd(struct mbcmd *mb);
+extern void mbox_tdel(struct mbcmd *mb);
+extern void mbox_dspcfg(struct mbcmd *mb);
+extern void mbox_regrw(struct mbcmd *mb);
+extern void mbox_getvar(struct mbcmd *mb);
+extern void mbox_err(struct mbcmd *mb);
+extern void mbox_dbg(struct mbcmd *mb);
+
+static const struct cmdinfo
+       cif_wdsnd    = { "WDSND",    CMD_L_TYPE_TID,    mbox_wdsnd   },
+       cif_wdreq    = { "WDREQ",    CMD_L_TYPE_TID,    mbox_wdreq   },
+       cif_bksnd    = { "BKSND",    CMD_L_TYPE_TID,    mbox_bksnd   },
+       cif_bkreq    = { "BKREQ",    CMD_L_TYPE_TID,    mbox_bkreq   },
+       cif_bkyld    = { "BKYLD",    CMD_L_TYPE_NULL,   mbox_bkyld   },
+       cif_bksndp   = { "BKSNDP",   CMD_L_TYPE_TID,    mbox_bksndp  },
+       cif_bkreqp   = { "BKREQP",   CMD_L_TYPE_TID,    mbox_bkreqp  },
+       cif_tctl     = { "TCTL",     CMD_L_TYPE_TID,    mbox_tctl    },
+       cif_poll     = { "POLL",     CMD_L_TYPE_NULL,   mbox_poll    },
+#ifdef OLD_BINARY_SUPPORT
+       /* v3.3 obsolete */
+       cif_wdt      = { "WDT",      CMD_L_TYPE_NULL,   mbox_wdt     },
+#endif
+       cif_runlevel = { "RUNLEVEL", CMD_L_TYPE_SUBCMD, NULL        },
+       cif_pm       = { "PM",       CMD_L_TYPE_SUBCMD, NULL        },
+       cif_suspend  = { "SUSPEND",  CMD_L_TYPE_NULL,   mbox_suspend },
+       cif_kfunc    = { "KFUNC",    CMD_L_TYPE_SUBCMD, mbox_kfunc   },
+       cif_tcfg     = { "TCFG",     CMD_L_TYPE_TID,    mbox_tcfg    },
+       cif_tadd     = { "TADD",     CMD_L_TYPE_TID,    mbox_tadd    },
+       cif_tdel     = { "TDEL",     CMD_L_TYPE_TID,    mbox_tdel    },
+       cif_tstop    = { "TSTOP",    CMD_L_TYPE_TID,    NULL        },
+       cif_dspcfg   = { "DSPCFG",   CMD_L_TYPE_SUBCMD, mbox_dspcfg  },
+       cif_regrw    = { "REGRW",    CMD_L_TYPE_SUBCMD, mbox_regrw   },
+       cif_getvar   = { "GETVAR",   CMD_L_TYPE_SUBCMD, mbox_getvar  },
+       cif_setvar   = { "SETVAR",   CMD_L_TYPE_SUBCMD, NULL        },
+       cif_err      = { "ERR",      CMD_L_TYPE_SUBCMD, mbox_err     },
+       cif_dbg      = { "DBG",      CMD_L_TYPE_NULL,   mbox_dbg     };
+
+#define MBOX_CMD_MAX   0x80
+const struct cmdinfo *cmdinfo[MBOX_CMD_MAX] = {
+       [MBOX_CMD_DSP_WDSND]    = &cif_wdsnd,
+       [MBOX_CMD_DSP_WDREQ]    = &cif_wdreq,
+       [MBOX_CMD_DSP_BKSND]    = &cif_bksnd,
+       [MBOX_CMD_DSP_BKREQ]    = &cif_bkreq,
+       [MBOX_CMD_DSP_BKYLD]    = &cif_bkyld,
+       [MBOX_CMD_DSP_BKSNDP]   = &cif_bksndp,
+       [MBOX_CMD_DSP_BKREQP]   = &cif_bkreqp,
+       [MBOX_CMD_DSP_TCTL]     = &cif_tctl,
+       [MBOX_CMD_DSP_POLL]     = &cif_poll,
+#ifdef OLD_BINARY_SUPPORT
+       [MBOX_CMD_DSP_WDT]      = &cif_wdt, /* v3.3 obsolete */
+#endif
+       [MBOX_CMD_DSP_RUNLEVEL] = &cif_runlevel,
+       [MBOX_CMD_DSP_PM]       = &cif_pm,
+       [MBOX_CMD_DSP_SUSPEND]  = &cif_suspend,
+       [MBOX_CMD_DSP_KFUNC]    = &cif_kfunc,
+       [MBOX_CMD_DSP_TCFG]     = &cif_tcfg,
+       [MBOX_CMD_DSP_TADD]     = &cif_tadd,
+       [MBOX_CMD_DSP_TDEL]     = &cif_tdel,
+       [MBOX_CMD_DSP_TSTOP]    = &cif_tstop,
+       [MBOX_CMD_DSP_DSPCFG]   = &cif_dspcfg,
+       [MBOX_CMD_DSP_REGRW]    = &cif_regrw,
+       [MBOX_CMD_DSP_GETVAR]   = &cif_getvar,
+       [MBOX_CMD_DSP_SETVAR]   = &cif_setvar,
+       [MBOX_CMD_DSP_ERR]      = &cif_err,
+       [MBOX_CMD_DSP_DBG]      = &cif_dbg,
+};
+
+static int dsp_kfunc_probe_devices(struct omap_dsp *dsp)
+{
+       struct dsp_kfunc_device *p;
+       int ret, fail = 0;
+
+       mutex_lock(&dsp->lock);
+       list_for_each_entry(p, dsp->kdev_list, entry) {
+               if (p->probe == NULL)
+                       continue;
+               ret = p->probe(p);
+               if (ret) {
+                       printk(KERN_ERR
+                              "probing %s failed\n", p->name);
+                       fail++;
+               }
+       }
+       mutex_unlock(&dsp->lock);
+
+       pr_debug("%s() fail:%d\n", __FUNCTION__, fail);
+
+       return fail;
+}
+
+static int dsp_kfunc_remove_devices(struct omap_dsp *dsp)
+{
+       struct dsp_kfunc_device *p;
+       int ret, fail = 0;
+
+       mutex_lock(&dsp->lock);
+       list_for_each_entry_reverse(p, dsp->kdev_list, entry) {
+               if (p->remove == NULL)
+                       continue;
+               ret = p->remove(p);
+               if (ret) {
+                       printk(KERN_ERR
+                              "removing %s failed\n", p->name);
+                       fail++;
+               }
+       }
+       mutex_unlock(&dsp->lock);
+
+       pr_debug("%s() fail:%d\n", __FUNCTION__, fail);
+
+       return fail;
+}
+
+static int dsp_kfunc_enable_devices(struct omap_dsp *dsp, int type, int stage)
+{
+       struct dsp_kfunc_device *p;
+       int ret, fail = 0;
+
+       mutex_lock(&dsp->lock);
+       list_for_each_entry(p, dsp->kdev_list, entry) {
+               if ((p->type != type) || (p->enable == NULL))
+                       continue;
+               ret = p->enable(p, stage);
+               if (ret) {
+                       printk(KERN_ERR
+                              "enabling %s failed\n", p->name);
+                       fail++;
+               }
+       }
+       mutex_unlock(&dsp->lock);
+
+       pr_debug("%s(%d) fail:%d\n", __FUNCTION__, type, fail);
+
+       return fail;
+}
+
+static int dsp_kfunc_disable_devices(struct omap_dsp *dsp, int type, int stage)
+{
+       struct dsp_kfunc_device *p;
+       int ret, fail = 0;
+
+       mutex_lock(&dsp->lock);
+       list_for_each_entry_reverse(p, omap_dsp->kdev_list, entry) {
+               if ((p->type != type) || (p->disable == NULL))
+                       continue;
+               ret = p->disable(p, stage);
+               if (ret) {
+                       printk(KERN_ERR
+                              "disabling %s failed\n", p->name);
+                       fail++;
+               }
+       }
+       mutex_unlock(&dsp->lock);
+
+       pr_debug("%s(%d) fail:%d\n", __FUNCTION__, type, fail);
+
+       return fail;
+}
+
+int sync_with_dsp(u16 *adr, u16 val, int try_cnt)
+{
+       int try;
+
+       if (*(volatile u16 *)adr == val)
+               return 0;
+
+       for (try = 0; try < try_cnt; try++) {
+               udelay(1);
+               if (*(volatile u16 *)adr == val) {
+                       /* success! */
+                       pr_info("omapdsp: sync_with_dsp(): try = %d\n", try);
+                       return 0;
+               }
+       }
+
+       /* fail! */
+       return -1;
+}
+
+static int mbcmd_sender_prepare(void *data)
+{
+       struct mb_exarg *arg = data;
+       int i, ret = 0;
+       /*
+        * even if ipbuf_sys_ad is in DSP internal memory,
+        * dsp_mem_enable() never cause to call PM mailbox command
+        * because in that case DSP memory should be always enabled.
+        * (see ipbuf_sys_hold_mem_active in ipbuf.c)
+        *
+        * Therefore, we can call this function here safely.
+        */
+       if (sync_with_dsp(&ipbuf_sys_ad->s, TID_FREE, 10) < 0) {
+               printk(KERN_ERR "omapdsp: ipbuf_sys_ad is busy.\n");
+               ret = -EBUSY;
+               goto out;
+       }
+
+       for (i = 0; i < arg->argc; i++) {
+               ipbuf_sys_ad->d[i] = arg->argv[i];
+       }
+       ipbuf_sys_ad->s = arg->tid;
+ out:
+       return ret;
+}
+
+/*
+ * __dsp_mbcmd_send_exarg(): mailbox dispatcher
+ */
+int __dsp_mbcmd_send_exarg(struct mbcmd *mb, struct mb_exarg *arg,
+                          int recovery_flag)
+{
+       int ret = 0;
+
+       if (unlikely(omap_dsp->enabled == 0)) {
+               ret = dsp_kfunc_enable_devices(omap_dsp,
+                                              DSP_KFUNC_DEV_TYPE_COMMON, 0);
+               if (ret == 0)
+                       omap_dsp->enabled = 1;
+       }
+
+       /*
+        * while MMU fault is set,
+        * only recovery command can be executed
+        */
+       if (dsp_err_isset(ERRCODE_MMU) && !recovery_flag) {
+               printk(KERN_ERR
+                      "mbox: mmu interrupt is set. %s is aborting.\n",
+                      cmd_name(*mb));
+               goto out;
+       }
+
+       if (arg)
+               dsp_mem_enable(ipbuf_sys_ad);
+
+       ret = omap_mbox_msg_send(omap_dsp->mbox,
+                                *(mbox_msg_t *)mb, (void*)arg);
+       if (ret)
+               goto out;
+
+       if (mbseq)
+               mbseq->ad_arm++;
+
+       mblog_add(mb, DIR_A2D);
+ out:
+       if (arg)
+               dsp_mem_disable(ipbuf_sys_ad);
+
+       return ret;
+}
+
+int dsp_mbcmd_send_and_wait_exarg(struct mbcmd *mb, struct mb_exarg *arg,
+                                 wait_queue_head_t *q)
+{
+       long current_state;
+       DECLARE_WAITQUEUE(wait, current);
+
+       add_wait_queue(q, &wait);
+       current_state = current->state;
+       set_current_state(TASK_INTERRUPTIBLE);
+       if (dsp_mbcmd_send_exarg(mb, arg) < 0) {
+               set_current_state(current_state);
+               remove_wait_queue(q, &wait);
+               return -1;
+       }
+       schedule_timeout(DSP_TIMEOUT);
+       set_current_state(current_state);
+       remove_wait_queue(q, &wait);
+
+       return 0;
+}
+
+/*
+ * mbcmd receiver
+ */
+static void mbcmd_receiver(mbox_msg_t msg)
+{
+       struct mbcmd *mb = (struct mbcmd *)&msg;
+
+       if (cmdinfo[mb->cmd_h] == NULL) {
+               printk(KERN_ERR
+                      "invalid message (%08x) for mbcmd_receiver().\n", msg);
+               return;
+       }
+
+       (*mbseq_expect)++;
+
+       mblog_add(mb, DIR_D2A);
+
+       /* call handler for the command */
+       if (cmdinfo[mb->cmd_h]->handler)
+               cmdinfo[mb->cmd_h]->handler(mb);
+       else
+               printk(KERN_ERR "mbox: %s is not allowed from DSP.\n",
+                      cmd_name(*mb));
+}
+
+static int mbsync_hold_mem_active;
+
+void dsp_mbox_start(void)
+{
+       omap_mbox_init_seq(omap_dsp->mbox);
+       mbseq_expect_tmp = 0;
+}
+
+void dsp_mbox_stop(void)
+{
+       mbseq = NULL;
+       mbseq_expect = &mbseq_expect_tmp;
+}
+
+int dsp_mbox_config(void *p)
+{
+       unsigned long flags;
+
+       if (dsp_address_validate(p, sizeof(struct sync_seq), "mbseq") < 0)
+               return -1;
+       if (dsp_mem_type(p, sizeof(struct sync_seq)) != MEM_TYPE_EXTERN) {
+               printk(KERN_WARNING
+                      "omapdsp: mbseq is placed in DSP internal memory.\n"
+                      "         It will prevent DSP from idling.\n");
+               mbsync_hold_mem_active = 1;
+               /*
+                * dsp_mem_enable() never fails because
+                * it has been already enabled in dspcfg process and
+                * this will just increment the usecount.
+                */
+               dsp_mem_enable((void *)daram_base);
+       }
+
+       local_irq_save(flags);
+       mbseq = p;
+       mbseq->da_arm = mbseq_expect_tmp;
+       mbseq_expect = &mbseq->da_arm;
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+static int __init dsp_mbox_init(void)
+{
+       omap_dsp->mbox = omap_mbox_get("dsp");
+       if (omap_dsp->mbox == NULL) {
+               printk(KERN_ERR "failed to get mailbox handler for DSP.\n");
+               return -ENODEV;
+       }
+
+       omap_dsp->mbox->msg_receive_cb = mbcmd_receiver;
+       omap_dsp->mbox->msg_sender_cb = mbcmd_sender_prepare;
+
+       return 0;
+}
+
+static void dsp_mbox_exit(void)
+{
+       omap_dsp->mbox->msg_sender_cb = NULL;
+       omap_dsp->mbox->msg_receive_cb = NULL;
+
+       if (mbsync_hold_mem_active) {
+               dsp_mem_disable((void *)daram_base);
+               mbsync_hold_mem_active = 0;
+       }
+}
+
+/*
+ * kernel function dispatcher
+ */
+extern void mbox_fbctl_upd(void);
+extern void mbox_fbctl_disable(struct mbcmd *mb);
+
+static void mbox_kfunc_fbctl(struct mbcmd *mb)
+{
+       switch (mb->data) {
+       case FBCTL_UPD:
+               mbox_fbctl_upd();
+               break;
+       case FBCTL_DISABLE:
+               mbox_fbctl_disable(mb);
+               break;
+       default:
+               printk(KERN_ERR
+                      "mbox: Unknown FBCTL from DSP: 0x%04x\n", mb->data);
+       }
+}
+
+/*
+ * dspgw: KFUNC message handler
+ */
+static void mbox_kfunc_power(unsigned short data)
+{
+       int ret = -1;
+
+       switch (data) {
+       case DVFS_START: /* ACK from DSP */
+               /* TBD */
+               break;
+       case AUDIO_PWR_UP:
+               ret = dsp_kfunc_enable_devices(omap_dsp,
+                                              DSP_KFUNC_DEV_TYPE_AUDIO, 0);
+               if (ret == 0)
+                       ret++;
+               break;
+       case AUDIO_PWR_DOWN: /* == AUDIO_PWR_DOWN1 */
+               ret = dsp_kfunc_disable_devices(omap_dsp,
+                                               DSP_KFUNC_DEV_TYPE_AUDIO, 1);
+               break;
+       case AUDIO_PWR_DOWN2:
+               ret = dsp_kfunc_disable_devices(omap_dsp,
+                                               DSP_KFUNC_DEV_TYPE_AUDIO, 2);
+               break;
+       case DSP_PWR_DOWN:
+               ret = dsp_kfunc_disable_devices(omap_dsp,
+                                               DSP_KFUNC_DEV_TYPE_COMMON, 0);
+               if (ret == 0)
+                       omap_dsp->enabled = 0;
+               break;
+       default:
+               printk(KERN_ERR
+                      "mailbox: Unknown PWR from DSP: 0x%04x\n", data);
+               break;
+       }
+
+       if (unlikely(ret < 0)) {
+               printk(KERN_ERR "mailbox: PWR(0x%04x) failed\n", data);
+               return;
+       }
+
+       if (likely(ret == 0))
+               return;
+
+       mbcompose_send(KFUNC, KFUNC_POWER, data);
+}
+
+static void mbox_kfunc(struct mbcmd *mb)
+{
+       switch (mb->cmd_l) {
+       case KFUNC_FBCTL:
+               mbox_kfunc_fbctl(mb);
+               break;
+       case KFUNC_POWER:
+               mbox_kfunc_power(mb->data);
+               break;
+       default:
+               printk(KERN_ERR
+                      "mbox: Unknown KFUNC from DSP: 0x%02x\n", mb->cmd_l);
+       }
+}
+
+int dsp_late_init(void)
+{
+       int ret;
+
+       dsp_clk_autoidle();
+
+#ifdef CONFIG_ARCH_OMAP2
+       clk_enable(dsp_fck_handle);
+       clk_enable(dsp_ick_handle);
+       __dsp_per_enable();
+#endif
+       dsp_mem_late_init();
+
+#ifdef CONFIG_ARCH_OMAP1
+       dsp_set_idle_boot_base(IDLEPG_BASE, IDLEPG_SIZE);
+#endif
+       ret = dsp_kfunc_enable_devices(omap_dsp,
+                                      DSP_KFUNC_DEV_TYPE_COMMON, 0);
+       if (ret == 0)
+               omap_dsp->enabled = 0;
+
+       return 0;
+}
+
+extern int  dsp_ctl_core_init(void);
+extern void dsp_ctl_core_exit(void);
+extern void dsp_ctl_init(void);
+extern void dsp_ctl_exit(void);
+extern int  dsp_mem_init(void);
+extern void dsp_mem_exit(void);
+extern void mblog_init(void);
+extern void mblog_exit(void);
+extern int  dsp_taskmod_init(void);
+extern void dsp_taskmod_exit(void);
+
+/*
+ * driver functions
+ */
+static int __init dsp_drv_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct omap_dsp *info;
+       struct dsp_platform_data *pdata = pdev->dev.platform_data;
+
+       dev_info(&pdev->dev, "OMAP DSP driver initialization\n");
+
+       info = kzalloc(sizeof(struct omap_dsp), GFP_KERNEL);
+       if (unlikely(info == NULL)) {
+               dev_dbg(&pdev->dev, "no memory for info\n");
+               return -ENOMEM;
+       }
+       platform_set_drvdata(pdev, info);
+       omap_dsp = info;
+
+       mutex_init(&info->lock);
+       info->dev = &pdev->dev;
+       info->kdev_list = &pdata->kdev_list;
+
+       ret = dsp_kfunc_probe_devices(info);
+       if (ret) {
+               ret = -ENXIO;
+               goto fail0;
+       }
+
+       info->mmu_irq = platform_get_irq_byname(pdev, "dsp_mmu");
+       if (unlikely(info->mmu_irq) < 0) {
+               ret = -ENXIO;
+               goto fail1;
+       }
+
+       if ((ret = dsp_ctl_core_init()) < 0)
+               goto fail2;
+       if ((ret = dsp_mem_init()) < 0)
+               goto fail3;
+       dsp_ctl_init();
+       mblog_init();
+       if ((ret = dsp_taskmod_init()) < 0)
+               goto fail4;
+       if ((ret = dsp_mbox_init()) < 0)
+               goto fail5;
+
+       return 0;
+
+ fail5:
+       dsp_taskmod_exit();
+ fail4:
+       mblog_exit();
+       dsp_ctl_exit();
+       dsp_mem_exit();
+ fail3:
+       dsp_ctl_core_exit();
+ fail2:
+ fail1:
+       dsp_kfunc_remove_devices(info);
+ fail0:
+       kfree(info);
+
+       return ret;
+}
+
+static int dsp_drv_remove(struct platform_device *pdev)
+{
+       struct omap_dsp *info = platform_get_drvdata(pdev);
+
+       dsp_cpustat_request(CPUSTAT_RESET);
+
+       dsp_cfgstat_request(CFGSTAT_CLEAN);
+       dsp_mbox_exit();
+       dsp_taskmod_exit();
+       mblog_exit();
+       dsp_ctl_exit();
+       dsp_mem_exit();
+
+       dsp_ctl_core_exit();
+
+#ifdef CONFIG_ARCH_OMAP2
+       __dsp_per_disable();
+       clk_disable(dsp_ick_handle);
+       clk_disable(dsp_fck_handle);
+#endif
+       dsp_kfunc_remove_devices(info);
+       kfree(info);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int dsp_drv_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       dsp_cfgstat_request(CFGSTAT_SUSPEND);
+
+       return 0;
+}
+
+static int dsp_drv_resume(struct platform_device *pdev)
+{
+       dsp_cfgstat_request(CFGSTAT_RESUME);
+
+       return 0;
+}
+#else
+#define dsp_drv_suspend                NULL
+#define dsp_drv_resume         NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver dsp_driver = {
+       .probe          = dsp_drv_probe,
+       .remove         = dsp_drv_remove,
+       .suspend        = dsp_drv_suspend,
+       .resume         = dsp_drv_resume,
+       .driver         = {
+               .name   = "dsp",
+       },
+};
+
+static int __init omap_dsp_mod_init(void)
+{
+       return platform_driver_register(&dsp_driver);
+}
+
+static void __exit omap_dsp_mod_exit(void)
+{
+       platform_driver_unregister(&dsp_driver);
+}
+
+/* module dependency: need mailbox module that have mbox_dsp_info */
+extern struct omap_mbox mbox_dsp_info;
+struct omap_mbox *mbox_dep = &mbox_dsp_info;
+
+module_init(omap_dsp_mod_init);
+module_exit(omap_dsp_mod_exit);
diff --git a/arch/arm/plat-omap/dsp/dsp_ctl.c b/arch/arm/plat-omap/dsp/dsp_ctl.c
new file mode 100644 (file)
index 0000000..91be986
--- /dev/null
@@ -0,0 +1,1057 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/ioctls.h>
+#include <asm/arch/mailbox.h>
+#include "hardware_dsp.h"
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.h"
+#include "ioctl.h"
+
+enum dsp_space_e {
+       SPACE_MEM,
+       SPACE_IO,
+};
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+static enum fbstat_e {
+       FBSTAT_DISABLED = 0,
+       FBSTAT_ENABLED,
+       FBSTAT_MAX,
+} fbstat = FBSTAT_ENABLED;
+#endif
+
+static enum cfgstat_e cfgstat;
+int mbox_revision;
+static u8 n_stask;
+
+static ssize_t ifver_show(struct device *dev, struct device_attribute *attr,
+                         char *buf);
+static ssize_t cpustat_show(struct device *dev, struct device_attribute *attr,
+                           char *buf);
+static ssize_t icrmask_show(struct device *dev, struct device_attribute *attr,
+                           char *buf);
+static ssize_t icrmask_store(struct device *dev, struct device_attribute *attr,
+                            const char *buf, size_t count);
+static ssize_t loadinfo_show(struct device *dev, struct device_attribute *attr,
+                            char *buf);
+
+#define __ATTR_RW(_name, _mode) { \
+       .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE },     \
+       .show   = _name##_show,                                 \
+       .store  = _name##_store,                                        \
+}
+
+static struct device_attribute dev_attr_ifver     = __ATTR_RO(ifver);
+static struct device_attribute dev_attr_cpustat   = __ATTR_RO(cpustat);
+static struct device_attribute dev_attr_icrmask   = __ATTR_RW(icrmask, 0644);
+static struct device_attribute dev_attr_loadinfo  = __ATTR_RO(loadinfo);
+
+/*
+ * misc interactive mailbox command operations
+ */
+static struct misc_mb_wait_struct {
+       struct mutex lock;
+       wait_queue_head_t wait_q;
+       u8 cmd_h;
+       u8 cmd_l;
+       u16 *retvp;
+} misc_mb_wait = {
+       .lock = __MUTEX_INITIALIZER(misc_mb_wait.lock),
+       .wait_q = __WAIT_QUEUE_HEAD_INITIALIZER(misc_mb_wait.wait_q),
+};
+
+static int __misc_mbcompose_send_and_wait(u8 cmd_h, u8 cmd_l, u16 data,
+                                         u16 *retvp)
+{
+       struct mbcmd mb = MBCMD_INIT(cmd_h, cmd_l, data);
+       int ret = 0;
+
+       if (mutex_lock_interruptible(&misc_mb_wait.lock))
+               return -EINTR;
+
+       misc_mb_wait.cmd_h = mb.cmd_h;
+       misc_mb_wait.cmd_l = mb.cmd_l;
+       misc_mb_wait.retvp = retvp;
+       dsp_mbcmd_send_and_wait(&mb, &misc_mb_wait.wait_q);
+
+       if (misc_mb_wait.cmd_h != 0)
+               ret = -EINVAL;
+
+       mutex_unlock(&misc_mb_wait.lock);
+       return ret;
+}
+
+#define misc_mbcompose_send_and_wait(cmd_h, cmd_l, data, retvp) \
+               __misc_mbcompose_send_and_wait(MBOX_CMD_DSP_##cmd_h, (cmd_l), \
+                                              (data), (retvp));
+
+static int misc_mbcmd_response(struct mbcmd *mb, int argc, int match_cmd_l_flag)
+{
+       volatile u16 *buf;
+       int i;
+
+       /* if match_cmd_l_v flag is set, cmd_l needs to be matched as well. */
+       if (!waitqueue_active(&misc_mb_wait.wait_q) ||
+           (misc_mb_wait.cmd_h != mb->cmd_h) ||
+           (match_cmd_l_flag && (misc_mb_wait.cmd_l != mb->cmd_l))) {
+               const struct cmdinfo *ci = cmdinfo[mb->cmd_h];
+               char cmdstr[32];
+
+               if (ci->cmd_l_type == CMD_L_TYPE_SUBCMD)
+                       sprintf(cmdstr, "%s:%s", ci->name, subcmd_name(mb));
+               else
+                       strcpy(cmdstr, ci->name);
+               printk(KERN_WARNING
+                      "mbox: unexpected command %s received!\n", cmdstr);
+               return -1;
+       }
+
+       /*
+        * if argc == 1, receive data through mbox:data register.
+        * if argc > 1, receive through ipbuf_sys.
+        */
+       if (argc == 1)
+               misc_mb_wait.retvp[0] = mb->data;
+       else if (argc > 1) {
+               if (dsp_mem_enable(ipbuf_sys_da) < 0) {
+                       printk(KERN_ERR "mbox: %s - ipbuf_sys_da read failed!\n",
+                              cmdinfo[mb->cmd_h]->name);
+                       return -1;
+               }
+               if (sync_with_dsp(&ipbuf_sys_da->s, TID_ANON, 10) < 0) {
+                       printk(KERN_ERR "mbox: %s - IPBUF sync failed!\n",
+                              cmdinfo[mb->cmd_h]->name);
+                       dsp_mem_disable(ipbuf_sys_da);
+                       return -1;
+               }
+               /* need word access. do not use memcpy. */
+               buf = ipbuf_sys_da->d;
+               for (i = 0; i < argc; i++)
+                       misc_mb_wait.retvp[i] = buf[i];
+               release_ipbuf_pvt(ipbuf_sys_da);
+               dsp_mem_disable(ipbuf_sys_da);
+       }
+
+       misc_mb_wait.cmd_h = 0;
+       wake_up_interruptible(&misc_mb_wait.wait_q);
+       return 0;
+}
+
+static int dsp_regread(enum dsp_space_e space, u16 adr, u16 *val)
+{
+       u8 cmd_l = (space == SPACE_MEM) ? REGRW_MEMR : REGRW_IOR;
+       int ret;
+
+       ret = misc_mbcompose_send_and_wait(REGRW, cmd_l, adr, val);
+       if ((ret < 0) && (ret != -EINTR))
+               printk(KERN_ERR "omapdsp: register read error!\n");
+
+       return ret;
+}
+
+static int dsp_regwrite(enum dsp_space_e space, u16 adr, u16 val)
+{
+       u8 cmd_l = (space == SPACE_MEM) ? REGRW_MEMW : REGRW_IOW;
+       struct mb_exarg arg = {
+               .tid  = TID_ANON,
+               .argc = 1,
+               .argv = &val,
+       };
+
+       mbcompose_send_exarg(REGRW, cmd_l, adr, &arg);
+       return 0;
+}
+
+static int dsp_getvar(u8 varid, u16 *val)
+{
+       int ret;
+
+       ret = misc_mbcompose_send_and_wait(GETVAR, varid, 0, val);
+       if ((ret < 0) && (ret != -EINTR))
+               printk(KERN_ERR "omapdsp: variable read error!\n");
+
+       return ret;
+}
+
+static int dsp_setvar(u8 varid, u16 val)
+{
+       mbcompose_send(SETVAR, varid, val);
+       return 0;
+}
+
+/*
+ * dsp_cfg() return value
+ *  = 0: OK
+ *  = 1: failed, but state is clear. (DSPCFG command failed)
+ *  < 0: failed. need cleanup.
+ */
+static int dsp_cfg(void)
+{
+       int ret = 0;
+
+#ifdef CONFIG_ARCH_OMAP1
+       /* for safety */
+       dsp_mem_usecount_clear();
+#endif
+
+       /*
+        * DSPCFG command and dsp_mem_start() must be called
+        * while internal mem is on.
+        */
+       dsp_mem_enable((void *)dspmem_base);
+
+       dsp_mbox_start();
+       dsp_twch_start();
+       dsp_mem_start();
+       dsp_err_start();
+
+       mbox_revision = -1;
+
+       ret = misc_mbcompose_send_and_wait(DSPCFG, DSPCFG_REQ, 0, NULL);
+       if (ret < 0) {
+               if (ret != -EINTR)
+                       printk(KERN_ERR "omapdsp: configuration error!\n");
+               ret = 1;
+               goto out;
+       }
+
+#if defined(CONFIG_ARCH_OMAP1) && defined(OLD_BINARY_SUPPORT)
+       /*
+        * MBREV 3.2 or earlier doesn't assume DMA domain is on
+        * when DSPCFG command is sent
+        */
+       if ((mbox_revision == MBREV_3_0) ||
+           (mbox_revision == MBREV_3_2)) {
+               if ((ret = mbcompose_send(PM, PM_ENABLE, DSPREG_ICR_DMA)) < 0)
+                       goto out;
+       }
+#endif
+
+       if ((ret = dsp_task_config_all(n_stask)) < 0)
+               goto out;
+
+       /* initialization */
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+       fbstat = FBSTAT_ENABLED;
+#endif
+
+       /* send parameter */
+       if ((ret = dsp_setvar(VARID_ICRMASK, dsp_cpustat_get_icrmask())) < 0)
+               goto out;
+
+       /* create runtime sysfs entries */
+       ret = device_create_file(omap_dsp->dev, &dev_attr_loadinfo);
+       if (ret)
+               printk(KERN_ERR "device_create_file failed: %d\n", ret);
+
+out:
+       dsp_mem_disable((void *)dspmem_base);
+       return ret;
+}
+
+static int dsp_uncfg(void)
+{
+       if (dsp_taskmod_busy()) {
+               printk(KERN_WARNING "omapdsp: tasks are busy.\n");
+               return -EBUSY;
+       }
+
+       /* FIXME: lock task module */
+
+       /* remove runtime sysfs entries */
+       device_remove_file(omap_dsp->dev, &dev_attr_loadinfo);
+
+       dsp_mbox_stop();
+       dsp_twch_stop();
+       dsp_mem_stop();
+       dsp_err_stop();
+       dsp_dbg_stop();
+       dsp_task_unconfig_all();
+       ipbuf_stop();
+
+       return 0;
+}
+
+static int dsp_suspend(void)
+{
+       int ret;
+
+       ret = misc_mbcompose_send_and_wait(SUSPEND, 0, 0, NULL);
+       if (ret < 0) {
+               if (ret != -EINVAL)
+                       printk(KERN_ERR "omapdsp: DSP suspend error!\n");
+               return ret;
+       }
+
+       udelay(100);    /* wait for DSP-side execution */
+       return 0;
+}
+
+int dsp_cfgstat_request(enum cfgstat_e st_req)
+{
+       static DEFINE_MUTEX(cfgstat_lock);
+       int ret = 0, ret_override = 0;
+
+       if (mutex_lock_interruptible(&cfgstat_lock))
+               return -EINTR;
+
+again:
+       switch (st_req) {
+
+       /* cfgstat takes CLEAN, READY or SUSPEND,
+          while st_req can take SUSPEND in addition. */
+
+       case CFGSTAT_CLEAN:
+               if (cfgstat == CFGSTAT_CLEAN)
+                       goto up_out;
+               if ((ret = dsp_uncfg()) < 0)
+                       goto up_out;
+               break;
+
+       case CFGSTAT_READY:
+               if (cfgstat != CFGSTAT_CLEAN) {
+                       printk(KERN_ERR "omapdsp: DSP is ready already!\n");
+                       ret = -EINVAL;
+                       goto up_out;
+               }
+
+               ret = dsp_cfg();
+               if (ret > 0) {  /* failed, but state is clear. */
+                       ret = -EINVAL;
+                       goto up_out;
+               } else if (ret < 0) {   /* failed, need cleanup. */
+                       st_req = CFGSTAT_CLEAN;
+                       ret_override = ret;
+                       goto again;
+               }
+               break;
+
+       /*
+        * suspend / resume
+        * DSP is not reset within this code, but done in omap_pm_suspend.
+        * so if these functions are called from sysfs,
+        * DSP should be reset / unreset out of these functions.
+        */
+       case CFGSTAT_SUSPEND:
+               switch (cfgstat) {
+
+               case CFGSTAT_CLEAN:
+                       if (dsp_cpustat_get_stat() == CPUSTAT_RUN) {
+                               printk(KERN_WARNING
+                                      "omapdsp: illegal operation -- trying "
+                                      "suspend DSP while it is running but "
+                                      "not configured.\n"
+                                      "  Resetting DSP.\n");
+                               dsp_cpustat_request(CPUSTAT_RESET);
+                               ret = -EINVAL;
+                       }
+                       goto up_out;
+
+               case CFGSTAT_READY:
+                       if ((ret = dsp_suspend()) < 0)
+                               goto up_out;
+                       break;
+
+               case CFGSTAT_SUSPEND:
+                       goto up_out;
+
+               default:
+                       BUG();
+
+               }
+
+               break;
+
+       case CFGSTAT_RESUME:
+               if (cfgstat != CFGSTAT_SUSPEND) {
+                       printk(KERN_WARNING
+                              "omapdsp: DSP resume request, but DSP is not in "
+                              "suspend state.\n");
+                       ret = -EINVAL;
+                       goto up_out;
+               }
+               st_req = CFGSTAT_READY;
+               break;
+
+       default:
+               BUG();
+
+       }
+
+       cfgstat = st_req;
+up_out:
+       mutex_unlock(&cfgstat_lock);
+       return ret_override ? ret_override : ret;
+}
+
+enum cfgstat_e dsp_cfgstat_get_stat(void)
+{
+       return cfgstat;
+}
+
+/*
+ * polls all tasks
+ */
+static int dsp_poll(void)
+{
+       int ret;
+
+       ret = misc_mbcompose_send_and_wait(POLL, 0, 0, NULL);
+       if ((ret < 0) && (ret != -EINTR))
+               printk(KERN_ERR "omapdsp: poll error!\n");
+
+       return ret;
+}
+
+int dsp_set_runlevel(u8 level)
+{
+       if (level == RUNLEVEL_RECOVERY) {
+               if (mbcompose_send_recovery(RUNLEVEL, level, 0) < 0)
+                       return -EINVAL;
+       } else {
+               if ((level < RUNLEVEL_USER) ||
+                   (level > RUNLEVEL_SUPER))
+                       return -EINVAL;
+               if (mbcompose_send(RUNLEVEL, level, 0) < 0)
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+static void dsp_fbctl_enable(void)
+{
+       mbcompose_send(KFUNC, KFUNC_FBCTL, FBCTL_ENABLE);
+}
+
+static int dsp_fbctl_disable(void)
+{
+       int ret;
+
+       ret = misc_mbcompose_send_and_wait(KFUNC, KFUNC_FBCTL, FBCTL_DISABLE,
+                                          NULL);
+       if ((ret < 0) && (ret != -EINTR))
+               printk(KERN_ERR "omapdsp: fb disable error!\n");
+
+       return 0;
+}
+
+static int dsp_fbstat_request(enum fbstat_e st)
+{
+       static DEFINE_MUTEX(fbstat_lock);
+       int ret = 0;
+
+       if (mutex_lock_interruptible(&fbstat_lock))
+               return -EINTR;
+
+       if (st == fbstat)
+               goto up_out;
+
+       switch (st) {
+       case FBSTAT_ENABLED:
+               dsp_fbctl_enable();
+               break;
+       case FBSTAT_DISABLED:
+               if ((ret = dsp_fbctl_disable()) < 0)
+                       goto up_out;
+               break;
+       default:
+               BUG();
+       }
+
+       fbstat = st;
+up_out:
+       mutex_unlock(&fbstat_lock);
+       return 0;
+}
+#endif /* CONFIG_OMAP_DSP_FBEXPORT */
+
+/*
+ * DSP control device file operations
+ */
+static int dsp_ctl_ioctl(struct inode *inode, struct file *file,
+                        unsigned int cmd, unsigned long arg)
+{
+       int ret = 0;
+
+       switch (cmd) {
+       /*
+        * command level 1: commands which don't need lock
+        */
+       case DSPCTL_IOCTL_RUN:
+               dsp_cpustat_request(CPUSTAT_RUN);
+               break;
+
+       case DSPCTL_IOCTL_RESET:
+               dsp_cpustat_request(CPUSTAT_RESET);
+               break;
+
+       case DSPCTL_IOCTL_SETRSTVECT:
+               ret = dsp_set_rstvect((dsp_long_t)arg);
+               break;
+
+#ifdef CONFIG_ARCH_OMAP1
+       case DSPCTL_IOCTL_CPU_IDLE:
+               dsp_cpustat_request(CPUSTAT_CPU_IDLE);
+               break;
+
+       case DSPCTL_IOCTL_GBL_IDLE:
+               dsp_cpustat_request(CPUSTAT_GBL_IDLE);
+               break;
+
+       case DSPCTL_IOCTL_MPUI_WORDSWAP_ON:
+               mpui_wordswap_on();
+               break;
+
+       case DSPCTL_IOCTL_MPUI_WORDSWAP_OFF:
+               mpui_wordswap_off();
+               break;
+
+       case DSPCTL_IOCTL_MPUI_BYTESWAP_ON:
+               mpui_byteswap_on();
+               break;
+
+       case DSPCTL_IOCTL_MPUI_BYTESWAP_OFF:
+               mpui_byteswap_off();
+               break;
+#endif /* CONFIG_ARCH_OMAP1 */
+
+       case DSPCTL_IOCTL_TASKCNT:
+               ret = dsp_task_count();
+               break;
+
+       case DSPCTL_IOCTL_MBSEND:
+               {
+                       struct omap_dsp_mailbox_cmd u_cmd;
+                       mbox_msg_t msg;
+                       if (copy_from_user(&u_cmd, (void *)arg, sizeof(u_cmd)))
+                               return -EFAULT;
+                       msg = (u_cmd.cmd << 16) | u_cmd.data;
+                       ret = dsp_mbcmd_send((struct mbcmd *)&msg);
+                       break;
+               }
+
+       case DSPCTL_IOCTL_SETVAR:
+               {
+                       struct omap_dsp_varinfo var;
+                       if (copy_from_user(&var, (void *)arg, sizeof(var)))
+                               return -EFAULT;
+                       ret = dsp_setvar(var.varid, var.val[0]);
+                       break;
+               }
+
+       case DSPCTL_IOCTL_RUNLEVEL:
+               ret = dsp_set_runlevel(arg);
+               break;
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+       case DSPCTL_IOCTL_FBEN:
+               ret = dsp_fbstat_request(FBSTAT_ENABLED);
+               break;
+#endif
+
+       /*
+        * command level 2: commands which need lock
+        */
+       case DSPCTL_IOCTL_DSPCFG:
+               ret = dsp_cfgstat_request(CFGSTAT_READY);
+               break;
+
+       case DSPCTL_IOCTL_DSPUNCFG:
+               ret = dsp_cfgstat_request(CFGSTAT_CLEAN);
+               break;
+
+       case DSPCTL_IOCTL_POLL:
+               ret = dsp_poll();
+               break;
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+       case DSPCTL_IOCTL_FBDIS:
+               ret = dsp_fbstat_request(FBSTAT_DISABLED);
+               break;
+#endif
+
+       case DSPCTL_IOCTL_SUSPEND:
+               if ((ret = dsp_cfgstat_request(CFGSTAT_SUSPEND)) < 0)
+                       break;
+               dsp_cpustat_request(CPUSTAT_RESET);
+               break;
+
+       case DSPCTL_IOCTL_RESUME:
+               if ((ret = dsp_cfgstat_request(CFGSTAT_RESUME)) < 0)
+                       break;
+               dsp_cpustat_request(CPUSTAT_RUN);
+               break;
+
+       case DSPCTL_IOCTL_REGMEMR:
+               {
+                       struct omap_dsp_reginfo *u_reg = (void *)arg;
+                       u16 adr, val;
+
+                       if (copy_from_user(&adr, &u_reg->adr, sizeof(u16)))
+                               return -EFAULT;
+                       if ((ret = dsp_regread(SPACE_MEM, adr, &val)) < 0)
+                               return ret;
+                       if (copy_to_user(&u_reg->val, &val, sizeof(u16)))
+                               return -EFAULT;
+                       break;
+               }
+
+       case DSPCTL_IOCTL_REGMEMW:
+               {
+                       struct omap_dsp_reginfo reg;
+
+                       if (copy_from_user(&reg, (void *)arg, sizeof(reg)))
+                               return -EFAULT;
+                       ret = dsp_regwrite(SPACE_MEM, reg.adr, reg.val);
+                       break;
+               }
+
+       case DSPCTL_IOCTL_REGIOR:
+               {
+                       struct omap_dsp_reginfo *u_reg = (void *)arg;
+                       u16 adr, val;
+
+                       if (copy_from_user(&adr, &u_reg->adr, sizeof(u16)))
+                               return -EFAULT;
+                       if ((ret = dsp_regread(SPACE_IO, adr, &val)) < 0)
+                               return ret;
+                       if (copy_to_user(&u_reg->val, &val, sizeof(u16)))
+                               return -EFAULT;
+                       break;
+               }
+
+       case DSPCTL_IOCTL_REGIOW:
+               {
+                       struct omap_dsp_reginfo reg;
+
+                       if (copy_from_user(&reg, (void *)arg, sizeof(reg)))
+                               return -EFAULT;
+                       ret = dsp_regwrite(SPACE_IO, reg.adr, reg.val);
+                       break;
+               }
+
+       case DSPCTL_IOCTL_GETVAR:
+               {
+                       struct omap_dsp_varinfo *u_var = (void *)arg;
+                       u8 varid;
+                       u16 val[5]; /* maximum */
+                       int argc;
+
+                       if (copy_from_user(&varid, &u_var->varid, sizeof(u8)))
+                               return -EFAULT;
+                       switch (varid) {
+                       case VARID_ICRMASK:
+                               argc = 1;
+                               break;
+                       case VARID_LOADINFO:
+                               argc = 5;
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+                       if ((ret = dsp_getvar(varid, val)) < 0)
+                               return ret;
+                       if (copy_to_user(&u_var->val, val, sizeof(u16) * argc))
+                               return -EFAULT;
+                       break;
+               }
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+
+       return ret;
+}
+
+/*
+ * functions called from mailbox interrupt routine
+ */
+void mbox_suspend(struct mbcmd *mb)
+{
+       misc_mbcmd_response(mb, 0, 0);
+}
+
+void mbox_dspcfg(struct mbcmd *mb)
+{
+       u8 last   = mb->cmd_l & 0x80;
+       u8 cfgcmd = mb->cmd_l & 0x7f;
+       static dsp_long_t tmp_ipb_adr;
+
+       if (!waitqueue_active(&misc_mb_wait.wait_q) ||
+           (misc_mb_wait.cmd_h != MBOX_CMD_DSP_DSPCFG)) {
+               printk(KERN_WARNING
+                      "mbox: DSPCFG command received, "
+                      "but nobody is waiting for it...\n");
+               return;
+       }
+
+       /* mailbox protocol check */
+       if (cfgcmd == DSPCFG_PROTREV) {
+               mbox_revision = mb->data;
+               if (mbox_revision == MBPROT_REVISION)
+                       return;
+#ifdef OLD_BINARY_SUPPORT
+               else if ((mbox_revision == MBREV_3_0) ||
+                        (mbox_revision == MBREV_3_2)) {
+                       printk(KERN_WARNING
+                              "mbox: ***** old DSP binary *****\n"
+                              "  Please update your DSP application.\n");
+                       return;
+               }
+#endif
+               else {
+                       printk(KERN_ERR
+                              "mbox: protocol revision check error!\n"
+                              "  expected=0x%04x, received=0x%04x\n",
+                              MBPROT_REVISION, mb->data);
+                       mbox_revision = -1;
+                       goto abort1;
+               }
+       }
+
+       /*
+        * following commands are accepted only after
+        * revision check has been passed.
+        */
+       if (!mbox_revision < 0) {
+               printk(KERN_INFO
+                      "mbox: DSPCFG command received, "
+                      "but revision check has not been passed.\n");
+               return;
+       }
+
+       switch (cfgcmd) {
+       case DSPCFG_SYSADRH:
+               tmp_ipb_adr = (u32)mb->data << 16;
+               break;
+
+       case DSPCFG_SYSADRL:
+               tmp_ipb_adr |= mb->data;
+               break;
+
+       case DSPCFG_ABORT:
+               goto abort1;
+
+       default:
+               printk(KERN_ERR
+                      "mbox: Unknown CFG command: cmd_l=0x%02x, data=0x%04x\n",
+                      mb->cmd_l, mb->data);
+               return;
+       }
+
+       if (last) {
+               void *badr;
+               u16 bln;
+               u16 bsz;
+               volatile u16 *buf;
+               void *ipb_sys_da, *ipb_sys_ad;
+               void *mbseq;     /* FIXME: 3.4 obsolete */
+               short *dbg_buf;
+               u16 dbg_buf_sz, dbg_line_sz;
+               struct mem_sync_struct mem_sync, *mem_syncp;
+
+               ipb_sys_da = dspword_to_virt(tmp_ipb_adr);
+               if (ipbuf_sys_config(ipb_sys_da, DIR_D2A) < 0)
+                       goto abort1;
+
+               if (dsp_mem_enable(ipbuf_sys_da) < 0) {
+                       printk(KERN_ERR "mbox: DSPCFG - ipbuf_sys_da read failed!\n");
+                       goto abort1;
+               }
+               if (sync_with_dsp(&ipbuf_sys_da->s, TID_ANON, 10) < 0) {
+                       printk(KERN_ERR "mbox: DSPCFG - IPBUF sync failed!\n");
+                       dsp_mem_disable(ipbuf_sys_da);
+                       goto abort1;
+               }
+               /*
+                * read configuration data on system IPBUF
+                * we must read with 16bit-access
+                */
+#ifdef OLD_BINARY_SUPPORT
+               if (mbox_revision == MBPROT_REVISION) {
+#endif
+                       buf = ipbuf_sys_da->d;
+                       n_stask        = buf[0];
+                       bln            = buf[1];
+                       bsz            = buf[2];
+                       badr           = MKVIRT(buf[3], buf[4]);
+                       /* ipb_sys_da     = MKVIRT(buf[5], buf[6]); */
+                       ipb_sys_ad     = MKVIRT(buf[7], buf[8]);
+                       mbseq          = MKVIRT(buf[9], buf[10]);
+                       dbg_buf        = MKVIRT(buf[11], buf[12]);
+                       dbg_buf_sz     = buf[13];
+                       dbg_line_sz    = buf[14];
+                       mem_sync.DARAM = MKVIRT(buf[15], buf[16]);
+                       mem_sync.SARAM = MKVIRT(buf[17], buf[18]);
+                       mem_sync.SDRAM = MKVIRT(buf[19], buf[20]);
+                       mem_syncp = &mem_sync;
+#ifdef OLD_BINARY_SUPPORT
+               } else if (mbox_revision == MBREV_3_2) {
+                       buf = ipbuf_sys_da->d;
+                       n_stask     = buf[0];
+                       bln         = buf[1];
+                       bsz         = buf[2];
+                       badr        = MKVIRT(buf[3], buf[4]);
+                       /* ipb_sys_da  = MKVIRT(buf[5], buf[6]); */
+                       ipb_sys_ad  = MKVIRT(buf[7], buf[8]);
+                       mbseq       = MKVIRT(buf[9], buf[10]);
+                       dbg_buf     = NULL;
+                       dbg_buf_sz  = 0;
+                       dbg_line_sz = 0;
+                       mem_syncp   = NULL;
+               } else if (mbox_revision == MBREV_3_0) {
+                       buf = ipbuf_sys_da->d;
+                       n_stask     = buf[0];
+                       bln         = buf[1];
+                       bsz         = buf[2];
+                       badr        = MKVIRT(buf[3], buf[4]);
+                       /* bkeep       = buf[5]; */
+                       /* ipb_sys_da  = MKVIRT(buf[6], buf[7]); */
+                       ipb_sys_ad  = MKVIRT(buf[8], buf[9]);
+                       mbseq       = MKVIRT(buf[10], buf[11]);
+                       dbg_buf     = NULL;
+                       dbg_buf_sz  = 0;
+                       dbg_line_sz = 0;
+                       mem_syncp   = NULL;
+               } else { /* should not occur */
+                       dsp_mem_disable(ipbuf_sys_da);
+                       goto abort1;
+               }
+#endif /* OLD_BINARY_SUPPORT */
+
+               release_ipbuf_pvt(ipbuf_sys_da);
+               dsp_mem_disable(ipbuf_sys_da);
+
+               /*
+                * following configurations need to be done before
+                * waking up the dspcfg initiator process.
+                */
+               if (ipbuf_sys_config(ipb_sys_ad, DIR_A2D) < 0)
+                       goto abort1;
+               if (ipbuf_config(bln, bsz, badr) < 0)
+                       goto abort1;
+               if (dsp_mbox_config(mbseq) < 0)
+                       goto abort2;
+               if (dsp_dbg_config(dbg_buf, dbg_buf_sz, dbg_line_sz) < 0)
+                       goto abort2;
+               if (dsp_mem_sync_config(mem_syncp) < 0)
+                       goto abort2;
+
+               misc_mb_wait.cmd_h = 0;
+               wake_up_interruptible(&misc_mb_wait.wait_q);
+       }
+       return;
+
+abort2:
+       ipbuf_stop();
+abort1:
+       wake_up_interruptible(&misc_mb_wait.wait_q);
+       return;
+}
+
+void mbox_poll(struct mbcmd *mb)
+{
+       misc_mbcmd_response(mb, 0, 0);
+}
+
+void mbox_regrw(struct mbcmd *mb)
+{
+       switch (mb->cmd_l) {
+       case REGRW_DATA:
+               misc_mbcmd_response(mb, 1, 0);
+               break;
+       default:
+               printk(KERN_ERR
+                      "mbox: Illegal REGRW command: "
+                      "cmd_l=0x%02x, data=0x%04x\n", mb->cmd_l, mb->data);
+               return;
+       }
+}
+
+void mbox_getvar(struct mbcmd *mb)
+{
+       switch (mb->cmd_l) {
+       case VARID_ICRMASK:
+               misc_mbcmd_response(mb, 1, 1);
+               break;
+       case VARID_LOADINFO:
+               misc_mbcmd_response(mb, 5, 1);
+               break;
+       default:
+               printk(KERN_ERR
+                      "mbox: Illegal GETVAR command: "
+                      "cmd_l=0x%02x, data=0x%04x\n", mb->cmd_l, mb->data);
+               return;
+       }
+}
+
+void mbox_fbctl_disable(struct mbcmd *mb)
+{
+       misc_mbcmd_response(mb, 0, 0);
+}
+
+struct file_operations dsp_ctl_fops = {
+       .owner   = THIS_MODULE,
+       .ioctl   = dsp_ctl_ioctl,
+};
+
+/*
+ * sysfs files
+ */
+
+/* ifver */
+static ssize_t ifver_show(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       int len = 0;
+
+       /*
+        * I/F VERSION descriptions:
+        *
+        * 3.2: sysfs / udev support
+        *      KMEM_RESERVE / KMEM_RELEASE ioctls for mem device
+        * 3.3: added following ioctls
+        *      DSPCTL_IOCTL_GBL_IDLE
+        *      DSPCTL_IOCTL_CPU_IDLE (instead of DSPCTL_IOCTL_IDLE)
+        *      DSPCTL_IOCTL_POLL
+        */
+
+       /*
+        * print all supporting I/F VERSIONs, like followings.
+        *
+        * len += sprintf(buf, "3.2\n");
+        * len += sprintf(buf, "3.3\n");
+        */
+       len += sprintf(buf + len, "3.2\n");
+       len += sprintf(buf + len, "3.3\n");
+
+       return len;
+}
+
+/* cpustat */
+static char *cpustat_name[CPUSTAT_MAX] = {
+       [CPUSTAT_RESET]    = "reset",
+#ifdef CONFIG_ARCH_OMAP1
+       [CPUSTAT_GBL_IDLE] = "gbl_idle",
+       [CPUSTAT_CPU_IDLE] = "cpu_idle",
+#endif
+       [CPUSTAT_RUN]      = "run",
+};
+
+static ssize_t cpustat_show(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       return sprintf(buf, "%s\n", cpustat_name[dsp_cpustat_get_stat()]);
+}
+
+/* icrmask */
+static ssize_t icrmask_show(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       return sprintf(buf, "0x%04x\n", dsp_cpustat_get_icrmask());
+}
+
+static ssize_t icrmask_store(struct device *dev, struct device_attribute *attr,
+                            const char *buf, size_t count)
+{
+       u16 mask;
+       int ret;
+
+       mask = simple_strtol(buf, NULL, 16);
+       dsp_cpustat_set_icrmask(mask);
+
+       if (dsp_cfgstat_get_stat() == CFGSTAT_READY) {
+               ret = dsp_setvar(VARID_ICRMASK, mask);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return count;
+}
+
+/* loadinfo */
+static ssize_t loadinfo_show(struct device *dev, struct device_attribute *attr,
+                            char *buf)
+{
+       int len;
+       int ret;
+       u16 val[5];
+
+       if ((ret = dsp_getvar(VARID_LOADINFO, val)) < 0)
+               return ret;
+
+       /*
+        * load info value range is 0(free) - 10000(busy):
+        * if CPU load is not measured on DSP, it sets 0xffff at val[0].
+        */
+
+       if (val[0] == 0xffff) {
+               len = sprintf(buf,
+                             "currently DSP load info is not available.\n");
+               goto out;
+       }
+
+       len = sprintf(buf,
+                     "DSP load info:\n"
+                     "  10ms average = %3d.%02d%%\n"
+                     "  1sec average = %3d.%02d%%  busiest 10ms = %3d.%02d%%\n"
+                     "  1min average = %3d.%02d%%  busiest 1s   = %3d.%02d%%\n",
+                     val[0]/100, val[0]%100,
+                     val[1]/100, val[1]%100, val[2]/100, val[2]%100,
+                     val[3]/100, val[3]%100, val[4]/100, val[4]%100);
+out:
+       return len;
+}
+
+void __init dsp_ctl_init(void)
+{
+       int ret;
+
+       ret = device_create_file(omap_dsp->dev, &dev_attr_ifver);
+       ret |= device_create_file(omap_dsp->dev, &dev_attr_cpustat);
+       ret |= device_create_file(omap_dsp->dev, &dev_attr_icrmask);
+       if (ret)
+               printk(KERN_ERR "device_create_file failed: %d\n", ret);
+}
+
+void dsp_ctl_exit(void)
+{
+       device_remove_file(omap_dsp->dev, &dev_attr_ifver);
+       device_remove_file(omap_dsp->dev, &dev_attr_cpustat);
+       device_remove_file(omap_dsp->dev, &dev_attr_icrmask);
+}
diff --git a/arch/arm/plat-omap/dsp/dsp_ctl_core.c b/arch/arm/plat-omap/dsp/dsp_ctl_core.c
new file mode 100644 (file)
index 0000000..04420df
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2004-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include "dsp.h"
+
+#define CTL_MINOR      0
+#define MEM_MINOR      1
+#define TWCH_MINOR     2
+#define ERR_MINOR      3
+
+static struct class *dsp_ctl_class;
+extern struct file_operations dsp_ctl_fops,
+                             dsp_mem_fops,
+                             dsp_twch_fops,
+                             dsp_err_fops;
+
+static int dsp_ctl_core_open(struct inode *inode, struct file *file)
+{
+       static DEFINE_MUTEX(open_lock);
+       int ret = 0;
+
+       mutex_lock_interruptible(&open_lock);
+       if (omap_dsp->initialized == 0) {
+               ret = dsp_late_init();
+               if (ret != 0) {
+                       mutex_unlock(&open_lock);
+                       return ret;
+               }
+               omap_dsp->initialized = 1;
+       }
+       mutex_unlock(&open_lock);
+
+       switch (iminor(inode)) {
+       case CTL_MINOR:
+               file->f_op = &dsp_ctl_fops;
+               break;
+       case MEM_MINOR:
+               file->f_op = &dsp_mem_fops;
+               break;
+       case TWCH_MINOR:
+               file->f_op = &dsp_twch_fops;
+               break;
+       case ERR_MINOR:
+               file->f_op = &dsp_err_fops;
+               break;
+       default:
+               return -ENXIO;
+       }
+       if (file->f_op && file->f_op->open)
+               return file->f_op->open(inode, file);
+       return 0;
+}
+
+static struct file_operations dsp_ctl_core_fops = {
+       .owner = THIS_MODULE,
+       .open  = dsp_ctl_core_open,
+};
+
+static const struct dev_list {
+       unsigned int    minor;
+       char            *devname;
+       umode_t         mode;
+} dev_list[] = {
+       {CTL_MINOR,  "dspctl",  S_IRUSR | S_IWUSR},
+       {MEM_MINOR,  "dspmem",  S_IRUSR | S_IWUSR | S_IRGRP},
+       {TWCH_MINOR, "dsptwch", S_IRUSR | S_IWUSR | S_IRGRP},
+       {ERR_MINOR,  "dsperr",  S_IRUSR | S_IRGRP},
+};
+
+int __init dsp_ctl_core_init(void)
+{
+       int retval;
+       int i;
+
+       retval = register_chrdev(OMAP_DSP_CTL_MAJOR, "dspctl",
+                                &dsp_ctl_core_fops);
+       if (retval < 0) {
+               printk(KERN_ERR
+                      "omapdsp: failed to register dspctl device: %d\n",
+                      retval);
+               return retval;
+       }
+
+       dsp_ctl_class = class_create(THIS_MODULE, "dspctl");
+       for (i = 0; i < ARRAY_SIZE(dev_list); i++) {
+               class_device_create(dsp_ctl_class, NULL,
+                                   MKDEV(OMAP_DSP_CTL_MAJOR,
+                                         dev_list[i].minor),
+                                   NULL, dev_list[i].devname);
+       }
+
+       return 0;
+}
+
+void dsp_ctl_core_exit(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(dev_list); i++) {
+               class_device_destroy(dsp_ctl_class,
+                                    MKDEV(OMAP_DSP_CTL_MAJOR,
+                                          dev_list[i].minor));
+       }
+       class_destroy(dsp_ctl_class);
+
+       unregister_chrdev(OMAP_DSP_CTL_MAJOR, "dspctl");
+}
diff --git a/arch/arm/plat-omap/dsp/dsp_mbcmd.h b/arch/arm/plat-omap/dsp/dsp_mbcmd.h
new file mode 100644 (file)
index 0000000..d30c3bc
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/*
+ * mailbox command: 0x00 - 0x7f
+ * when a driver wants to use mailbox, it must reserve mailbox commands here.
+ */
+#define MBOX_CMD_DSP_WDSND     0x10
+#define MBOX_CMD_DSP_WDREQ     0x11
+#define MBOX_CMD_DSP_BKSND     0x20
+#define MBOX_CMD_DSP_BKREQ     0x21
+#define MBOX_CMD_DSP_BKYLD     0x23
+#define MBOX_CMD_DSP_BKSNDP    0x24
+#define MBOX_CMD_DSP_BKREQP    0x25
+#define MBOX_CMD_DSP_TCTL      0x30
+#define MBOX_CMD_DSP_TCTLDATA  0x31
+#define MBOX_CMD_DSP_POLL      0x32
+#define MBOX_CMD_DSP_WDT       0x50
+#define MBOX_CMD_DSP_RUNLEVEL  0x51
+#define MBOX_CMD_DSP_PM                0x52
+#define MBOX_CMD_DSP_SUSPEND   0x53
+#define MBOX_CMD_DSP_KFUNC     0x54
+#define MBOX_CMD_DSP_TCFG      0x60
+#define MBOX_CMD_DSP_TADD      0x62
+#define MBOX_CMD_DSP_TDEL      0x63
+#define MBOX_CMD_DSP_TSTOP     0x65
+#define MBOX_CMD_DSP_DSPCFG    0x70
+#define MBOX_CMD_DSP_REGRW     0x72
+#define MBOX_CMD_DSP_GETVAR    0x74
+#define MBOX_CMD_DSP_SETVAR    0x75
+#define MBOX_CMD_DSP_ERR       0x78
+#define MBOX_CMD_DSP_DBG       0x79
+
+/*
+ * DSP mailbox protocol definitions
+ */
+#define MBPROT_REVISION        0x0019
+
+#define TCTL_TINIT             0x0000
+#define TCTL_TEN               0x0001
+#define TCTL_TDIS              0x0002
+#define TCTL_TCLR              0x0003
+#define TCTL_TCLR_FORCE                0x0004
+
+#define RUNLEVEL_USER          0x01
+#define RUNLEVEL_SUPER         0x0e
+#define RUNLEVEL_RECOVERY      0x10
+
+#define PM_DISABLE             0x00
+#define PM_ENABLE              0x01
+
+#define KFUNC_FBCTL            0x00
+#define KFUNC_POWER            0x01
+
+#define FBCTL_UPD              0x0000
+#define FBCTL_ENABLE           0x0002
+#define FBCTL_DISABLE          0x0003
+
+/* KFUNC_POWER */
+#define AUDIO_PWR_UP           0x0000  /* ARM(exe/ack) <->  DSP(req)   */
+#define AUDIO_PWR_DOWN         0x0001  /* ARM(exe)     <-  DSP(req)    */
+#define AUDIO_PWR_DOWN1                AUDIO_PWR_DOWN
+#define AUDIO_PWR_DOWN2                0x0002
+#define DSP_PWR_UP             0x0003  /* ARM(exe/snd) ->  DSP(exe)    */
+#define DSP_PWR_DOWN           0x0004  /* ARM(exe)     <-  DSP(req)    */
+#define DVFS_START             0x0006  /* ARM(req)     <-> DSP(exe/ack)*/
+#define DVFS_STOP              0x0007  /* ARM(req)      -> DSP(exe)    */
+
+#define TDEL_SAFE              0x0000
+#define TDEL_KILL              0x0001
+
+#define DSPCFG_REQ             0x00
+#define DSPCFG_SYSADRH         0x28
+#define DSPCFG_SYSADRL         0x29
+#define DSPCFG_PROTREV         0x70
+#define DSPCFG_ABORT           0x78
+#define DSPCFG_LAST            0x80
+
+#define REGRW_MEMR             0x00
+#define REGRW_MEMW             0x01
+#define REGRW_IOR              0x02
+#define REGRW_IOW              0x03
+#define REGRW_DATA             0x04
+
+#define VARID_ICRMASK          0x00
+#define VARID_LOADINFO         0x01
+
+#define TTYP_ARCV              0x0001
+#define TTYP_ASND              0x0002
+#define TTYP_BKMD              0x0004
+#define TTYP_BKDM              0x0008
+#define TTYP_PVMD              0x0010
+#define TTYP_PVDM              0x0020
+
+#define EID_BADTID             0x10
+#define EID_BADTCN             0x11
+#define EID_BADBID             0x20
+#define EID_BADCNT             0x21
+#define EID_NOTLOCKED          0x22
+#define EID_STVBUF             0x23
+#define EID_BADADR             0x24
+#define EID_BADTCTL            0x30
+#define EID_BADPARAM           0x50
+#define EID_FATAL              0x58
+#define EID_NOMEM              0xc0
+#define EID_NORES              0xc1
+#define EID_IPBFULL            0xc2
+#define EID_WDT                        0xd0
+#define EID_TASKNOTRDY         0xe0
+#define EID_TASKBSY            0xe1
+#define EID_TASKERR            0xef
+#define EID_BADCFGTYP          0xf0
+#define EID_DEBUG              0xf8
+#define EID_BADSEQ             0xfe
+#define EID_BADCMD             0xff
+
+#define TNM_LEN                        16
+
+#define TID_FREE               0xff
+#define TID_ANON               0xfe
+
+#define BID_NULL               0xffff
+#define BID_PVT                        0xfffe
diff --git a/arch/arm/plat-omap/dsp/dsp_mem.c b/arch/arm/plat-omap/dsp/dsp_mem.c
new file mode 100644 (file)
index 0000000..8442a96
--- /dev/null
@@ -0,0 +1,2542 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * Conversion to mempool API and ARM MMU section mapping
+ * by Paul Mundt <paul.mundt@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/fb.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mempool.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/arch/tc.h>
+#include <asm/arch/omapfb.h>
+#include <asm/arch/mailbox.h>
+#include <asm/arch/dsp_common.h>
+#include "uaccess_dsp.h"
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ioctl.h"
+#include "ipbuf.h"
+
+#ifdef CONFIG_ARCH_OMAP2
+#define IOMAP_VAL      0x3f
+#endif
+
+#define SZ_1KB 0x400
+#define SZ_4KB 0x1000
+#define SZ_64KB        0x10000
+#define SZ_1MB 0x100000
+#define SZ_16MB        0x1000000
+#define is_aligned(adr,align)  (!((adr)&((align)-1)))
+#define ORDER_4KB      (12 - PAGE_SHIFT)
+#define ORDER_64KB     (16 - PAGE_SHIFT)
+#define ORDER_1MB      (20 - PAGE_SHIFT)
+
+/*
+ * absorb DSP MMU register size and location difference
+ */
+#if defined(CONFIG_ARCH_OMAP1)
+typedef u16 dsp_mmu_reg_t;
+#define dsp_mmu_read_reg(a)    omap_readw(a)
+#define dsp_mmu_write_reg(v,a) omap_writew(v,a)
+#elif defined(CONFIG_ARCH_OMAP2)
+typedef u32 dsp_mmu_reg_t;
+#define dsp_mmu_read_reg(a)    readl(a)
+#define dsp_mmu_write_reg(v,a) writel(v,a)
+#define dsp_ipi_read_reg(a)    readl(a)
+#define dsp_ipi_write_reg(v,a) writel(v,a)
+#endif
+
+#if defined(CONFIG_ARCH_OMAP1)
+
+#define dsp_mmu_enable() \
+       do { \
+               dsp_mmu_write_reg(DSP_MMU_CNTL_MMU_EN | DSP_MMU_CNTL_RESET_SW, \
+                                 DSP_MMU_CNTL); \
+       } while(0)
+#define dsp_mmu_disable() \
+       do { \
+               dsp_mmu_write_reg(0, DSP_MMU_CNTL); \
+       } while(0)
+#define __dsp_mmu_itack() \
+       do { \
+               dsp_mmu_write_reg(DSP_MMU_IT_ACK_IT_ACK, DSP_MMU_IT_ACK); \
+       } while(0)
+
+#elif defined(CONFIG_ARCH_OMAP2)
+
+#define dsp_mmu_enable() \
+       do { \
+               dsp_mmu_write_reg(DSP_MMU_CNTL_MMUENABLE, DSP_MMU_CNTL); \
+       } while(0)
+#define dsp_mmu_disable() \
+       do { \
+               dsp_mmu_write_reg(0, DSP_MMU_CNTL); \
+       } while(0)
+#define dsp_mmu_reset() \
+       do { \
+               dsp_mmu_write_reg(dsp_mmu_read_reg(DSP_MMU_SYSCONFIG) | \
+                                 DSP_MMU_SYSCONFIG_SOFTRESET, \
+                                 DSP_MMU_SYSCONFIG); \
+       } while(0)
+
+#endif /* CONFIG_ARCH_OMAP2 */
+
+#define dsp_mmu_flush() \
+       do { \
+               dsp_mmu_write_reg(DSP_MMU_FLUSH_ENTRY_FLUSH_ENTRY, \
+                                 DSP_MMU_FLUSH_ENTRY); \
+       } while(0)
+#define __dsp_mmu_gflush() \
+       do { \
+               dsp_mmu_write_reg(DSP_MMU_GFLUSH_GFLUSH, DSP_MMU_GFLUSH); \
+       } while(0)
+
+/*
+ * absorb register name difference
+ */
+#ifdef CONFIG_ARCH_OMAP1
+#define DSP_MMU_CAM_P                  DSP_MMU_CAM_L_P
+#define DSP_MMU_CAM_V                  DSP_MMU_CAM_L_V
+#define DSP_MMU_CAM_PAGESIZE_MASK      DSP_MMU_CAM_L_PAGESIZE_MASK
+#define DSP_MMU_CAM_PAGESIZE_1MB       DSP_MMU_CAM_L_PAGESIZE_1MB
+#define DSP_MMU_CAM_PAGESIZE_64KB      DSP_MMU_CAM_L_PAGESIZE_64KB
+#define DSP_MMU_CAM_PAGESIZE_4KB       DSP_MMU_CAM_L_PAGESIZE_4KB
+#define DSP_MMU_CAM_PAGESIZE_1KB       DSP_MMU_CAM_L_PAGESIZE_1KB
+#endif /* CONFIG_ARCH_OMAP1 */
+
+/*
+ * OMAP1 EMIFF access
+ */
+#ifdef CONFIG_ARCH_OMAP1
+#define EMIF_PRIO_LB_MASK      0x0000f000
+#define EMIF_PRIO_LB_SHIFT     12
+#define EMIF_PRIO_DMA_MASK     0x00000f00
+#define EMIF_PRIO_DMA_SHIFT    8
+#define EMIF_PRIO_DSP_MASK     0x00000070
+#define EMIF_PRIO_DSP_SHIFT    4
+#define EMIF_PRIO_MPU_MASK     0x00000007
+#define EMIF_PRIO_MPU_SHIFT    0
+#define set_emiff_dma_prio(prio) \
+       do { \
+               omap_writel((omap_readl(OMAP_TC_OCPT1_PRIOR) & \
+                            ~EMIF_PRIO_DMA_MASK) | \
+                           ((prio) << EMIF_PRIO_DMA_SHIFT), \
+                           OMAP_TC_OCPT1_PRIOR); \
+       } while(0)
+#endif /* CONFIG_ARCH_OMAP1 */
+
+enum exmap_type_e {
+       EXMAP_TYPE_MEM,
+       EXMAP_TYPE_FB
+};
+
+struct exmap_tbl_entry {
+       unsigned int valid:1;
+       unsigned int prsvd:1;   /* preserved */
+       int usecount;           /* reference count by mmap */
+       enum exmap_type_e type;
+       void *buf;              /* virtual address of the buffer,
+                                * i.e. 0xc0000000 - */
+       void *vadr;             /* DSP shadow space,
+                                * i.e. 0xe0000000 - 0xe0ffffff */
+       unsigned int order;
+       struct {
+               int prev;
+               int next;
+       } link;                 /* grouping */
+};
+
+#define INIT_EXMAP_TBL_ENTRY(ent,b,v,typ,od) \
+       do {\
+               (ent)->buf       = (b); \
+               (ent)->vadr      = (v); \
+               (ent)->valid     = 1; \
+               (ent)->prsvd     = 0; \
+               (ent)->usecount  = 0; \
+               (ent)->type      = (typ); \
+               (ent)->order     = (od); \
+               (ent)->link.next = -1; \
+               (ent)->link.prev = -1; \
+       } while (0)
+
+#define INIT_EXMAP_TBL_ENTRY_4KB_PRESERVED(ent,b,v) \
+       do {\
+               (ent)->buf       = (b); \
+               (ent)->vadr      = (v); \
+               (ent)->valid     = 1; \
+               (ent)->prsvd     = 1; \
+               (ent)->usecount  = 0; \
+               (ent)->type      = EXMAP_TYPE_MEM; \
+               (ent)->order     = 0; \
+               (ent)->link.next = -1; \
+               (ent)->link.prev = -1; \
+       } while (0)
+
+#define DSP_MMU_TLB_LINES      32
+static struct exmap_tbl_entry exmap_tbl[DSP_MMU_TLB_LINES];
+static int exmap_preserved_cnt;
+static DECLARE_RWSEM(exmap_sem);
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+static struct omapfb_notifier_block *omapfb_nb;
+static int omapfb_ready;
+#endif
+
+struct cam_ram_regset {
+#if defined(CONFIG_ARCH_OMAP1)
+       dsp_mmu_reg_t cam_h;
+       dsp_mmu_reg_t cam_l;
+       dsp_mmu_reg_t ram_h;
+       dsp_mmu_reg_t ram_l;
+#elif defined(CONFIG_ARCH_OMAP2)
+       dsp_mmu_reg_t cam;
+       dsp_mmu_reg_t ram;
+#endif
+};
+
+struct tlb_entry {
+       dsp_long_t va;
+       unsigned long pa;
+       dsp_mmu_reg_t pgsz, prsvd, valid;
+#if defined(CONFIG_ARCH_OMAP1)
+       dsp_mmu_reg_t ap;
+#elif defined(CONFIG_ARCH_OMAP2)
+       dsp_mmu_reg_t endian, elsz, mixed;
+#endif
+};
+
+#if defined(CONFIG_ARCH_OMAP1)
+#define INIT_TLB_ENTRY(ent,v,p,ps) \
+       do { \
+               (ent)->va = (v); \
+               (ent)->pa = (p); \
+               (ent)->pgsz = (ps); \
+               (ent)->prsvd = 0; \
+               (ent)->ap = DSP_MMU_RAM_L_AP_FA; \
+       } while (0)
+#define INIT_TLB_ENTRY_4KB_PRESERVED(ent,v,p) \
+       do { \
+               (ent)->va = (v); \
+               (ent)->pa = (p); \
+               (ent)->pgsz = DSP_MMU_CAM_PAGESIZE_4KB; \
+               (ent)->prsvd = DSP_MMU_CAM_P; \
+               (ent)->ap = DSP_MMU_RAM_L_AP_FA; \
+       } while (0)
+#elif defined(CONFIG_ARCH_OMAP2)
+#define INIT_TLB_ENTRY(ent,v,p,ps) \
+       do { \
+               (ent)->va = (v); \
+               (ent)->pa = (p); \
+               (ent)->pgsz = (ps); \
+               (ent)->prsvd = 0; \
+               (ent)->endian = DSP_MMU_RAM_ENDIANNESS_LITTLE; \
+               (ent)->elsz = DSP_MMU_RAM_ELEMENTSIZE_16; \
+               (ent)->mixed = 0; \
+       } while (0)
+#define INIT_TLB_ENTRY_4KB_PRESERVED(ent,v,p) \
+       do { \
+               (ent)->va = (v); \
+               (ent)->pa = (p); \
+               (ent)->pgsz = DSP_MMU_CAM_PAGESIZE_4KB; \
+               (ent)->prsvd = DSP_MMU_CAM_P; \
+               (ent)->endian = DSP_MMU_RAM_ENDIANNESS_LITTLE; \
+               (ent)->elsz = DSP_MMU_RAM_ELEMENTSIZE_16; \
+               (ent)->mixed = 0; \
+       } while (0)
+#define INIT_TLB_ENTRY_4KB_ES32_PRESERVED(ent,v,p) \
+       do { \
+               (ent)->va = (v); \
+               (ent)->pa = (p); \
+               (ent)->pgsz = DSP_MMU_CAM_PAGESIZE_4KB; \
+               (ent)->prsvd = DSP_MMU_CAM_P; \
+               (ent)->endian = DSP_MMU_RAM_ENDIANNESS_LITTLE; \
+               (ent)->elsz = DSP_MMU_RAM_ELEMENTSIZE_32; \
+               (ent)->mixed = 0; \
+       } while (0)
+#endif
+
+#if defined(CONFIG_ARCH_OMAP1)
+#define cam_ram_valid(cr)      ((cr).cam_l & DSP_MMU_CAM_V)
+#elif defined(CONFIG_ARCH_OMAP2)
+#define cam_ram_valid(cr)      ((cr).cam & DSP_MMU_CAM_V)
+#endif
+
+struct tlb_lock {
+       int base;
+       int victim;
+};
+
+static int dsp_exunmap(dsp_long_t dspadr);
+
+static void *dspvect_page;
+static u32 dsp_fault_adr;
+static struct mem_sync_struct mem_sync;
+
+static ssize_t mmu_show(struct device *dev, struct device_attribute *attr,
+                       char *buf);
+static ssize_t exmap_show(struct device *dev, struct device_attribute *attr,
+                         char *buf);
+static ssize_t mempool_show(struct device *dev, struct device_attribute *attr,
+                           char *buf);
+
+static struct device_attribute dev_attr_mmu =     __ATTR_RO(mmu);
+static struct device_attribute dev_attr_exmap =   __ATTR_RO(exmap);
+static struct device_attribute dev_attr_mempool = __ATTR_RO(mempool);
+
+/*
+ * special mempool function:
+ * hope this goes to mm/mempool.c
+ */
+static void *mempool_alloc_from_pool(mempool_t *pool, gfp_t gfp_mask)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pool->lock, flags);
+       if (likely(pool->curr_nr)) {
+               void *element = pool->elements[--pool->curr_nr];
+               spin_unlock_irqrestore(&pool->lock, flags);
+               return element;
+       }
+       spin_unlock_irqrestore(&pool->lock, flags);
+
+       return mempool_alloc(pool, gfp_mask);
+}
+
+static __inline__ unsigned long lineup_offset(unsigned long adr,
+                                             unsigned long ref,
+                                             unsigned long mask)
+{
+       unsigned long newadr;
+
+       newadr = (adr & ~mask) | (ref & mask);
+       if (newadr < adr)
+               newadr += mask + 1;
+       return newadr;
+}
+
+int dsp_mem_sync_inc(void)
+{
+       if (dsp_mem_enable((void *)dspmem_base) < 0)
+               return -1;
+       if (mem_sync.DARAM)
+               mem_sync.DARAM->ad_arm++;
+       if (mem_sync.SARAM)
+               mem_sync.SARAM->ad_arm++;
+       if (mem_sync.SDRAM)
+               mem_sync.SDRAM->ad_arm++;
+       dsp_mem_disable((void *)dspmem_base);
+       return 0;
+}
+
+/*
+ * dsp_mem_sync_config() is called from mbox1 workqueue
+ */
+int dsp_mem_sync_config(struct mem_sync_struct *sync)
+{
+       size_t sync_seq_sz = sizeof(struct sync_seq);
+
+#ifdef OLD_BINARY_SUPPORT
+       if (sync == NULL) {
+               memset(&mem_sync, 0, sizeof(struct mem_sync_struct));
+               return 0;
+       }
+#endif
+       if ((dsp_mem_type(sync->DARAM, sync_seq_sz) != MEM_TYPE_DARAM) ||
+           (dsp_mem_type(sync->SARAM, sync_seq_sz) != MEM_TYPE_SARAM) ||
+           (dsp_mem_type(sync->SDRAM, sync_seq_sz) != MEM_TYPE_EXTERN)) {
+               printk(KERN_ERR
+                      "omapdsp: mem_sync address validation failure!\n"
+                      "  mem_sync.DARAM = 0x%p,\n"
+                      "  mem_sync.SARAM = 0x%p,\n"
+                      "  mem_sync.SDRAM = 0x%p,\n",
+                      sync->DARAM, sync->SARAM, sync->SDRAM);
+               return -1;
+       }
+       memcpy(&mem_sync, sync, sizeof(struct mem_sync_struct));
+       return 0;
+}
+
+static mempool_t *kmem_pool_1M;
+static mempool_t *kmem_pool_64K;
+
+static void *dsp_pool_alloc(unsigned int __nocast gfp, void *order)
+{
+       return (void *)__get_dma_pages(gfp, (unsigned int)order);
+}
+
+static void dsp_pool_free(void *buf, void *order)
+{
+       free_pages((unsigned long)buf, (unsigned int)order);
+}
+
+static void dsp_kmem_release(void)
+{
+       if (kmem_pool_64K) {
+               mempool_destroy(kmem_pool_64K);
+               kmem_pool_64K = NULL;
+       }
+
+       if (kmem_pool_1M) {
+               mempool_destroy(kmem_pool_1M);
+               kmem_pool_1M = NULL;
+       }
+}
+
+static int dsp_kmem_reserve(unsigned long size)
+{
+       unsigned long len = size;
+
+       /* alignment check */
+       if (!is_aligned(size, SZ_64KB)) {
+               printk(KERN_ERR
+                      "omapdsp: size(0x%lx) is not multiple of 64KB.\n", size);
+               return -EINVAL;
+       }
+
+       if (size > DSPSPACE_SIZE) {
+               printk(KERN_ERR
+                      "omapdsp: size(0x%lx) is larger than DSP memory space "
+                      "size (0x%x.\n", size, DSPSPACE_SIZE);
+               return -EINVAL;
+       }
+
+       if (size >= SZ_1MB) {
+               int nr = size >> 20;
+
+               if (likely(!kmem_pool_1M))
+                       kmem_pool_1M = mempool_create(nr,
+                                                     dsp_pool_alloc,
+                                                     dsp_pool_free,
+                                                     (void *)ORDER_1MB);
+               else
+                       mempool_resize(kmem_pool_1M, kmem_pool_1M->min_nr + nr,
+                                      GFP_KERNEL);
+
+               size &= ~(0xf << 20);
+       }
+
+       if (size >= SZ_64KB) {
+               int nr = size >> 16;
+
+               if (likely(!kmem_pool_64K))
+                       kmem_pool_64K = mempool_create(nr,
+                                                      dsp_pool_alloc,
+                                                      dsp_pool_free,
+                                                      (void *)ORDER_64KB);
+               else
+                       mempool_resize(kmem_pool_64K,
+                                      kmem_pool_64K->min_nr + nr, GFP_KERNEL);
+
+               size &= ~(0xf << 16);
+       }
+
+       if (size)
+               len -= size;
+
+       return len;
+}
+
+static void dsp_mem_free_pages(unsigned long buf, unsigned int order)
+{
+       struct page *page, *ps, *pe;
+
+       ps = virt_to_page(buf);
+       pe = virt_to_page(buf + (1 << (PAGE_SHIFT + order)));
+
+       for (page = ps; page < pe; page++)
+               ClearPageReserved(page);
+
+       if ((order == ORDER_64KB) && likely(kmem_pool_64K))
+               mempool_free((void *)buf, kmem_pool_64K);
+       else if ((order == ORDER_1MB) && likely(kmem_pool_1M))
+               mempool_free((void *)buf, kmem_pool_1M);
+       else
+               free_pages(buf, order);
+}
+
+static inline void
+exmap_alloc_pte(unsigned long virt, unsigned long phys, pgprot_t prot)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+       pte_t *pte;
+
+       pgd = pgd_offset_k(virt);
+       pud = pud_offset(pgd, virt);
+       pmd = pmd_offset(pud, virt);
+
+       if (pmd_none(*pmd)) {
+               pte = pte_alloc_one_kernel(&init_mm, 0);
+               if (!pte)
+                       return;
+
+               /* note: two PMDs will be set  */
+               pmd_populate_kernel(&init_mm, pmd, pte);
+       }
+
+       pte = pte_offset_kernel(pmd, virt);
+       set_pte_ext(pte, pfn_pte(phys >> PAGE_SHIFT, prot), 0);
+}
+
+#if 0
+static inline int
+exmap_alloc_sect(unsigned long virt, unsigned long phys, int prot)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+
+       pgd = pgd_offset_k(virt);
+       pud = pud_alloc(&init_mm, pgd, virt);
+       pmd = pmd_alloc(&init_mm, pud, virt);
+
+       if (virt & (1 << 20))
+               pmd++;
+
+       if (!pmd_none(*pmd))
+               /* No good, fall back on smaller mappings. */
+               return -EINVAL;
+
+       *pmd = __pmd(phys | prot);
+       flush_pmd_entry(pmd);
+
+       return 0;
+}
+#endif
+
+/*
+ * ARM MMU operations
+ */
+static int exmap_set_armmmu(unsigned long virt, unsigned long phys,
+                           unsigned long size)
+{
+       long off;
+       pgprot_t prot_pte;
+       int prot_sect;
+
+       printk(KERN_DEBUG
+              "omapdsp: mapping in ARM MMU, v=0x%08lx, p=0x%08lx, sz=0x%lx\n",
+              virt, phys, size);
+
+       prot_pte = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG |
+                           L_PTE_DIRTY | L_PTE_WRITE);
+
+       prot_sect = PMD_TYPE_SECT | PMD_SECT_UNCACHED |
+                   PMD_SECT_AP_WRITE | PMD_DOMAIN(DOMAIN_IO);
+
+       if (cpu_architecture() <= CPU_ARCH_ARMv5)
+               prot_sect |= PMD_BIT4;
+
+       off = phys - virt;
+
+       while ((virt & 0xfffff || (virt + off) & 0xfffff) && size >= PAGE_SIZE) {
+               exmap_alloc_pte(virt, virt + off, prot_pte);
+
+               virt += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       /* XXX: Not yet.. confuses dspfb -- PFM. */
+#if 0
+       while (size >= (PGDIR_SIZE / 2)) {
+               if (exmap_alloc_sect(virt, virt + off, prot_sect) < 0)
+                       break;
+
+               virt += (PGDIR_SIZE / 2);
+               size -= (PGDIR_SIZE / 2);
+       }
+#endif
+
+       while (size >= PAGE_SIZE) {
+               exmap_alloc_pte(virt, virt + off, prot_pte);
+
+               virt += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       BUG_ON(size);
+
+       return 0;
+}
+
+       /* XXX: T.Kobayashi
+        * A process can have old mappings. if we want to clear a pmd,
+        * we need to do it for all proceeses that use the old mapping.
+        */
+#if 0
+static inline void
+exmap_clear_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end)
+{
+       pte_t *pte;
+
+       pte = pte_offset_map(pmd, addr);
+       do {
+               if (pte_none(*pte))
+                       continue;
+
+               pte_clear(&init_mm, addr, pte);
+       } while (pte++, addr += PAGE_SIZE, addr != end);
+
+       pte_unmap(pte - 1);
+}
+
+static inline void
+exmap_clear_pmd_range(pud_t *pud, unsigned long addr, unsigned long end)
+{
+       pmd_t *pmd;
+       unsigned long next;
+
+       pmd = pmd_offset(pud, addr);
+       do {
+               next = pmd_addr_end(addr, end);
+
+               if (addr & (1 << 20))
+                       pmd++;
+
+               if ((pmd_val(*pmd) & PMD_TYPE_MASK) == PMD_TYPE_SECT) {
+                       *pmd = __pmd(0);
+                       clean_pmd_entry(pmd);
+                       continue;
+               }
+
+               if (pmd_none_or_clear_bad(pmd))
+                       continue;
+
+               exmap_clear_pte_range(pmd, addr, next);
+       } while (pmd++, addr = next, addr != end);
+}
+
+static inline void
+exmap_clear_pud_range(pgd_t *pgd, unsigned long addr, unsigned long end)
+{
+       pud_t *pud;
+       unsigned long next;
+
+       pud = pud_offset(pgd, addr);
+       do {
+               next = pud_addr_end(addr, end);
+               if (pud_none_or_clear_bad(pud))
+                       continue;
+
+               exmap_clear_pmd_range(pud, addr, next);
+       } while (pud++, addr = next, addr != end);
+}
+#endif
+
+static void exmap_clear_armmmu(unsigned long virt, unsigned long size)
+{
+#if 0
+       unsigned long next, end;
+       pgd_t *pgd;
+
+       printk(KERN_DEBUG
+              "omapdsp: unmapping in ARM MMU, v=%#010lx, sz=%#lx\n",
+              virt, size);
+
+       pgd = pgd_offset_k(virt);
+       end = virt + size;
+       do {
+               next = pgd_addr_end(virt, end);
+               if (pgd_none_or_clear_bad(pgd))
+                       continue;
+
+               exmap_clear_pud_range(pgd, virt, next);
+       } while (pgd++, virt = next, virt != end);
+#else
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+       pte_t *pte;
+
+       printk(KERN_DEBUG
+              "omapdsp: unmapping in ARM MMU, v=%#010lx, sz=%#lx\n",
+              virt, size);
+
+       while (size >= PAGE_SIZE) {
+               pgd = pgd_offset_k(virt);
+               pud = pud_offset(pgd, virt);
+               pmd = pmd_offset(pud, virt);
+               pte = pte_offset_kernel(pmd, virt);
+
+               pte_clear(&init_mm, virt, pte);
+               size -= PAGE_SIZE;
+               virt += PAGE_SIZE;
+       }
+
+       BUG_ON(size);
+#endif
+}
+
+static int exmap_valid(void *vadr, size_t len)
+{
+       /* exmap_sem should be held before calling this function */
+       int i;
+
+start:
+       for (i = 0; i < DSP_MMU_TLB_LINES; i++) {
+               void *mapadr;
+               unsigned long mapsize;
+               struct exmap_tbl_entry *ent = &exmap_tbl[i];
+
+               if (!ent->valid)
+                       continue;
+               mapadr = (void *)ent->vadr;
+               mapsize = 1 << (ent->order + PAGE_SHIFT);
+               if ((vadr >= mapadr) && (vadr < mapadr + mapsize)) {
+                       if (vadr + len <= mapadr + mapsize) {
+                               /* this map covers whole address. */
+                               return 1;
+                       } else {
+                               /*
+                                * this map covers partially.
+                                * check rest portion.
+                                */
+                               len -= mapadr + mapsize - vadr;
+                               vadr = mapadr + mapsize;
+                               goto start;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+enum dsp_mem_type_e dsp_mem_type(void *vadr, size_t len)
+{
+       void *ds = (void *)daram_base;
+       void *de = (void *)daram_base + daram_size;
+       void *ss = (void *)saram_base;
+       void *se = (void *)saram_base + saram_size;
+       int ret;
+
+       if ((vadr >= ds) && (vadr < de)) {
+               if (vadr + len > de)
+                       return MEM_TYPE_CROSSING;
+               else
+                       return MEM_TYPE_DARAM;
+       } else if ((vadr >= ss) && (vadr < se)) {
+               if (vadr + len > se)
+                       return MEM_TYPE_CROSSING;
+               else
+                       return MEM_TYPE_SARAM;
+       } else {
+               down_read(&exmap_sem);
+               if (exmap_valid(vadr, len))
+                       ret = MEM_TYPE_EXTERN;
+               else
+                       ret = MEM_TYPE_NONE;
+               up_read(&exmap_sem);
+               return ret;
+       }
+}
+
+int dsp_address_validate(void *p, size_t len, char *fmt, ...)
+{
+       if (dsp_mem_type(p, len) <= 0) {
+               if (fmt != NULL) {
+                       char s[64];
+                       va_list args;
+
+                       va_start(args, fmt);
+                       vsprintf(s, fmt, args);
+                       va_end(args);
+                       printk(KERN_ERR
+                              "omapdsp: %s address(0x%p) and size(0x%x) is "
+                              "not valid!\n"
+                              "         (crossing different type of memories, or \n"
+                              "          external memory space where no "
+                              "actual memory is mapped)\n",
+                              s, p, len);
+               }
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * exmap_use(), unuse():
+ * when the mapped area is exported to user space with mmap,
+ * the usecount is incremented.
+ * while the usecount > 0, that area can't be released.
+ */
+void exmap_use(void *vadr, size_t len)
+{
+       int i;
+
+       down_write(&exmap_sem);
+       for (i = 0; i < DSP_MMU_TLB_LINES; i++) {
+               void *mapadr;
+               unsigned long mapsize;
+               struct exmap_tbl_entry *ent = &exmap_tbl[i];
+
+               if (!ent->valid)
+                       continue;
+               mapadr = (void *)ent->vadr;
+               mapsize = 1 << (ent->order + PAGE_SHIFT);
+               if ((vadr + len > mapadr) && (vadr < mapadr + mapsize))
+                       ent->usecount++;
+       }
+       up_write(&exmap_sem);
+}
+
+void exmap_unuse(void *vadr, size_t len)
+{
+       int i;
+
+       down_write(&exmap_sem);
+       for (i = 0; i < DSP_MMU_TLB_LINES; i++) {
+               void *mapadr;
+               unsigned long mapsize;
+               struct exmap_tbl_entry *ent = &exmap_tbl[i];
+
+               if (!ent->valid)
+                       continue;
+               mapadr = (void *)ent->vadr;
+               mapsize = 1 << (ent->order + PAGE_SHIFT);
+               if ((vadr + len > mapadr) && (vadr < mapadr + mapsize))
+                       ent->usecount--;
+       }
+       up_write(&exmap_sem);
+}
+
+/*
+ * dsp_virt_to_phys()
+ * returns physical address, and sets len to valid length
+ */
+unsigned long dsp_virt_to_phys(void *vadr, size_t *len)
+{
+       int i;
+
+       if (is_dsp_internal_mem(vadr)) {
+               /* DSRAM or SARAM */
+               *len = dspmem_base + dspmem_size - (unsigned long)vadr;
+               return (unsigned long)vadr;
+       }
+
+       /* EXRAM */
+       for (i = 0; i < DSP_MMU_TLB_LINES; i++) {
+               void *mapadr;
+               unsigned long mapsize;
+               struct exmap_tbl_entry *ent = &exmap_tbl[i];
+
+               if (!ent->valid)
+                       continue;
+               mapadr = (void *)ent->vadr;
+               mapsize = 1 << (ent->order + PAGE_SHIFT);
+               if ((vadr >= mapadr) && (vadr < mapadr + mapsize)) {
+                       *len = mapadr + mapsize - vadr;
+                       return __pa(ent->buf) + vadr - mapadr;
+               }
+       }
+
+       /* valid mapping not found */
+       return 0;
+}
+
+/*
+ * DSP MMU operations
+ */
+#ifdef CONFIG_ARCH_OMAP1
+static dsp_mmu_reg_t get_cam_l_va_mask(dsp_mmu_reg_t pgsz)
+{
+       switch (pgsz) {
+       case DSP_MMU_CAM_PAGESIZE_1MB:
+               return DSP_MMU_CAM_L_VA_TAG_L1_MASK |
+                      DSP_MMU_CAM_L_VA_TAG_L2_MASK_1MB;
+       case DSP_MMU_CAM_PAGESIZE_64KB:
+               return DSP_MMU_CAM_L_VA_TAG_L1_MASK |
+                      DSP_MMU_CAM_L_VA_TAG_L2_MASK_64KB;
+       case DSP_MMU_CAM_PAGESIZE_4KB:
+               return DSP_MMU_CAM_L_VA_TAG_L1_MASK |
+                      DSP_MMU_CAM_L_VA_TAG_L2_MASK_4KB;
+       case DSP_MMU_CAM_PAGESIZE_1KB:
+               return DSP_MMU_CAM_L_VA_TAG_L1_MASK |
+                      DSP_MMU_CAM_L_VA_TAG_L2_MASK_1KB;
+       }
+       return 0;
+}
+#endif /* CONFIG_ARCH_OMAP1 */
+
+#if defined(CONFIG_ARCH_OMAP1)
+#define get_cam_va_mask(pgsz) \
+       ((u32)DSP_MMU_CAM_H_VA_TAG_H_MASK << 22 | \
+        (u32)get_cam_l_va_mask(pgsz) << 6)
+#elif defined(CONFIG_ARCH_OMAP2)
+#define get_cam_va_mask(pgsz) \
+       ((pgsz == DSP_MMU_CAM_PAGESIZE_16MB) ? 0xff000000 : \
+        (pgsz == DSP_MMU_CAM_PAGESIZE_1MB)  ? 0xfff00000 : \
+        (pgsz == DSP_MMU_CAM_PAGESIZE_64KB) ? 0xffff0000 : \
+        (pgsz == DSP_MMU_CAM_PAGESIZE_4KB)  ? 0xfffff000 : 0)
+#endif /* CONFIG_ARCH_OMAP2 */
+
+static void get_tlb_lock(struct tlb_lock *tlb_lock)
+{
+       dsp_mmu_reg_t lock = dsp_mmu_read_reg(DSP_MMU_LOCK);
+
+       tlb_lock->base = (lock & DSP_MMU_LOCK_BASE_MASK) >>
+                        DSP_MMU_LOCK_BASE_SHIFT;
+       tlb_lock->victim = (lock & DSP_MMU_LOCK_VICTIM_MASK) >>
+                          DSP_MMU_LOCK_VICTIM_SHIFT;
+}
+
+static void set_tlb_lock(struct tlb_lock *tlb_lock)
+{
+       dsp_mmu_write_reg((tlb_lock->base   << DSP_MMU_LOCK_BASE_SHIFT) |
+                         (tlb_lock->victim << DSP_MMU_LOCK_VICTIM_SHIFT),
+                         DSP_MMU_LOCK);
+}
+
+static void __read_tlb(struct tlb_lock *tlb_lock, struct cam_ram_regset *cr)
+{
+       /* set victim */
+       set_tlb_lock(tlb_lock);
+
+#if defined(CONFIG_ARCH_OMAP1)
+       /* read a TLB entry */
+       dsp_mmu_write_reg(DSP_MMU_LD_TLB_RD, DSP_MMU_LD_TLB);
+
+       cr->cam_h = dsp_mmu_read_reg(DSP_MMU_READ_CAM_H);
+       cr->cam_l = dsp_mmu_read_reg(DSP_MMU_READ_CAM_L);
+       cr->ram_h = dsp_mmu_read_reg(DSP_MMU_READ_RAM_H);
+       cr->ram_l = dsp_mmu_read_reg(DSP_MMU_READ_RAM_L);
+#elif defined(CONFIG_ARCH_OMAP2)
+       cr->cam = dsp_mmu_read_reg(DSP_MMU_READ_CAM);
+       cr->ram = dsp_mmu_read_reg(DSP_MMU_READ_RAM);
+#endif
+}
+
+static void __load_tlb(struct cam_ram_regset *cr)
+{
+#if defined(CONFIG_ARCH_OMAP1)
+       dsp_mmu_write_reg(cr->cam_h, DSP_MMU_CAM_H);
+       dsp_mmu_write_reg(cr->cam_l, DSP_MMU_CAM_L);
+       dsp_mmu_write_reg(cr->ram_h, DSP_MMU_RAM_H);
+       dsp_mmu_write_reg(cr->ram_l, DSP_MMU_RAM_L);
+#elif defined(CONFIG_ARCH_OMAP2)
+       dsp_mmu_write_reg(cr->cam | DSP_MMU_CAM_V, DSP_MMU_CAM);
+       dsp_mmu_write_reg(cr->ram, DSP_MMU_RAM);
+#endif
+
+       /* flush the entry */
+       dsp_mmu_flush();
+
+       /* load a TLB entry */
+       dsp_mmu_write_reg(DSP_MMU_LD_TLB_LD, DSP_MMU_LD_TLB);
+}
+
+static int dsp_mmu_load_tlb(struct tlb_entry *tlb_ent)
+{
+       struct tlb_lock tlb_lock;
+       struct cam_ram_regset cr;
+
+#ifdef CONFIG_ARCH_OMAP1
+       clk_enable(dsp_ck_handle);
+       omap_dsp_request_mem();
+#endif
+
+       get_tlb_lock(&tlb_lock);
+       for (tlb_lock.victim = 0;
+            tlb_lock.victim < tlb_lock.base;
+            tlb_lock.victim++) {
+               struct cam_ram_regset tmp_cr;
+
+               /* read a TLB entry */
+               __read_tlb(&tlb_lock, &tmp_cr);
+               if (!cam_ram_valid(tmp_cr))
+                       goto found_victim;
+       }
+       set_tlb_lock(&tlb_lock);
+
+found_victim:
+       /* The last (31st) entry cannot be locked? */
+       if (tlb_lock.victim == 31) {
+               printk(KERN_ERR "omapdsp: TLB is full.\n");
+               return -EBUSY;
+       }
+
+       if (tlb_ent->va & ~get_cam_va_mask(tlb_ent->pgsz)) {
+               printk(KERN_ERR
+                      "omapdsp: mapping vadr (0x%06x) is not "
+                      "aligned boundary\n", tlb_ent->va);
+               return -EINVAL;
+       }
+
+#if defined(CONFIG_ARCH_OMAP1)
+       cr.cam_h = tlb_ent->va >> 22;
+       cr.cam_l = (tlb_ent->va >> 6 & get_cam_l_va_mask(tlb_ent->pgsz)) |
+                  tlb_ent->prsvd | tlb_ent->pgsz;
+       cr.ram_h = tlb_ent->pa >> 16;
+       cr.ram_l = (tlb_ent->pa & DSP_MMU_RAM_L_RAM_LSB_MASK) | tlb_ent->ap;
+#elif defined(CONFIG_ARCH_OMAP2)
+       cr.cam = (tlb_ent->va & DSP_MMU_CAM_VATAG_MASK) |
+                tlb_ent->prsvd | tlb_ent->pgsz;
+       cr.ram = tlb_ent->pa | tlb_ent->endian | tlb_ent->elsz;
+#endif
+       __load_tlb(&cr);
+
+       /* update lock base */
+       if (tlb_lock.victim == tlb_lock.base)
+               tlb_lock.base++;
+       tlb_lock.victim = tlb_lock.base;
+       set_tlb_lock(&tlb_lock);
+
+#ifdef CONFIG_ARCH_OMAP1
+       omap_dsp_release_mem();
+       clk_disable(dsp_ck_handle);
+#endif
+       return 0;
+}
+
+static int dsp_mmu_clear_tlb(dsp_long_t vadr)
+{
+       struct tlb_lock tlb_lock;
+       int i;
+       int max_valid = 0;
+
+#ifdef CONFIG_ARCH_OMAP1
+       clk_enable(dsp_ck_handle);
+       omap_dsp_request_mem();
+#endif
+
+       get_tlb_lock(&tlb_lock);
+       for (i = 0; i < tlb_lock.base; i++) {
+               struct cam_ram_regset cr;
+               dsp_long_t cam_va;
+               dsp_mmu_reg_t pgsz;
+
+               /* read a TLB entry */
+               tlb_lock.victim = i;
+               __read_tlb(&tlb_lock, &cr);
+               if (!cam_ram_valid(cr))
+                       continue;
+
+#if defined(CONFIG_ARCH_OMAP1)
+               pgsz = cr.cam_l & DSP_MMU_CAM_PAGESIZE_MASK;
+               cam_va = (u32)(cr.cam_h & DSP_MMU_CAM_H_VA_TAG_H_MASK) << 22 |
+                        (u32)(cr.cam_l & get_cam_l_va_mask(pgsz)) << 6;
+#elif defined(CONFIG_ARCH_OMAP2)
+               pgsz = cr.cam & DSP_MMU_CAM_PAGESIZE_MASK;
+               cam_va = cr.cam & get_cam_va_mask(pgsz);
+#endif
+
+               if (cam_va == vadr)
+                       /* flush the entry */
+                       dsp_mmu_flush();
+               else
+                       max_valid = i;
+       }
+
+       /* set new lock base */
+       tlb_lock.base   = max_valid + 1;
+       tlb_lock.victim = max_valid + 1;
+       set_tlb_lock(&tlb_lock);
+
+#ifdef CONFIG_ARCH_OMAP1
+       omap_dsp_release_mem();
+       clk_disable(dsp_ck_handle);
+#endif
+       return 0;
+}
+
+static void dsp_mmu_gflush(void)
+{
+       struct tlb_lock tlb_lock;
+
+#ifdef CONFIG_ARCH_OMAP1
+       clk_enable(dsp_ck_handle);
+       omap_dsp_request_mem();
+#endif
+
+       __dsp_mmu_gflush();
+       tlb_lock.base   = exmap_preserved_cnt;
+       tlb_lock.victim = exmap_preserved_cnt;
+       set_tlb_lock(&tlb_lock);
+
+#ifdef CONFIG_ARCH_OMAP1
+       omap_dsp_release_mem();
+       clk_disable(dsp_ck_handle);
+#endif
+}
+
+/*
+ * dsp_exmap()
+ *
+ * MEM_IOCTL_EXMAP ioctl calls this function with padr=0.
+ * In this case, the buffer for DSP is allocated in this routine,
+ * then it is mapped.
+ * On the other hand, for example - frame buffer sharing, calls
+ * this function with padr set. It means some known address space
+ * pointed with padr is going to be shared with DSP.
+ */
+static int dsp_exmap(dsp_long_t dspadr, unsigned long padr, unsigned long size,
+                    enum exmap_type_e type)
+{
+       dsp_mmu_reg_t pgsz;
+       void *buf;
+       unsigned int order = 0;
+       unsigned long unit;
+       int prev = -1;
+       dsp_long_t _dspadr = dspadr;
+       unsigned long _padr = padr;
+       void *_vadr = dspbyte_to_virt(dspadr);
+       unsigned long _size = size;
+       struct tlb_entry tlb_ent;
+       struct exmap_tbl_entry *exmap_ent;
+       int status;
+       int idx;
+       int i;
+
+#define MINIMUM_PAGESZ SZ_4KB
+       /*
+        * alignment check
+        */
+       if (!is_aligned(size, MINIMUM_PAGESZ)) {
+               printk(KERN_ERR
+                      "omapdsp: size(0x%lx) is not multiple of 4KB.\n", size);
+               return -EINVAL;
+       }
+       if (!is_aligned(dspadr, MINIMUM_PAGESZ)) {
+               printk(KERN_ERR
+                      "omapdsp: DSP address(0x%x) is not aligned.\n", dspadr);
+               return -EINVAL;
+       }
+       if (!is_aligned(padr, MINIMUM_PAGESZ)) {
+               printk(KERN_ERR
+                      "omapdsp: physical address(0x%lx) is not aligned.\n",
+                      padr);
+               return -EINVAL;
+       }
+
+       /* address validity check */
+       if ((dspadr < dspmem_size) ||
+           (dspadr >= DSPSPACE_SIZE) ||
+           ((dspadr + size > DSP_INIT_PAGE) &&
+            (dspadr < DSP_INIT_PAGE + PAGE_SIZE))) {
+               printk(KERN_ERR
+                      "omapdsp: illegal address/size for dsp_exmap().\n");
+               return -EINVAL;
+       }
+
+       down_write(&exmap_sem);
+
+       /* overlap check */
+       for (i = 0; i < DSP_MMU_TLB_LINES; i++) {
+               unsigned long mapsize;
+               struct exmap_tbl_entry *tmp_ent = &exmap_tbl[i];
+
+               if (!tmp_ent->valid)
+                       continue;
+               mapsize = 1 << (tmp_ent->order + PAGE_SHIFT);
+               if ((_vadr + size > tmp_ent->vadr) &&
+                   (_vadr < tmp_ent->vadr + mapsize)) {
+                       printk(KERN_ERR "omapdsp: exmap page overlap!\n");
+                       up_write(&exmap_sem);
+                       return -EINVAL;
+               }
+       }
+
+start:
+       buf = NULL;
+       /* Are there any free TLB lines?  */
+       for (idx = 0; idx < DSP_MMU_TLB_LINES; idx++) {
+               if (!exmap_tbl[idx].valid)
+                       goto found_free;
+       }
+       printk(KERN_ERR "omapdsp: DSP TLB is full.\n");
+       status = -EBUSY;
+       goto fail;
+
+found_free:
+       exmap_ent = &exmap_tbl[idx];
+
+       /*
+        * we don't use
+        * 1KB mapping in OMAP1,
+        * 16MB mapping in OMAP2.
+        */
+       if ((_size >= SZ_1MB) &&
+           (is_aligned(_padr, SZ_1MB) || (padr == 0)) &&
+           is_aligned(_dspadr, SZ_1MB)) {
+               unit = SZ_1MB;
+               pgsz = DSP_MMU_CAM_PAGESIZE_1MB;
+       } else if ((_size >= SZ_64KB) &&
+                  (is_aligned(_padr, SZ_64KB) || (padr == 0)) &&
+                  is_aligned(_dspadr, SZ_64KB)) {
+               unit = SZ_64KB;
+               pgsz = DSP_MMU_CAM_PAGESIZE_64KB;
+       } else {
+               unit = SZ_4KB;
+               pgsz = DSP_MMU_CAM_PAGESIZE_4KB;
+       }
+
+       order = get_order(unit);
+
+       /* buffer allocation */
+       if (type == EXMAP_TYPE_MEM) {
+               struct page *page, *ps, *pe;
+
+               if ((order == ORDER_1MB) && likely(kmem_pool_1M))
+                       buf = mempool_alloc_from_pool(kmem_pool_1M, GFP_KERNEL);
+               else if ((order == ORDER_64KB) && likely(kmem_pool_64K))
+                       buf = mempool_alloc_from_pool(kmem_pool_64K,GFP_KERNEL);
+               else {
+                       buf = (void *)__get_dma_pages(GFP_KERNEL, order);
+                       if (buf == NULL) {
+                               status = -ENOMEM;
+                               goto fail;
+                       }
+               }
+
+               /* mark the pages as reserved; this is needed for mmap */
+               ps = virt_to_page(buf);
+               pe = virt_to_page(buf + unit);
+
+               for (page = ps; page < pe; page++)
+                       SetPageReserved(page);
+
+               _padr = __pa(buf);
+       }
+
+       /*
+        * mapping for ARM MMU:
+        * we should not access to the allocated memory through 'buf'
+        * since this area should not be cashed.
+        */
+       status = exmap_set_armmmu((unsigned long)_vadr, _padr, unit);
+       if (status < 0)
+               goto fail;
+
+       /* loading DSP TLB entry */
+       INIT_TLB_ENTRY(&tlb_ent, _dspadr, _padr, pgsz);
+       status = dsp_mmu_load_tlb(&tlb_ent);
+       if (status < 0) {
+               exmap_clear_armmmu((unsigned long)_vadr, unit);
+               goto fail;
+       }
+
+       INIT_EXMAP_TBL_ENTRY(exmap_ent, buf, _vadr, type, order);
+       exmap_ent->link.prev = prev;
+       if (prev >= 0)
+               exmap_tbl[prev].link.next = idx;
+
+       if ((_size -= unit) == 0) {     /* normal completion */
+               up_write(&exmap_sem);
+               return size;
+       }
+
+       _dspadr += unit;
+       _vadr   += unit;
+       _padr = padr ? _padr + unit : 0;
+       prev = idx;
+       goto start;
+
+fail:
+       up_write(&exmap_sem);
+       if (buf)
+               dsp_mem_free_pages((unsigned long)buf, order);
+       dsp_exunmap(dspadr);
+       return status;
+}
+
+static unsigned long unmap_free_arm(struct exmap_tbl_entry *ent)
+{
+       unsigned long size;
+
+       /* clearing ARM MMU */
+       size = 1 << (ent->order + PAGE_SHIFT);
+       exmap_clear_armmmu((unsigned long)ent->vadr, size);
+
+       /* freeing allocated memory */
+       if (ent->type == EXMAP_TYPE_MEM) {
+               dsp_mem_free_pages((unsigned long)ent->buf, ent->order);
+               printk(KERN_DEBUG
+                      "omapdsp: freeing 0x%lx bytes @ adr 0x%8p\n",
+                      size, ent->buf);
+       }
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+       else if (ent->type == EXMAP_TYPE_FB) {
+               int status;
+               if (omapfb_nb) {
+                       status = omapfb_unregister_client(omapfb_nb);
+                       if (!status)
+                               printk("omapfb_unregister_client(): "
+                                      "success\n");
+                       else
+                               printk("omapfb_runegister_client(): "
+                                      "failure(%d)\n", status);
+                       kfree(omapfb_nb);
+                       omapfb_nb = NULL;
+                       omapfb_ready = 0;
+               }
+       }
+#endif
+
+       return size;
+}
+
+static int dsp_exunmap(dsp_long_t dspadr)
+{
+       void *vadr;
+       unsigned long size;
+       int total = 0;
+       struct exmap_tbl_entry *ent;
+       int idx;
+
+       vadr = dspbyte_to_virt(dspadr);
+       down_write(&exmap_sem);
+       for (idx = 0; idx < DSP_MMU_TLB_LINES; idx++) {
+               ent = &exmap_tbl[idx];
+               if ((!ent->valid) || ent->prsvd)
+                       continue;
+               if (ent->vadr == vadr)
+                       goto found_map;
+       }
+       up_write(&exmap_sem);
+       printk(KERN_WARNING
+              "omapdsp: address %06x not found in exmap_tbl.\n", dspadr);
+       return -EINVAL;
+
+found_map:
+       if (ent->usecount > 0) {
+               printk(KERN_ERR
+                      "omapdsp: exmap reference count is not 0.\n"
+                      "   idx=%d, vadr=%p, order=%d, usecount=%d\n",
+                      idx, ent->vadr, ent->order, ent->usecount);
+               up_write(&exmap_sem);
+               return -EINVAL;
+       }
+       /* clearing DSP TLB entry */
+       dsp_mmu_clear_tlb(dspadr);
+
+       /* clear ARM MMU and free buffer */
+       size = unmap_free_arm(ent);
+       ent->valid = 0;
+       total += size;
+
+       /* we don't free PTEs */
+
+       /* flush TLB */
+       flush_tlb_kernel_range((unsigned long)vadr, (unsigned long)vadr + size);
+
+       if ((idx = ent->link.next) < 0)
+               goto up_out;    /* normal completion */
+       ent = &exmap_tbl[idx];
+       dspadr += size;
+       vadr   += size;
+       if (ent->vadr == vadr)
+               goto found_map; /* continue */
+
+       printk(KERN_ERR
+              "omapdsp: illegal exmap_tbl grouping!\n"
+              "expected vadr = %p, exmap_tbl[%d].vadr = %p\n",
+              vadr, idx, ent->vadr);
+       up_write(&exmap_sem);
+       return -EINVAL;
+
+up_out:
+       up_write(&exmap_sem);
+       return total;
+}
+
+static void exmap_flush(void)
+{
+       struct exmap_tbl_entry *ent;
+       int i;
+
+       down_write(&exmap_sem);
+
+       /* clearing DSP TLB entry */
+       dsp_mmu_gflush();
+
+       for (i = 0; i < DSP_MMU_TLB_LINES; i++) {
+               ent = &exmap_tbl[i];
+               if (ent->valid && (!ent->prsvd)) {
+                       unmap_free_arm(ent);
+                       ent->valid = 0;
+               }
+       }
+
+       /* flush TLB */
+       flush_tlb_kernel_range(dspmem_base + dspmem_size,
+                              dspmem_base + DSPSPACE_SIZE);
+       up_write(&exmap_sem);
+}
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+#ifndef CONFIG_FB
+#error You configured OMAP_DSP_FBEXPORT, but FB was not configured!
+#endif /* CONFIG_FB */
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+static int omapfb_notifier_cb(struct notifier_block *omapfb_nb,
+                             unsigned long event, void *fbi)
+{
+       /* XXX */
+       printk("omapfb_notifier_cb(): event = %s\n",
+              (event == OMAPFB_EVENT_READY)    ? "READY" :
+              (event == OMAPFB_EVENT_DISABLED) ? "DISABLED" : "Unknown");
+       if (event == OMAPFB_EVENT_READY)
+               omapfb_ready = 1;
+       else if (event == OMAPFB_EVENT_DISABLED)
+               omapfb_ready = 0;
+       return 0;
+}
+#endif
+
+static int dsp_fbexport(dsp_long_t *dspadr)
+{
+       dsp_long_t dspadr_actual;
+       unsigned long padr_sys, padr, fbsz_sys, fbsz;
+       int cnt;
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+       int status;
+#endif
+
+       printk(KERN_DEBUG "omapdsp: frame buffer export\n");
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+       if (omapfb_nb) {
+               printk(KERN_WARNING
+                      "omapdsp: frame buffer has been exported already!\n");
+               return -EBUSY;
+       }
+#endif
+
+       if (num_registered_fb == 0) {
+               printk(KERN_INFO "omapdsp: frame buffer not registered.\n");
+               return -EINVAL;
+       }
+       if (num_registered_fb != 1) {
+               printk(KERN_INFO
+                      "omapdsp: %d frame buffers found. we use first one.\n",
+                      num_registered_fb);
+       }
+       padr_sys = registered_fb[0]->fix.smem_start;
+       fbsz_sys = registered_fb[0]->fix.smem_len;
+       if (fbsz_sys == 0) {
+               printk(KERN_ERR
+                      "omapdsp: framebuffer doesn't seem to be configured "
+                      "correctly! (size=0)\n");
+               return -EINVAL;
+       }
+
+       /*
+        * align padr and fbsz to 4kB boundary
+        * (should be noted to the user afterwards!)
+        */
+       padr = padr_sys & ~(SZ_4KB-1);
+       fbsz = (fbsz_sys + padr_sys - padr + SZ_4KB-1) & ~(SZ_4KB-1);
+
+       /* line up dspadr offset with padr */
+       dspadr_actual =
+               (fbsz > SZ_1MB) ?  lineup_offset(*dspadr, padr, SZ_1MB-1) :
+               (fbsz > SZ_64KB) ? lineup_offset(*dspadr, padr, SZ_64KB-1) :
+               /* (fbsz > SZ_4KB) ? */ *dspadr;
+       if (dspadr_actual != *dspadr)
+               printk(KERN_DEBUG
+                      "omapdsp: actual dspadr for FBEXPORT = %08x\n",
+                      dspadr_actual);
+       *dspadr = dspadr_actual;
+
+       cnt = dsp_exmap(dspadr_actual, padr, fbsz, EXMAP_TYPE_FB);
+       if (cnt < 0) {
+               printk(KERN_ERR "omapdsp: exmap failure.\n");
+               return cnt;
+       }
+
+       if ((padr != padr_sys) || (fbsz != fbsz_sys)) {
+               printk(KERN_WARNING
+"  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
+"  !!  screen base address or size is not aligned in 4kB:           !!\n"
+"  !!    actual screen  adr = %08lx, size = %08lx             !!\n"
+"  !!    exporting      adr = %08lx, size = %08lx             !!\n"
+"  !!  Make sure that the framebuffer is allocated with 4kB-order!  !!\n"
+"  !!  Otherwise DSP can corrupt the kernel memory.                 !!\n"
+"  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",
+                      padr_sys, fbsz_sys, padr, fbsz);
+       }
+
+#ifdef CONFIG_ARCH_OMAP1
+       /* increase the DMA priority */
+       set_emiff_dma_prio(15);
+#endif
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+       omapfb_nb = kzalloc(sizeof(struct omapfb_notifier_block), GFP_KERNEL);
+       if (omapfb_nb == NULL) {
+               printk(KERN_ERR
+                      "omapdsp: failed to allocate memory for omapfb_nb!\n");
+               dsp_exunmap(dspadr_actual);
+               return -ENOMEM;
+       }
+       status = omapfb_register_client(omapfb_nb, omapfb_notifier_cb, NULL);
+       if (!status)
+               printk("omapfb_register_client(): success\n");
+       else
+               printk("omapfb_register_client(): failure(%d)\n", status);
+#endif
+
+       return cnt;
+}
+
+#else /* CONFIG_OMAP_DSP_FBEXPORT */
+
+static int dsp_fbexport(dsp_long_t *dspadr)
+{
+       printk(KERN_ERR "omapdsp: FBEXPORT function is not enabled.\n");
+       return -EINVAL;
+}
+
+#endif /* CONFIG_OMAP_DSP_FBEXPORT */
+
+static void exmap_setup_preserved_mem_page(void *buf, dsp_long_t dspadr,
+                                          int exmap_idx)
+{
+       unsigned long phys;
+       void *virt;
+       struct tlb_entry tlb_ent;
+
+       phys = __pa(buf);
+       virt = dspbyte_to_virt(dspadr);
+       exmap_set_armmmu((unsigned long)virt, phys, PAGE_SIZE);
+       INIT_EXMAP_TBL_ENTRY_4KB_PRESERVED(&exmap_tbl[exmap_idx], buf, virt);
+       INIT_TLB_ENTRY_4KB_PRESERVED(&tlb_ent, dspadr, phys);
+       dsp_mmu_load_tlb(&tlb_ent);
+}
+
+static void exmap_clear_mem_page(dsp_long_t dspadr)
+{
+       void *virt;
+
+       virt = dspbyte_to_virt(dspadr);
+       exmap_clear_armmmu((unsigned long)virt, PAGE_SIZE);
+       /* DSP MMU is shutting down. not handled here. */
+}
+
+#ifdef CONFIG_ARCH_OMAP2
+static void exmap_setup_iomap_page(unsigned long phys, unsigned long dsp_io_adr,
+                                  int exmap_idx)
+{
+       dsp_long_t dspadr;
+       void *virt;
+       struct tlb_entry tlb_ent;
+
+       dspadr = (IOMAP_VAL << 18) + (dsp_io_adr << 1);
+       virt = dspbyte_to_virt(dspadr);
+       exmap_set_armmmu((unsigned long)virt, phys, PAGE_SIZE);
+       INIT_EXMAP_TBL_ENTRY_4KB_PRESERVED(&exmap_tbl[exmap_idx], NULL, virt);
+       INIT_TLB_ENTRY_4KB_ES32_PRESERVED(&tlb_ent, dspadr, phys);
+       dsp_mmu_load_tlb(&tlb_ent);
+}
+
+static void exmap_clear_iomap_page(unsigned long dsp_io_adr)
+{
+       dsp_long_t dspadr;
+       void *virt;
+
+       dspadr = (IOMAP_VAL << 18) + (dsp_io_adr << 1);
+       virt = dspbyte_to_virt(dspadr);
+       exmap_clear_armmmu((unsigned long)virt, PAGE_SIZE);
+       /* DSP MMU is shutting down. not handled here. */
+}
+#endif /* CONFIG_ARCH_OMAP2 */
+
+#define OMAP2420_GPT5_BASE     (L4_24XX_BASE + 0x7c000)
+#define OMAP2420_GPT6_BASE     (L4_24XX_BASE + 0x7e000)
+#define OMAP2420_GPT7_BASE     (L4_24XX_BASE + 0x80000)
+#define OMAP2420_GPT8_BASE     (L4_24XX_BASE + 0x82000)
+#define OMAP24XX_EAC_BASE      (L4_24XX_BASE + 0x90000)
+
+static int exmap_setup_preserved_entries(void)
+{
+       int n = 0;
+
+       exmap_setup_preserved_mem_page(dspvect_page, DSP_INIT_PAGE, n++);
+#ifdef CONFIG_ARCH_OMAP2
+       exmap_setup_iomap_page(OMAP24XX_PRCM_BASE,     0x7000, n++);
+#ifdef CONFIG_ARCH_OMAP2420
+       exmap_setup_iomap_page(OMAP2420_GPT5_BASE,     0xe000, n++);
+       exmap_setup_iomap_page(OMAP2420_GPT6_BASE,     0xe800, n++);
+       exmap_setup_iomap_page(OMAP2420_GPT7_BASE,     0xf000, n++);
+       exmap_setup_iomap_page(OMAP2420_GPT8_BASE,     0xf800, n++);
+#endif /* CONFIG_ARCH_OMAP2420 */
+       exmap_setup_iomap_page(OMAP24XX_EAC_BASE,     0x10000, n++);
+       exmap_setup_iomap_page(OMAP24XX_MAILBOX_BASE, 0x11000, n++);
+#endif /* CONFIG_ARCH_OMAP2 */
+
+       return n;
+}
+
+static void exmap_clear_preserved_entries(void)
+{
+       exmap_clear_mem_page(DSP_INIT_PAGE);
+#ifdef CONFIG_ARCH_OMAP2
+       exmap_clear_iomap_page(0x7000);         /* PRCM */
+#ifdef CONFIG_ARCH_OMAP2420
+       exmap_clear_iomap_page(0xe000);         /* GPT5 */
+       exmap_clear_iomap_page(0xe800);         /* GPT6 */
+       exmap_clear_iomap_page(0xf000);         /* GPT7 */
+       exmap_clear_iomap_page(0xf800);         /* GPT8 */
+#endif /* CONFIG_ARCH_OMAP2420 */
+       exmap_clear_iomap_page(0x10000);        /* EAC */
+       exmap_clear_iomap_page(0x11000);        /* MAILBOX */
+#endif /* CONFIG_ARCH_OMAP2 */
+}
+
+#ifdef CONFIG_ARCH_OMAP1
+static int dsp_mmu_itack(void)
+{
+       unsigned long dspadr;
+
+       printk(KERN_INFO "omapdsp: sending DSP MMU interrupt ack.\n");
+       if (!dsp_err_isset(ERRCODE_MMU)) {
+               printk(KERN_ERR "omapdsp: DSP MMU error has not been set.\n");
+               return -EINVAL;
+       }
+       dspadr = dsp_fault_adr & ~(SZ_4K-1);
+       dsp_exmap(dspadr, 0, SZ_4K, EXMAP_TYPE_MEM);    /* FIXME: reserve TLB entry for this */
+       printk(KERN_INFO "omapdsp: falling into recovery runlevel...\n");
+       dsp_set_runlevel(RUNLEVEL_RECOVERY);
+       __dsp_mmu_itack();
+       udelay(100);
+       dsp_exunmap(dspadr);
+       dsp_err_clear(ERRCODE_MMU);
+       return 0;
+}
+#endif /* CONFIG_ARCH_OMAP1 */
+
+#ifdef CONFIG_ARCH_OMAP2
+#define MMU_IRQ_MASK \
+       (DSP_MMU_IRQ_MULTIHITFAULT | \
+        DSP_MMU_IRQ_TABLEWALKFAULT | \
+        DSP_MMU_IRQ_EMUMISS | \
+        DSP_MMU_IRQ_TRANSLATIONFAULT | \
+        DSP_MMU_IRQ_TLBMISS)
+#endif
+
+static int is_mmu_init;
+
+static void dsp_mmu_init(void)
+{
+       struct tlb_lock tlb_lock;
+
+#ifdef CONFIG_ARCH_OMAP1
+       clk_enable(dsp_ck_handle);
+       omap_dsp_request_mem();
+#endif
+       down_write(&exmap_sem);
+
+#if defined(CONFIG_ARCH_OMAP1)
+       dsp_mmu_disable();      /* clear all */
+       udelay(100);
+#elif defined(CONFIG_ARCH_OMAP2)
+       dsp_mmu_reset();
+#endif
+       dsp_mmu_enable();
+
+       /* DSP TLB initialization */
+       tlb_lock.base   = 0;
+       tlb_lock.victim = 0;
+       set_tlb_lock(&tlb_lock);
+
+       exmap_preserved_cnt = exmap_setup_preserved_entries();
+
+#ifdef CONFIG_ARCH_OMAP2
+       /* MMU IRQ mask setup */
+       dsp_mmu_write_reg(MMU_IRQ_MASK, DSP_MMU_IRQENABLE);
+#endif
+
+       up_write(&exmap_sem);
+#ifdef CONFIG_ARCH_OMAP1
+       omap_dsp_release_mem();
+       clk_disable(dsp_ck_handle);
+#endif
+
+       is_mmu_init = 1;
+}
+
+static void dsp_mmu_shutdown(void)
+{
+       if (is_mmu_init) {
+               exmap_flush();
+               exmap_clear_preserved_entries();
+               dsp_mmu_disable();
+       }
+}
+
+#ifdef CONFIG_ARCH_OMAP1
+/*
+ * intmem_enable() / disable():
+ * if the address is in DSP internal memories,
+ * we send PM mailbox commands so that DSP DMA domain won't go in idle
+ * when ARM is accessing to those memories.
+ */
+static int intmem_enable(void)
+{
+       int ret = 0;
+
+       if (dsp_cfgstat_get_stat() == CFGSTAT_READY)
+               ret = mbcompose_send(PM, PM_ENABLE, DSPREG_ICR_DMA);
+
+       return ret;
+}
+
+static void intmem_disable(void) {
+       if (dsp_cfgstat_get_stat() == CFGSTAT_READY)
+               mbcompose_send(PM, PM_DISABLE, DSPREG_ICR_DMA);
+}
+#endif /* CONFIG_ARCH_OMAP1 */
+
+/*
+ * dsp_mem_enable() / disable()
+ */
+#ifdef CONFIG_ARCH_OMAP1
+int intmem_usecount;
+#endif
+
+int dsp_mem_enable(void *adr)
+{
+       int ret = 0;
+
+       if (is_dsp_internal_mem(adr)) {
+#ifdef CONFIG_ARCH_OMAP1
+               if (intmem_usecount++ == 0)
+                       ret = omap_dsp_request_mem();
+#endif
+       } else
+               down_read(&exmap_sem);
+
+       return ret;
+}
+
+void dsp_mem_disable(void *adr)
+{
+       if (is_dsp_internal_mem(adr)) {
+#ifdef CONFIG_ARCH_OMAP1
+               if (--intmem_usecount == 0)
+                       omap_dsp_release_mem();
+#endif
+       } else
+               up_read(&exmap_sem);
+}
+
+/* for safety */
+#ifdef CONFIG_ARCH_OMAP1
+void dsp_mem_usecount_clear(void)
+{
+       if (intmem_usecount != 0) {
+               printk(KERN_WARNING
+                      "omapdsp: unbalanced memory request/release detected.\n"
+                      "         intmem_usecount is not zero at where "
+                      "it should be! ... fixed to be zero.\n");
+               intmem_usecount = 0;
+               omap_dsp_release_mem();
+       }
+}
+#endif /* CONFIG_ARCH_OMAP1 */
+
+/*
+ * dsp_mem file operations
+ */
+static loff_t dsp_mem_lseek(struct file *file, loff_t offset, int orig)
+{
+       loff_t ret;
+
+       mutex_lock(&file->f_dentry->d_inode->i_mutex);
+       switch (orig) {
+       case 0:
+               file->f_pos = offset;
+               ret = file->f_pos;
+               break;
+       case 1:
+               file->f_pos += offset;
+               ret = file->f_pos;
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+       return ret;
+}
+
+static ssize_t intmem_read(struct file *file, char __user *buf, size_t count,
+                          loff_t *ppos)
+{
+       unsigned long p = *ppos;
+       void *vadr = dspbyte_to_virt(p);
+       ssize_t size = dspmem_size;
+       ssize_t read;
+
+       if (p >= size)
+               return 0;
+#ifdef CONFIG_ARCH_OMAP1
+       clk_enable(api_ck_handle);
+#endif
+       read = count;
+       if (count > size - p)
+               read = size - p;
+       if (copy_to_user(buf, vadr, read)) {
+               read = -EFAULT;
+               goto out;
+       }
+       *ppos += read;
+out:
+#ifdef CONFIG_ARCH_OMAP1
+       clk_disable(api_ck_handle);
+#endif
+       return read;
+}
+
+static ssize_t exmem_read(struct file *file, char __user *buf, size_t count,
+                         loff_t *ppos)
+{
+       unsigned long p = *ppos;
+       void *vadr = dspbyte_to_virt(p);
+
+       if (!exmap_valid(vadr, count)) {
+               printk(KERN_ERR
+                      "omapdsp: DSP address %08lx / size %08x "
+                      "is not valid!\n", p, count);
+               return -EFAULT;
+       }
+       if (count > DSPSPACE_SIZE - p)
+               count = DSPSPACE_SIZE - p;
+       if (copy_to_user(buf, vadr, count))
+               return -EFAULT;
+       *ppos += count;
+
+       return count;
+}
+
+static ssize_t dsp_mem_read(struct file *file, char __user *buf, size_t count,
+                           loff_t *ppos)
+{
+       int ret;
+       void *vadr = dspbyte_to_virt(*(unsigned long *)ppos);
+
+       if (dsp_mem_enable(vadr) < 0)
+               return -EBUSY;
+       if (is_dspbyte_internal_mem(*ppos))
+               ret = intmem_read(file, buf, count, ppos);
+       else
+               ret = exmem_read(file, buf, count, ppos);
+       dsp_mem_disable(vadr);
+
+       return ret;
+}
+
+static ssize_t intmem_write(struct file *file, const char __user *buf,
+                           size_t count, loff_t *ppos)
+{
+       unsigned long p = *ppos;
+       void *vadr = dspbyte_to_virt(p);
+       ssize_t size = dspmem_size;
+       ssize_t written;
+
+       if (p >= size)
+               return 0;
+#ifdef CONFIG_ARCH_OMAP1
+       clk_enable(api_ck_handle);
+#endif
+       written = count;
+       if (count > size - p)
+               written = size - p;
+       if (copy_from_user(vadr, buf, written)) {
+               written = -EFAULT;
+               goto out;
+       }
+       *ppos += written;
+out:
+#ifdef CONFIG_ARCH_OMAP1
+       clk_disable(api_ck_handle);
+#endif
+       return written;
+}
+
+static ssize_t exmem_write(struct file *file, const char __user *buf,
+                          size_t count, loff_t *ppos)
+{
+       unsigned long p = *ppos;
+       void *vadr = dspbyte_to_virt(p);
+
+       if (!exmap_valid(vadr, count)) {
+               printk(KERN_ERR
+                      "omapdsp: DSP address %08lx / size %08x "
+                      "is not valid!\n", p, count);
+               return -EFAULT;
+       }
+       if (count > DSPSPACE_SIZE - p)
+               count = DSPSPACE_SIZE - p;
+       if (copy_from_user(vadr, buf, count))
+               return -EFAULT;
+       *ppos += count;
+
+       return count;
+}
+
+static ssize_t dsp_mem_write(struct file *file, const char __user *buf,
+                            size_t count, loff_t *ppos)
+{
+       int ret;
+       void *vadr = dspbyte_to_virt(*(unsigned long *)ppos);
+
+       if (dsp_mem_enable(vadr) < 0)
+               return -EBUSY;
+       if (is_dspbyte_internal_mem(*ppos))
+               ret = intmem_write(file, buf, count, ppos);
+       else
+               ret = exmem_write(file, buf, count, ppos);
+       dsp_mem_disable(vadr);
+
+       return ret;
+}
+
+static int dsp_mem_ioctl(struct inode *inode, struct file *file,
+                        unsigned int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case MEM_IOCTL_MMUINIT:
+               dsp_mmu_init();
+               return 0;
+
+       case MEM_IOCTL_EXMAP:
+               {
+                       struct omap_dsp_mapinfo mapinfo;
+                       if (copy_from_user(&mapinfo, (void __user *)arg,
+                                          sizeof(mapinfo)))
+                               return -EFAULT;
+                       return dsp_exmap(mapinfo.dspadr, 0, mapinfo.size,
+                                        EXMAP_TYPE_MEM);
+               }
+
+       case MEM_IOCTL_EXUNMAP:
+               return dsp_exunmap((unsigned long)arg);
+
+       case MEM_IOCTL_EXMAP_FLUSH:
+               exmap_flush();
+               return 0;
+
+       case MEM_IOCTL_FBEXPORT:
+               {
+                       dsp_long_t dspadr;
+                       int ret;
+                       if (copy_from_user(&dspadr, (void __user *)arg,
+                                          sizeof(dsp_long_t)))
+                               return -EFAULT;
+                       ret = dsp_fbexport(&dspadr);
+                       if (copy_to_user((void __user *)arg, &dspadr,
+                                        sizeof(dsp_long_t)))
+                               return -EFAULT;
+                       return ret;
+               }
+
+#ifdef CONFIG_ARCH_OMAP1
+       case MEM_IOCTL_MMUITACK:
+               return dsp_mmu_itack();
+#endif
+
+       case MEM_IOCTL_KMEM_RESERVE:
+               {
+                       __u32 size;
+                       if (copy_from_user(&size, (void __user *)arg,
+                                          sizeof(__u32)))
+                               return -EFAULT;
+                       return dsp_kmem_reserve(size);
+               }
+
+       case MEM_IOCTL_KMEM_RELEASE:
+               dsp_kmem_release();
+               return 0;
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+
+static int dsp_mem_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       /*
+        * FIXME
+        */
+       return -ENOSYS;
+}
+
+static int dsp_mem_open(struct inode *inode, struct file *file)
+{
+       if (!capable(CAP_SYS_RAWIO))
+               return -EPERM;
+
+       return 0;
+}
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+/*
+ * fb update functions:
+ * fbupd_response() is executed by the workqueue.
+ * fbupd_cb() is called when fb update is done, in interrupt context.
+ * mbox_fbupd() is called when KFUNC:FBCTL:UPD is received from DSP.
+ */
+static void fbupd_response(struct work_struct *unused)
+{
+       int status;
+
+       status = mbcompose_send(KFUNC, KFUNC_FBCTL, FBCTL_UPD);
+       if (status < 0) {
+               /* FIXME: DSP is busy !! */
+               printk(KERN_ERR
+                      "omapdsp: DSP is busy when trying to send FBCTL:UPD "
+                      "response!\n");
+       }
+}
+
+static DECLARE_WORK(fbupd_response_work, fbupd_response);
+
+static void fbupd_cb(void *arg)
+{
+       schedule_work(&fbupd_response_work);
+}
+
+void mbox_fbctl_upd(void)
+{
+       struct omapfb_update_window win;
+       volatile unsigned short *buf = ipbuf_sys_da->d;
+
+       /* FIXME: try count sometimes exceeds 1000. */
+       if (sync_with_dsp(&ipbuf_sys_da->s, TID_ANON, 5000) < 0) {
+               printk(KERN_ERR "mbox: FBCTL:UPD - IPBUF sync failed!\n");
+               return;
+       }
+       win.x = buf[0];
+       win.y = buf[1];
+       win.width = buf[2];
+       win.height = buf[3];
+       win.format = buf[4];
+       release_ipbuf_pvt(ipbuf_sys_da);
+
+       if (!omapfb_ready) {
+               printk(KERN_WARNING
+                      "omapdsp: fbupd() called while HWA742 is not ready!\n");
+               return;
+       }
+       //printk("calling omapfb_update_window_async()\n");
+       omapfb_update_window_async(registered_fb[0], &win, fbupd_cb, NULL);
+}
+
+#else /* CONFIG_FB_OMAP_LCDC_EXTERNAL */
+
+void mbox_fbctl_upd(void)
+{
+}
+#endif /* CONFIG_FB_OMAP_LCDC_EXTERNAL */
+
+/*
+ * sysfs files
+ */
+
+/* mmu */
+static ssize_t mmu_show(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       int len;
+       struct tlb_lock tlb_lock_org;
+       int i;
+
+#ifdef CONFIG_ARCH_OMAP1
+       clk_enable(dsp_ck_handle);
+       omap_dsp_request_mem();
+#endif
+       down_read(&exmap_sem);
+
+       get_tlb_lock(&tlb_lock_org);
+
+#if defined(CONFIG_ARCH_OMAP1)
+       len = sprintf(buf, "P: preserved, V: valid\n"
+                          "ety P V size   cam_va     ram_pa ap\n");
+                        /* 00: P V  4KB 0x300000 0x10171800 FA */
+#elif defined(CONFIG_ARCH_OMAP2)
+       len = sprintf(buf, "P: preserved, V: valid\n"
+                          "B: big endian, L:little endian, "
+                          "M: mixed page attribute\n"
+                          "ety P V size   cam_va     ram_pa E ES M\n");
+                        /* 00: P V  4KB 0x300000 0x10171800 B 16 M */
+#endif
+
+       for (i = 0; i < DSP_MMU_TLB_LINES; i++) {
+               struct cam_ram_regset cr;
+               struct tlb_lock tlb_lock_tmp;
+               struct tlb_entry ent;
+#if defined(CONFIG_ARCH_OMAP1)
+               char *pgsz_str, *ap_str;
+#elif defined(CONFIG_ARCH_OMAP2)
+               char *pgsz_str, *elsz_str;
+#endif
+
+               /* read a TLB entry */
+               tlb_lock_tmp.base   = tlb_lock_org.base;
+               tlb_lock_tmp.victim = i;
+               __read_tlb(&tlb_lock_tmp, &cr);
+
+#if defined(CONFIG_ARCH_OMAP1)
+               ent.pgsz  = cr.cam_l & DSP_MMU_CAM_PAGESIZE_MASK;
+               ent.prsvd = cr.cam_l & DSP_MMU_CAM_P;
+               ent.valid = cr.cam_l & DSP_MMU_CAM_V;
+               ent.ap    = cr.ram_l & DSP_MMU_RAM_L_AP_MASK;
+               ent.va = (u32)(cr.cam_h & DSP_MMU_CAM_H_VA_TAG_H_MASK) << 22 |
+                        (u32)(cr.cam_l & get_cam_l_va_mask(ent.pgsz)) << 6;
+               ent.pa = (unsigned long)cr.ram_h << 16 |
+                        (cr.ram_l & DSP_MMU_RAM_L_RAM_LSB_MASK);
+
+               pgsz_str = (ent.pgsz == DSP_MMU_CAM_PAGESIZE_1MB)  ? " 1MB":
+                          (ent.pgsz == DSP_MMU_CAM_PAGESIZE_64KB) ? "64KB":
+                          (ent.pgsz == DSP_MMU_CAM_PAGESIZE_4KB)  ? " 4KB":
+                          (ent.pgsz == DSP_MMU_CAM_PAGESIZE_1KB)  ? " 1KB":
+                                                                    " ???";
+               ap_str = (ent.ap == DSP_MMU_RAM_L_AP_RO) ? "RO":
+                        (ent.ap == DSP_MMU_RAM_L_AP_FA) ? "FA":
+                        (ent.ap == DSP_MMU_RAM_L_AP_NA) ? "NA":
+                                                          "??";
+#elif defined(CONFIG_ARCH_OMAP2)
+               ent.pgsz   = cr.cam & DSP_MMU_CAM_PAGESIZE_MASK;
+               ent.prsvd  = cr.cam & DSP_MMU_CAM_P;
+               ent.valid  = cr.cam & DSP_MMU_CAM_V;
+               ent.va     = cr.cam & DSP_MMU_CAM_VATAG_MASK;
+               ent.endian = cr.ram & DSP_MMU_RAM_ENDIANNESS;
+               ent.elsz   = cr.ram & DSP_MMU_RAM_ELEMENTSIZE_MASK;
+               ent.pa     = cr.ram & DSP_MMU_RAM_PADDR_MASK;
+               ent.mixed  = cr.ram & DSP_MMU_RAM_MIXED;
+
+               pgsz_str = (ent.pgsz == DSP_MMU_CAM_PAGESIZE_16MB) ? "64MB":
+                          (ent.pgsz == DSP_MMU_CAM_PAGESIZE_1MB)  ? " 1MB":
+                          (ent.pgsz == DSP_MMU_CAM_PAGESIZE_64KB) ? "64KB":
+                          (ent.pgsz == DSP_MMU_CAM_PAGESIZE_4KB)  ? " 4KB":
+                                                                    " ???";
+               elsz_str = (ent.elsz == DSP_MMU_RAM_ELEMENTSIZE_8)  ? " 8":
+                          (ent.elsz == DSP_MMU_RAM_ELEMENTSIZE_16) ? "16":
+                          (ent.elsz == DSP_MMU_RAM_ELEMENTSIZE_32) ? "32":
+                                                                     "??";
+#endif
+
+               if (i == tlb_lock_org.base)
+                       len += sprintf(buf + len, "lock base = %d\n",
+                                      tlb_lock_org.base);
+               if (i == tlb_lock_org.victim)
+                       len += sprintf(buf + len, "victim    = %d\n",
+                                      tlb_lock_org.victim);
+#if defined(CONFIG_ARCH_OMAP1)
+               len += sprintf(buf + len,
+                              /* 00: P V  4KB 0x300000 0x10171800 FA */
+                              "%02d: %c %c %s 0x%06x 0x%08lx %s\n",
+                              i,
+                              ent.prsvd ? 'P' : ' ',
+                              ent.valid ? 'V' : ' ',
+                              pgsz_str, ent.va, ent.pa, ap_str);
+#elif defined(CONFIG_ARCH_OMAP2)
+               len += sprintf(buf + len,
+                              /* 00: P V  4KB 0x300000 0x10171800 B 16 M */
+                              "%02d: %c %c %s 0x%06x 0x%08lx %c %s %c\n",
+                              i,
+                              ent.prsvd ? 'P' : ' ',
+                              ent.valid ? 'V' : ' ',
+                              pgsz_str, ent.va, ent.pa,
+                              ent.endian ? 'B' : 'L',
+                              elsz_str,
+                              ent.mixed ? 'M' : ' ');
+#endif /* CONFIG_ARCH_OMAP2 */
+       }
+
+       /* restore victim entry */
+       set_tlb_lock(&tlb_lock_org);
+
+       up_read(&exmap_sem);
+#ifdef CONFIG_ARCH_OMAP1
+       omap_dsp_release_mem();
+       clk_disable(dsp_ck_handle);
+#endif
+       return len;
+}
+
+/* exmap */
+static ssize_t exmap_show(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       int len;
+       int i;
+
+       down_read(&exmap_sem);
+       len = sprintf(buf, "  dspadr     size         buf     size uc\n");
+                        /* 0x300000 0x123000  0xc0171000 0x100000  0*/
+       for (i = 0; i < DSP_MMU_TLB_LINES; i++) {
+               struct exmap_tbl_entry *ent = &exmap_tbl[i];
+               void *vadr;
+               unsigned long size;
+               enum exmap_type_e type;
+               int idx;
+
+               /* find a top of link */
+               if (!ent->valid || (ent->link.prev >= 0))
+                       continue;
+
+               vadr = ent->vadr;
+               type = ent->type;
+               size = 0;
+               idx = i;
+               do {
+                       ent = &exmap_tbl[idx];
+                       size += PAGE_SIZE << ent->order;
+               } while ((idx = ent->link.next) >= 0);
+
+               len += sprintf(buf + len, "0x%06x %#8lx",
+                              virt_to_dspbyte(vadr), size);
+
+               if (type == EXMAP_TYPE_FB) {
+                       len += sprintf(buf + len, "    framebuf\n");
+               } else {
+                       len += sprintf(buf + len, "\n");
+                       idx = i;
+                       do {
+                               ent = &exmap_tbl[idx];
+                               len += sprintf(buf + len,
+                                              /* 0xc0171000 0x100000  0*/
+                                              "%19s0x%8p %#8lx %2d\n",
+                                              "", ent->buf,
+                                              PAGE_SIZE << ent->order,
+                                              ent->usecount);
+                       } while ((idx = ent->link.next) >= 0);
+               }
+       }
+
+       up_read(&exmap_sem);
+       return len;
+}
+
+/* mempool */
+static ssize_t mempool_show(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       int min_nr_1M = 0, curr_nr_1M = 0;
+       int min_nr_64K = 0, curr_nr_64K = 0;
+       int total = 0;
+
+       if (likely(kmem_pool_1M)) {
+               min_nr_1M  = kmem_pool_1M->min_nr;
+               curr_nr_1M = kmem_pool_1M->curr_nr;
+               total += min_nr_1M * SZ_1MB;
+       }
+       if (likely(kmem_pool_64K)) {
+               min_nr_64K  = kmem_pool_64K->min_nr;
+               curr_nr_64K = kmem_pool_64K->curr_nr;
+               total += min_nr_64K * SZ_64KB;
+       }
+
+       return sprintf(buf,
+                      "0x%x\n"
+                      "1M  buffer: %d (%d free)\n"
+                      "64K buffer: %d (%d free)\n",
+                      total, min_nr_1M, curr_nr_1M, min_nr_64K, curr_nr_64K);
+}
+
+/*
+ * workqueue for mmu int
+ */
+#ifdef CONFIG_ARCH_OMAP1
+/*
+ * MMU fault mask:
+ * We ignore prefetch err.
+ */
+#define MMUFAULT_MASK \
+       (DSP_MMU_FAULT_ST_PERM |\
+        DSP_MMU_FAULT_ST_TLB_MISS |\
+        DSP_MMU_FAULT_ST_TRANS)
+#endif /* CONFIG_ARCH_OMAP1 */
+
+static void do_mmu_int(struct work_struct *unused)
+{
+#if defined(CONFIG_ARCH_OMAP1)
+
+       dsp_mmu_reg_t status;
+       dsp_mmu_reg_t adh, adl;
+       dsp_mmu_reg_t dp;
+
+       status = dsp_mmu_read_reg(DSP_MMU_FAULT_ST);
+       adh = dsp_mmu_read_reg(DSP_MMU_FAULT_AD_H);
+       adl = dsp_mmu_read_reg(DSP_MMU_FAULT_AD_L);
+       dp = adh & DSP_MMU_FAULT_AD_H_DP;
+       dsp_fault_adr = MK32(adh & DSP_MMU_FAULT_AD_H_ADR_MASK, adl);
+
+       /* if the fault is masked, nothing to do */
+       if ((status & MMUFAULT_MASK) == 0) {
+               printk(KERN_DEBUG "DSP MMU interrupt, but ignoring.\n");
+               /*
+                * note: in OMAP1710,
+                * when CACHE + DMA domain gets out of idle in DSP,
+                * MMU interrupt occurs but DSP_MMU_FAULT_ST is not set.
+                * in this case, we just ignore the interrupt.
+                */
+               if (status) {
+                       printk(KERN_DEBUG "%s%s%s%s\n",
+                              (status & DSP_MMU_FAULT_ST_PREF)?
+                                       "  (prefetch err)" : "",
+                              (status & DSP_MMU_FAULT_ST_PERM)?
+                                       "  (permission fault)" : "",
+                              (status & DSP_MMU_FAULT_ST_TLB_MISS)?
+                                       "  (TLB miss)" : "",
+                              (status & DSP_MMU_FAULT_ST_TRANS) ?
+                                       "  (translation fault)": "");
+                       printk(KERN_DEBUG "fault address = %#08x\n",
+                              dsp_fault_adr);
+               }
+               enable_irq(omap_dsp->mmu_irq);
+               return;
+       }
+
+#elif defined(CONFIG_ARCH_OMAP2)
+
+       dsp_mmu_reg_t status;
+
+       status = dsp_mmu_read_reg(DSP_MMU_IRQSTATUS);
+       dsp_fault_adr = dsp_mmu_read_reg(DSP_MMU_FAULT_AD);
+
+#endif /* CONFIG_ARCH_OMAP2 */
+
+       printk(KERN_INFO "DSP MMU interrupt!\n");
+
+#if defined(CONFIG_ARCH_OMAP1)
+
+       printk(KERN_INFO "%s%s%s%s\n",
+              (status & DSP_MMU_FAULT_ST_PREF)?
+                       (MMUFAULT_MASK & DSP_MMU_FAULT_ST_PREF)?
+                               "  prefetch err":
+                               "  (prefetch err)":
+                               "",
+              (status & DSP_MMU_FAULT_ST_PERM)?
+                       (MMUFAULT_MASK & DSP_MMU_FAULT_ST_PERM)?
+                               "  permission fault":
+                               "  (permission fault)":
+                               "",
+              (status & DSP_MMU_FAULT_ST_TLB_MISS)?
+                       (MMUFAULT_MASK & DSP_MMU_FAULT_ST_TLB_MISS)?
+                               "  TLB miss":
+                               "  (TLB miss)":
+                               "",
+              (status & DSP_MMU_FAULT_ST_TRANS)?
+                       (MMUFAULT_MASK & DSP_MMU_FAULT_ST_TRANS)?
+                               "  translation fault":
+                               "  (translation fault)":
+                               "");
+
+#elif defined(CONFIG_ARCH_OMAP2)
+
+       printk(KERN_INFO "%s%s%s%s%s\n",
+              (status & DSP_MMU_IRQ_MULTIHITFAULT)?
+                       (MMU_IRQ_MASK & DSP_MMU_IRQ_MULTIHITFAULT)?
+                               "  multi hit":
+                               "  (multi hit)":
+                               "",
+              (status & DSP_MMU_IRQ_TABLEWALKFAULT)?
+                       (MMU_IRQ_MASK & DSP_MMU_IRQ_TABLEWALKFAULT)?
+                               "  table walk fault":
+                               "  (table walk fault)":
+                               "",
+              (status & DSP_MMU_IRQ_EMUMISS)?
+                       (MMU_IRQ_MASK & DSP_MMU_IRQ_EMUMISS)?
+                               "  EMU miss":
+                               "  (EMU miss)":
+                               "",
+              (status & DSP_MMU_IRQ_TRANSLATIONFAULT)?
+                       (MMU_IRQ_MASK & DSP_MMU_IRQ_TRANSLATIONFAULT)?
+                               "  translation fault":
+                               "  (translation fault)":
+                               "",
+              (status & DSP_MMU_IRQ_TLBMISS)?
+                       (MMU_IRQ_MASK & DSP_MMU_IRQ_TLBMISS)?
+                               "  TLB miss":
+                               "  (TLB miss)":
+                               "");
+
+#endif /* CONFIG_ARCH_OMAP2 */
+
+       printk(KERN_INFO "fault address = %#08x\n", dsp_fault_adr);
+
+       if (dsp_cfgstat_get_stat() == CFGSTAT_READY)
+               dsp_err_set(ERRCODE_MMU, (unsigned long)dsp_fault_adr);
+       else {
+#ifdef CONFIG_ARCH_OMAP1
+               __dsp_mmu_itack();
+#endif
+               printk(KERN_INFO "Resetting DSP...\n");
+               dsp_cpustat_request(CPUSTAT_RESET);
+               /*
+                * if we enable followings, semaphore lock should be avoided.
+                *
+               printk(KERN_INFO "Flushing DSP MMU...\n");
+               exmap_flush();
+               dsp_mmu_init();
+                */
+       }
+
+#ifdef CONFIG_ARCH_OMAP2
+       dsp_mmu_disable();
+       dsp_mmu_write_reg(status, DSP_MMU_IRQSTATUS);
+       dsp_mmu_enable();
+#endif
+
+       enable_irq(omap_dsp->mmu_irq);
+}
+
+static DECLARE_WORK(mmu_int_work, do_mmu_int);
+
+/*
+ * DSP MMU interrupt handler
+ */
+
+static irqreturn_t dsp_mmu_interrupt(int irq, void *dev_id)
+{
+       disable_irq(omap_dsp->mmu_irq);
+       schedule_work(&mmu_int_work);
+       return IRQ_HANDLED;
+}
+
+/*
+ *
+ */
+struct file_operations dsp_mem_fops = {
+       .owner   = THIS_MODULE,
+       .llseek  = dsp_mem_lseek,
+       .read    = dsp_mem_read,
+       .write   = dsp_mem_write,
+       .ioctl   = dsp_mem_ioctl,
+       .mmap    = dsp_mem_mmap,
+       .open    = dsp_mem_open,
+};
+
+void dsp_mem_start(void)
+{
+#ifdef CONFIG_ARCH_OMAP1
+       dsp_register_mem_cb(intmem_enable, intmem_disable);
+#endif
+}
+
+void dsp_mem_stop(void)
+{
+       memset(&mem_sync, 0, sizeof(struct mem_sync_struct));
+#ifdef CONFIG_ARCH_OMAP1
+       dsp_unregister_mem_cb();
+#endif
+}
+
+/*
+ * later half of dsp memory initialization
+ */
+void dsp_mem_late_init(void)
+{
+#ifdef CONFIG_ARCH_OMAP2
+       int i;
+       int dspmem_pg_count;
+
+       dspmem_pg_count = dspmem_size >> 12;
+       for (i = 0; i < dspmem_pg_count; i++) {
+               dsp_ipi_write_reg(i, DSP_IPI_INDEX);
+               dsp_ipi_write_reg(DSP_IPI_ENTRY_ELMSIZEVALUE_16,
+                                 DSP_IPI_ENTRY);
+       }
+       dsp_ipi_write_reg(1, DSP_IPI_ENABLE);
+       dsp_ipi_write_reg(IOMAP_VAL, DSP_IPI_IOMAP);
+#endif
+       dsp_mmu_init();
+}
+
+static char devid_mmu;
+
+int __init dsp_mem_init(void)
+{
+       int i, ret;
+
+       for (i = 0; i < DSP_MMU_TLB_LINES; i++)
+               exmap_tbl[i].valid = 0;
+
+       dspvect_page = (void *)__get_dma_pages(GFP_KERNEL, 0);
+       if (dspvect_page == NULL) {
+               printk(KERN_ERR
+                      "omapdsp: failed to allocate memory "
+                      "for dsp vector table\n");
+               return -ENOMEM;
+       }
+
+       /*
+        * DSP MMU interrupt setup
+        */
+       ret = request_irq(omap_dsp->mmu_irq, dsp_mmu_interrupt, IRQF_DISABLED,
+                         "dsp_mmu",  &devid_mmu);
+       if (ret) {
+               printk(KERN_ERR
+                      "failed to register DSP MMU interrupt: %d\n", ret);
+               return ret;
+       }
+
+       /* MMU interrupt is not enabled until DSP runs */
+       disable_irq(omap_dsp->mmu_irq);
+
+       ret = device_create_file(omap_dsp->dev, &dev_attr_mmu);
+       ret |= device_create_file(omap_dsp->dev, &dev_attr_exmap);
+       ret |= device_create_file(omap_dsp->dev, &dev_attr_mempool);
+       if (ret)
+               printk(KERN_ERR "device_create_file failed: %d\n", ret);
+
+       return 0;
+}
+
+void dsp_mem_exit(void)
+{
+       free_irq(omap_dsp->mmu_irq, &devid_mmu);
+
+       /* recover disable_depth */
+       enable_irq(omap_dsp->mmu_irq);
+
+#ifdef CONFIG_ARCH_OMAP1
+       dsp_reset_idle_boot_base();
+#endif
+       dsp_mmu_shutdown();
+       dsp_kmem_release();
+
+       if (dspvect_page != NULL) {
+               free_page((unsigned long)dspvect_page);
+               dspvect_page = NULL;
+       }
+
+       device_remove_file(omap_dsp->dev, &dev_attr_mmu);
+       device_remove_file(omap_dsp->dev, &dev_attr_exmap);
+       device_remove_file(omap_dsp->dev, &dev_attr_mempool);
+}
diff --git a/arch/arm/plat-omap/dsp/error.c b/arch/arm/plat-omap/dsp/error.c
new file mode 100644 (file)
index 0000000..dc831ce
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+
+/*
+ * value seen through read()
+ */
+#define DSP_ERR_WDT    0x00000001
+#define DSP_ERR_MMU    0x00000002
+static unsigned long errval;
+
+static DECLARE_WAIT_QUEUE_HEAD(err_wait_q);
+static int errcnt;
+static u16 wdtval;     /* FIXME: read through ioctl */
+static u32 mmu_fadr;   /* FIXME: read through ioctl */
+
+/*
+ * DSP error detection device file operations
+ */
+static ssize_t dsp_err_read(struct file *file, char __user *buf, size_t count,
+                           loff_t *ppos)
+{
+       unsigned long flags;
+       int status;
+
+       if (count < 4)
+               return 0;
+
+       if (errcnt == 0) {
+               long current_state;
+               DECLARE_WAITQUEUE(wait, current);
+
+               add_wait_queue(&err_wait_q, &wait);
+               current_state = current->state;
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (errcnt == 0)        /* last check */
+                       schedule();
+               set_current_state(current_state);
+               remove_wait_queue(&err_wait_q, &wait);
+               if (signal_pending(current))
+                       return -EINTR;
+       }
+
+       local_irq_save(flags);
+       status = copy_to_user(buf, &errval, 4);
+       if (status) {
+               local_irq_restore(flags);
+               return -EFAULT;
+       }
+       errcnt = 0;
+       local_irq_restore(flags);
+
+       return 4;
+}
+
+static unsigned int dsp_err_poll(struct file *file, poll_table *wait)
+{
+       unsigned int mask = 0;
+
+       poll_wait(file, &err_wait_q, wait);
+       if (errcnt != 0)
+               mask |= POLLIN | POLLRDNORM;
+
+       return mask;
+}
+
+struct file_operations dsp_err_fops = {
+       .owner = THIS_MODULE,
+       .poll  = dsp_err_poll,
+       .read  = dsp_err_read,
+};
+
+/*
+ * set / clear functions
+ */
+
+/* DSP MMU */
+static void dsp_err_mmu_set(unsigned long arg)
+{
+       disable_irq(omap_dsp->mmu_irq);
+       mmu_fadr = (u32)arg;
+}
+
+static void dsp_err_mmu_clr(void)
+{
+       enable_irq(omap_dsp->mmu_irq);
+}
+
+/* WDT */
+static void dsp_err_wdt_set(unsigned long arg)
+{
+       wdtval = (u16)arg;
+}
+
+/*
+ * error code handler
+ */
+static struct {
+       unsigned long val;
+       void (*set)(unsigned long arg);
+       void (*clr)(void);
+} dsp_err_desc[ERRCODE_MAX] = {
+       [ERRCODE_MMU] = { DSP_ERR_MMU, dsp_err_mmu_set, dsp_err_mmu_clr },
+       [ERRCODE_WDT] = { DSP_ERR_WDT, dsp_err_wdt_set, NULL },
+};
+
+void dsp_err_set(enum errcode_e code, unsigned long arg)
+{
+       if (dsp_err_desc[code].set != NULL)
+               dsp_err_desc[code].set(arg);
+
+       errval |= dsp_err_desc[code].val;
+       errcnt++;
+       wake_up_interruptible(&err_wait_q);
+}
+
+void dsp_err_clear(enum errcode_e code)
+{
+       errval &= ~dsp_err_desc[code].val;
+
+       if (dsp_err_desc[code].clr != NULL)
+               dsp_err_desc[code].clr();
+}
+
+int dsp_err_isset(enum errcode_e code)
+{
+       return (errval & dsp_err_desc[code].val) ? 1 : 0;
+}
+
+/*
+ * functions called from mailbox interrupt routine
+ */
+static void mbox_err_wdt(u16 data)
+{
+       dsp_err_set(DSP_ERR_WDT, (unsigned long)data);
+}
+
+#ifdef OLD_BINARY_SUPPORT
+/* v3.3 obsolete */
+void mbox_wdt(struct mbcmd *mb)
+{
+       mbox_err_wdt(mb->data);
+}
+#endif
+
+extern void mbox_err_ipbfull(void);
+extern void mbox_err_fatal(u8 tid);
+
+void mbox_err(struct mbcmd *mb)
+{
+       u8 eid = mb->cmd_l;
+       char *eidnm = subcmd_name(mb);
+       u8 tid;
+
+       if (eidnm) {
+               printk(KERN_WARNING
+                      "mbox: ERR from DSP (%s): 0x%04x\n", eidnm, mb->data);
+       } else {
+               printk(KERN_WARNING
+                      "mbox: ERR from DSP (unknown EID=%02x): %04x\n",
+                      eid, mb->data);
+       }
+
+       switch (eid) {
+       case EID_IPBFULL:
+               mbox_err_ipbfull();
+               break;
+
+       case EID_FATAL:
+               tid = mb->data & 0x00ff;
+               mbox_err_fatal(tid);
+               break;
+
+       case EID_WDT:
+               mbox_err_wdt(mb->data);
+               break;
+       }
+}
+
+/*
+ *
+ */
+void dsp_err_start(void)
+{
+       enum errcode_e i;
+
+       for (i = 0; i < ERRCODE_MAX; i++) {
+               if (dsp_err_isset(i))
+                       dsp_err_clear(i);
+       }
+
+       errcnt = 0;
+}
+
+void dsp_err_stop(void)
+{
+       wake_up_interruptible(&err_wait_q);
+}
diff --git a/arch/arm/plat-omap/dsp/fifo.h b/arch/arm/plat-omap/dsp/fifo.h
new file mode 100644 (file)
index 0000000..3a79867
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+struct fifo_struct {
+       spinlock_t lock;
+       char *buf;
+       size_t sz;
+       size_t cnt;
+       unsigned int wp;
+};
+
+static inline int alloc_fifo(struct fifo_struct *fifo, size_t sz)
+{
+       if ((fifo->buf = kmalloc(sz, GFP_KERNEL)) == NULL) {
+               fifo->sz = 0;
+               return -ENOMEM;
+       }
+       fifo->sz = sz;
+       fifo->cnt = 0;
+       fifo->wp = 0;
+       return 0;
+}
+
+static inline int init_fifo(struct fifo_struct *fifo, size_t sz)
+{
+       spin_lock_init(&fifo->lock);
+       return alloc_fifo(fifo, sz);
+}
+
+static inline void free_fifo(struct fifo_struct *fifo)
+{
+       spin_lock(&fifo->lock);
+       if (fifo->buf == NULL) {
+               spin_unlock(&fifo->lock);
+               return;
+       }
+
+       kfree(fifo->buf);
+       fifo->buf = NULL;
+       fifo->sz = 0;
+       spin_unlock(&fifo->lock);
+}
+
+static inline void flush_fifo(struct fifo_struct *fifo)
+{
+       spin_lock(&fifo->lock);
+       fifo->cnt = 0;
+       fifo->wp = 0;
+       spin_unlock(&fifo->lock);
+}
+
+#define fifo_empty(fifo)       ((fifo)->cnt == 0)
+
+static inline int realloc_fifo(struct fifo_struct *fifo, size_t sz)
+{
+       int ret = sz;
+
+       spin_lock(&fifo->lock);
+       if (!fifo_empty(fifo)) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       /* free */
+       if (fifo->buf)
+               kfree(fifo->buf);
+
+       /* alloc */
+       ret = alloc_fifo(fifo, sz);
+
+out:
+       spin_unlock(&fifo->lock);
+       return ret;
+}
+
+static inline void write_word_to_fifo(struct fifo_struct *fifo, u16 word)
+{
+       spin_lock(&fifo->lock);
+       *(u16 *)&fifo->buf[fifo->wp] = word;
+       if ((fifo->wp += 2) == fifo->sz)
+               fifo->wp = 0;
+       if ((fifo->cnt += 2) > fifo->sz)
+               fifo->cnt = fifo->sz;
+       spin_unlock(&fifo->lock);
+}
+
+/*
+ * (before)
+ *
+ * [*******----------*************]
+ *         ^wp
+ *  <---------------------------->  sz = 30
+ *  <----->          <----------->  cnt = 20
+ *
+ * (read: count=16)
+ *  <->              <----------->  count = 16
+ *                   <----------->  cnt1 = 13
+ *                   ^rp
+ *
+ * (after)
+ * [---****-----------------------]
+ *         ^wp
+ */
+static inline ssize_t copy_to_user_fm_fifo(char *dst, struct fifo_struct *fifo,
+                                          size_t count)
+{
+       int rp;
+       ssize_t ret;
+
+       /* fifo size can be zero */
+       if (fifo->sz == 0)
+               return 0;
+
+       spin_lock(&fifo->lock);
+       if (count > fifo->cnt)
+               count = fifo->cnt;
+
+       if ((rp = fifo->wp - fifo->cnt) >= 0) {
+               /* valid area is straight */
+               if (copy_to_user(dst, &fifo->buf[rp], count)) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+       } else {
+               int cnt1 = -rp;
+               rp += fifo->sz;
+               if (cnt1 >= count) {
+                       /* requested area is straight */
+                       if (copy_to_user(dst, &fifo->buf[rp], count)) {
+                               ret = -EFAULT;
+                               goto out;
+                       }
+               } else {
+                       if (copy_to_user(dst, &fifo->buf[rp], cnt1)) {
+                               ret = -EFAULT;
+                               goto out;
+                       }
+                       if (copy_to_user(dst+cnt1, fifo->buf, count-cnt1)) {
+                               ret = -EFAULT;
+                               goto out;
+                       }
+               }
+       }
+       fifo->cnt -= count;
+       ret = count;
+
+out:
+       spin_unlock(&fifo->lock);
+       return ret;
+}
diff --git a/arch/arm/plat-omap/dsp/ioctl.h b/arch/arm/plat-omap/dsp/ioctl.h
new file mode 100644 (file)
index 0000000..27e8358
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/*
+ * for /dev/dspctl/ctl
+ */
+#define DSPCTL_IOCTL_RESET             1
+#define DSPCTL_IOCTL_RUN               2
+#define DSPCTL_IOCTL_SETRSTVECT                3
+#ifdef CONFIG_ARCH_OMAP1
+#define DSPCTL_IOCTL_CPU_IDLE          4
+#define DSPCTL_IOCTL_MPUI_WORDSWAP_ON  5
+#define DSPCTL_IOCTL_MPUI_WORDSWAP_OFF 6
+#define DSPCTL_IOCTL_MPUI_BYTESWAP_ON  7
+#define DSPCTL_IOCTL_MPUI_BYTESWAP_OFF 8
+#define DSPCTL_IOCTL_GBL_IDLE          9
+#endif /* CONFIG_ARCH_OMAP1 */
+#define DSPCTL_IOCTL_DSPCFG            10
+#define DSPCTL_IOCTL_DSPUNCFG          11
+#define DSPCTL_IOCTL_TASKCNT           12
+#define DSPCTL_IOCTL_POLL              13
+#define DSPCTL_IOCTL_REGMEMR           40
+#define DSPCTL_IOCTL_REGMEMW           41
+#define DSPCTL_IOCTL_REGIOR            42
+#define DSPCTL_IOCTL_REGIOW            43
+#define DSPCTL_IOCTL_GETVAR            44
+#define DSPCTL_IOCTL_SETVAR            45
+#define DSPCTL_IOCTL_RUNLEVEL          50
+#define DSPCTL_IOCTL_SUSPEND           51
+#define DSPCTL_IOCTL_RESUME            52
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+#define DSPCTL_IOCTL_FBEN              53
+#define DSPCTL_IOCTL_FBDIS             54
+#endif /* CONFIG_OMAP_DSP_FBEXPORT */
+#define DSPCTL_IOCTL_MBSEND            99
+
+struct omap_dsp_mailbox_cmd {
+       __u16 cmd;
+       __u16 data;
+};
+
+struct omap_dsp_reginfo {
+       __u16 adr;
+       __u16 val;
+};
+
+struct omap_dsp_varinfo {
+       __u8 varid;
+       __u16 val[0];
+};
+
+/*
+ * for taskdev
+ * (ioctls below should be >= 0x10000)
+ */
+#define TASK_IOCTL_BFLSH       0x10000
+#define TASK_IOCTL_SETBSZ      0x10001
+#define TASK_IOCTL_LOCK                0x10002
+#define TASK_IOCTL_UNLOCK      0x10003
+#define TASK_IOCTL_GETNAME     0x10004
+
+/*
+ * for /dev/dspctl/mem
+ */
+#define MEM_IOCTL_EXMAP                1
+#define MEM_IOCTL_EXUNMAP      2
+#define MEM_IOCTL_EXMAP_FLUSH  3
+#define MEM_IOCTL_FBEXPORT     5
+#ifdef CONFIG_ARCH_OMAP1
+#define MEM_IOCTL_MMUITACK     7
+#endif
+#define MEM_IOCTL_MMUINIT      9
+#define MEM_IOCTL_KMEM_RESERVE 11
+#define MEM_IOCTL_KMEM_RELEASE 12
+
+struct omap_dsp_mapinfo {
+       __u32 dspadr;
+       __u32 size;
+};
+
+/*
+ * for /dev/dspctl/twch
+ */
+#define TWCH_IOCTL_MKDEV       1
+#define TWCH_IOCTL_RMDEV       2
+#define TWCH_IOCTL_TADD                11
+#define TWCH_IOCTL_TDEL                12
+#define TWCH_IOCTL_TKILL       13
+
+struct omap_dsp_taddinfo {
+       __u8 minor;
+       __u32 taskadr;
+};
+
+#define TADD_ABORTADR  0xffffffff
diff --git a/arch/arm/plat-omap/dsp/ipbuf.c b/arch/arm/plat-omap/dsp/ipbuf.c
new file mode 100644 (file)
index 0000000..943943b
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <asm/arch/mailbox.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.h"
+
+static struct ipbuf_head *g_ipbuf;
+struct ipbcfg ipbcfg;
+struct ipbuf_sys *ipbuf_sys_da, *ipbuf_sys_ad;
+static struct ipblink ipb_free = IPBLINK_INIT;
+static int ipbuf_sys_hold_mem_active;
+
+static ssize_t ipbuf_show(struct device *dev, struct device_attribute *attr,
+                         char *buf);
+static struct device_attribute dev_attr_ipbuf = __ATTR_RO(ipbuf);
+
+void ipbuf_stop(void)
+{
+       int i;
+
+       device_remove_file(omap_dsp->dev, &dev_attr_ipbuf);
+
+       spin_lock(&ipb_free.lock);
+       RESET_IPBLINK(&ipb_free);
+       spin_unlock(&ipb_free.lock);
+
+       ipbcfg.ln = 0;
+       if (g_ipbuf) {
+               kfree(g_ipbuf);
+               g_ipbuf = NULL;
+       }
+       for (i = 0; i < ipbuf_sys_hold_mem_active; i++) {
+               dsp_mem_disable((void *)daram_base);
+       }
+       ipbuf_sys_hold_mem_active = 0;
+}
+
+int ipbuf_config(u16 ln, u16 lsz, void *base)
+{
+       size_t lsz_byte = ((size_t)lsz) << 1;
+       size_t size;
+       int ret = 0;
+       int i;
+
+       /*
+        * global IPBUF
+        */
+       if (((unsigned long)base) & 0x3) {
+               printk(KERN_ERR
+                      "omapdsp: global ipbuf address(0x%p) is not "
+                      "32-bit aligned!\n", base);
+               return -EINVAL;
+       }
+       size = lsz_byte * ln;
+       if (dsp_address_validate(base, size, "global ipbuf") < 0)
+               return -EINVAL;
+
+       g_ipbuf = kmalloc(sizeof(struct ipbuf_head) * ln, GFP_KERNEL);
+       if (g_ipbuf == NULL) {
+               printk(KERN_ERR
+                      "omapdsp: memory allocation for ipbuf failed.\n");
+               return -ENOMEM;
+       }
+       for (i = 0; i < ln; i++) {
+               void *top, *btm;
+
+               top = base + (sizeof(struct ipbuf) + lsz_byte) * i;
+               btm = base + (sizeof(struct ipbuf) + lsz_byte) * (i+1) - 1;
+               g_ipbuf[i].p = (struct ipbuf *)top;
+               g_ipbuf[i].bid = i;
+               if (((unsigned long)top & 0xfffe0000) !=
+                   ((unsigned long)btm & 0xfffe0000)) {
+                       /*
+                        * an ipbuf line should not cross
+                        * 64k-word boundary.
+                        */
+                       printk(KERN_ERR
+                              "omapdsp: ipbuf[%d] crosses 64k-word boundary!\n"
+                              "  @0x%p, size=0x%08x\n", i, top, lsz_byte);
+                       ret = -EINVAL;
+                       goto free_out;
+               }
+       }
+       ipbcfg.ln       = ln;
+       ipbcfg.lsz      = lsz;
+       ipbcfg.base     = base;
+       ipbcfg.bsycnt   = ln;   /* DSP holds all ipbufs initially. */
+       ipbcfg.cnt_full = 0;
+
+       printk(KERN_INFO
+              "omapdsp: IPBUF configuration\n"
+              "           %d words * %d lines at 0x%p.\n",
+              ipbcfg.lsz, ipbcfg.ln, ipbcfg.base);
+
+       ret = device_create_file(omap_dsp->dev, &dev_attr_ipbuf);
+       if (ret)
+               printk(KERN_ERR "device_create_file failed: %d\n", ret);
+
+       return ret;
+
+free_out:
+       kfree(g_ipbuf);
+       g_ipbuf = NULL;
+       return ret;
+}
+
+int ipbuf_sys_config(void *p, arm_dsp_dir_t dir)
+{
+       char *dir_str = (dir == DIR_D2A) ? "D2A" : "A2D";
+
+       if (((unsigned long)p) & 0x3) {
+               printk(KERN_ERR
+                      "omapdsp: system ipbuf(%s) address(0x%p) is "
+                      "not 32-bit aligned!\n", dir_str, p);
+               return -1;
+       }
+       if (dsp_address_validate(p, sizeof(struct ipbuf_sys),
+                                "system ipbuf(%s)", dir_str) < 0)
+               return -1;
+       if (dsp_mem_type(p, sizeof(struct ipbuf_sys)) != MEM_TYPE_EXTERN) {
+               printk(KERN_WARNING
+                      "omapdsp: system ipbuf(%s) is placed in"
+                      " DSP internal memory.\n"
+                      "         It will prevent DSP from idling.\n", dir_str);
+               ipbuf_sys_hold_mem_active++;
+               /*
+                * dsp_mem_enable() never fails because
+                * it has been already enabled in dspcfg process and
+                * this will just increment the usecount.
+                */
+               dsp_mem_enable((void *)daram_base);
+       }
+
+       if (dir == DIR_D2A)
+               ipbuf_sys_da = p;
+       else
+               ipbuf_sys_ad = p;
+
+       return 0;
+}
+
+int ipbuf_p_validate(void *p, arm_dsp_dir_t dir)
+{
+       char *dir_str = (dir == DIR_D2A) ? "D2A" : "A2D";
+
+       if (((unsigned long)p) & 0x3) {
+               printk(KERN_ERR
+                      "omapdsp: private ipbuf(%s) address(0x%p) is "
+                      "not 32-bit aligned!\n", dir_str, p);
+               return -1;
+       }
+       return dsp_address_validate(p, sizeof(struct ipbuf_p),
+                                   "private ipbuf(%s)", dir_str);
+}
+
+/*
+ * Global IPBUF operations
+ */
+struct ipbuf_head *bid_to_ipbuf(u16 bid)
+{
+       return &g_ipbuf[bid];
+}
+
+struct ipbuf_head *get_free_ipbuf(u8 tid)
+{
+       struct ipbuf_head *ipb_h;
+
+       if (dsp_mem_enable_ipbuf() < 0)
+               return NULL;
+
+       spin_lock(&ipb_free.lock);
+
+       if (ipblink_empty(&ipb_free)) {
+               /* FIXME: wait on queue when not available.  */
+               ipb_h = NULL;
+               goto out;
+       }
+       ipb_h = &g_ipbuf[ipb_free.top];
+       ipb_h->p->la = tid;     /* lock */
+       __ipblink_del_top(&ipb_free);
+out:
+       spin_unlock(&ipb_free.lock);
+       dsp_mem_disable_ipbuf();
+
+       return ipb_h;
+}
+
+void release_ipbuf(struct ipbuf_head *ipb_h)
+{
+       if (ipb_h->p->la == TID_FREE) {
+               printk(KERN_WARNING
+                      "omapdsp: attempt to release unlocked IPBUF[%d].\n",
+                      ipb_h->bid);
+               /*
+                * FIXME: re-calc bsycnt
+                */
+               return;
+       }
+       ipb_h->p->la = TID_FREE;
+       ipb_h->p->sa = TID_FREE;
+       ipblink_add_tail(&ipb_free, ipb_h->bid);
+}
+
+static int try_yld(struct ipbuf_head *ipb_h)
+{
+       int status;
+
+       ipb_h->p->sa = TID_ANON;
+       status = mbcompose_send(BKYLD, 0, ipb_h->bid);
+       if (status < 0) {
+               /* DSP is busy and ARM keeps this line. */
+               release_ipbuf(ipb_h);
+               return status;
+       }
+
+       ipb_bsycnt_inc(&ipbcfg);
+       return 0;
+}
+
+/*
+ * balancing ipbuf lines with DSP
+ */
+static void do_balance_ipbuf(struct work_struct *unused)
+{
+       while (ipbcfg.bsycnt <= ipbcfg.ln / 4) {
+               struct ipbuf_head *ipb_h;
+
+               if ((ipb_h = get_free_ipbuf(TID_ANON)) == NULL)
+                       return;
+               if (try_yld(ipb_h) < 0)
+                       return;
+       }
+}
+
+static DECLARE_WORK(balance_ipbuf_work, do_balance_ipbuf);
+
+void balance_ipbuf(void)
+{
+       schedule_work(&balance_ipbuf_work);
+}
+
+/* for process context */
+void unuse_ipbuf(struct ipbuf_head *ipb_h)
+{
+       if (ipbcfg.bsycnt > ipbcfg.ln / 4) {
+               /* we don't have enough IPBUF lines. let's keep it. */
+               release_ipbuf(ipb_h);
+       } else {
+               /* we have enough IPBUF lines. let's return this line to DSP. */
+               ipb_h->p->la = TID_ANON;
+               try_yld(ipb_h);
+               balance_ipbuf();
+       }
+}
+
+/* for interrupt context */
+void unuse_ipbuf_nowait(struct ipbuf_head *ipb_h)
+{
+       release_ipbuf(ipb_h);
+       balance_ipbuf();
+}
+
+/*
+ * functions called from mailbox interrupt routine
+ */
+
+void mbox_err_ipbfull(void)
+{
+       ipbcfg.cnt_full++;
+}
+
+/*
+ * sysfs files
+ */
+static ssize_t ipbuf_show(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       int len = 0;
+       u16 bid;
+
+       for (bid = 0; bid < ipbcfg.ln; bid++) {
+               struct ipbuf_head *ipb_h = &g_ipbuf[bid];
+               u16 la = ipb_h->p->la;
+               u16 ld = ipb_h->p->ld;
+               u16 c  = ipb_h->p->c;
+
+               if (len > PAGE_SIZE - 100) {
+                       len += sprintf(buf + len, "out of buffer.\n");
+                       goto finish;
+               }
+
+               len += sprintf(buf + len, "ipbuf[%d]: adr = 0x%p\n",
+                              bid, ipb_h->p);
+               if (la == TID_FREE) {
+                       len += sprintf(buf + len,
+                                      "  DSPtask[%d]->Linux "
+                                      "(already read and now free for Linux)\n",
+                                      ld);
+               } else if (ld == TID_FREE) {
+                       len += sprintf(buf + len,
+                                      "  Linux->DSPtask[%d] "
+                                      "(already read and now free for DSP)\n",
+                                      la);
+               } else if (ipbuf_is_held(ld, bid)) {
+                       len += sprintf(buf + len,
+                                      "  DSPtask[%d]->Linux "
+                                      "(waiting to be read)\n"
+                                      "  count = %d\n", ld, c);
+               } else {
+                       len += sprintf(buf + len,
+                                      "  Linux->DSPtask[%d] "
+                                      "(waiting to be read)\n"
+                                      "  count = %d\n", la, c);
+               }
+       }
+
+       len += sprintf(buf + len, "\nFree IPBUF link: ");
+       spin_lock(&ipb_free.lock);
+       ipblink_for_each(bid, &ipb_free) {
+               len += sprintf(buf + len, "%d ", bid);
+       }
+       spin_unlock(&ipb_free.lock);
+       len += sprintf(buf + len, "\n");
+       len += sprintf(buf + len, "IPBFULL error count: %ld\n",
+                      ipbcfg.cnt_full);
+
+finish:
+       return len;
+}
diff --git a/arch/arm/plat-omap/dsp/ipbuf.h b/arch/arm/plat-omap/dsp/ipbuf.h
new file mode 100644 (file)
index 0000000..efaa2b7
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+struct ipbuf {
+       u16 c;                  /* count */
+       u16 next;               /* link */
+       u16 la;                 /* lock owner (ARM side) */
+       u16 sa;                 /* sync word (ARM->DSP) */
+       u16 ld;                 /* lock owner (DSP side) */
+       u16 sd;                 /* sync word (DSP->ARM) */
+       unsigned char d[0];     /* data */
+};
+
+struct ipbuf_p {
+       u16 c;          /* count */
+       u16 s;          /* sync word */
+       u16 al;         /* data address lower */
+       u16 ah;         /* data address upper */
+};
+
+#define IPBUF_SYS_DLEN 31
+
+struct ipbuf_sys {
+       u16 s;                  /* sync word */
+       u16 d[IPBUF_SYS_DLEN];  /* data */
+};
+
+struct ipbcfg {
+       u16 ln;
+       u16 lsz;
+       void *base;
+       u16 bsycnt;
+       unsigned long cnt_full; /* count of IPBFULL error */
+};
+
+struct ipbuf_head {
+       u16 bid;
+       struct ipbuf *p;
+};
+
+extern struct ipbcfg ipbcfg;
+extern struct ipbuf_sys *ipbuf_sys_da, *ipbuf_sys_ad;
+
+#define ipb_bsycnt_inc(ipbcfg)                         \
+       do {                                            \
+               disable_irq(omap_dsp->mbox->irq);       \
+               (ipbcfg)->bsycnt++;                     \
+               enable_irq(omap_dsp->mbox->irq);        \
+       } while(0)
+
+#define ipb_bsycnt_dec(ipbcfg)                         \
+       do {                                            \
+               disable_irq(omap_dsp->mbox->irq);       \
+               (ipbcfg)->bsycnt--;                     \
+               enable_irq(omap_dsp->mbox->irq);        \
+       } while(0)
+
+#define dsp_mem_enable_ipbuf() dsp_mem_enable(ipbcfg.base)
+#define dsp_mem_disable_ipbuf()        dsp_mem_disable(ipbcfg.base)
+
+struct ipblink {
+       spinlock_t lock;
+       u16 top;
+       u16 tail;
+};
+
+#define IPBLINK_INIT {                         \
+               .lock = SPIN_LOCK_UNLOCKED,     \
+               .top  = BID_NULL,               \
+               .tail = BID_NULL,               \
+       }
+
+#define INIT_IPBLINK(link)                     \
+       do {                                    \
+               spin_lock_init(&(link)->lock);  \
+               (link)->top  = BID_NULL;        \
+               (link)->tail = BID_NULL;        \
+       } while(0)
+
+#define RESET_IPBLINK(link)                    \
+       do {                                    \
+               (link)->top  = BID_NULL;        \
+               (link)->tail = BID_NULL;        \
+       } while(0)
+
+#define ipblink_empty(link)    ((link)->top == BID_NULL)
+
+static __inline__ void __ipblink_del_top(struct ipblink *link)
+{
+       struct ipbuf_head *ipb_h = bid_to_ipbuf(link->top);
+
+       if ((link->top = ipb_h->p->next) == BID_NULL)
+               link->tail = BID_NULL;
+       else
+               ipb_h->p->next = BID_NULL;
+}
+
+static __inline__ void ipblink_del_top(struct ipblink *link)
+{
+       spin_lock(&link->lock);
+       __ipblink_del_top(link);
+       spin_unlock(&link->lock);
+}
+
+static __inline__ void __ipblink_add_tail(struct ipblink *link, u16 bid)
+{
+       if (ipblink_empty(link))
+               link->top = bid;
+       else
+               bid_to_ipbuf(link->tail)->p->next = bid;
+       link->tail = bid;
+}
+
+static __inline__ void ipblink_add_tail(struct ipblink *link, u16 bid)
+{
+       spin_lock(&link->lock);
+       __ipblink_add_tail(link, bid);
+       spin_unlock(&link->lock);
+}
+
+static __inline__ void __ipblink_flush(struct ipblink *link)
+{
+       u16 bid;
+
+       while (!ipblink_empty(link)) {
+               bid = link->top;
+               __ipblink_del_top(link);
+               unuse_ipbuf(bid_to_ipbuf(bid));
+       }
+}
+
+static __inline__ void ipblink_flush(struct ipblink *link)
+{
+       spin_lock(&link->lock);
+       __ipblink_flush(link);
+       spin_unlock(&link->lock);
+}
+
+static __inline__ void __ipblink_add_pvt(struct ipblink *link)
+{
+       link->top  = BID_PVT;
+       link->tail = BID_PVT;
+}
+
+static __inline__ void ipblink_add_pvt(struct ipblink *link)
+{
+       spin_lock(&link->lock);
+       __ipblink_add_pvt(link);
+       spin_unlock(&link->lock);
+}
+
+static __inline__ void __ipblink_del_pvt(struct ipblink *link)
+{
+       link->top  = BID_NULL;
+       link->tail = BID_NULL;
+}
+
+static __inline__ void ipblink_del_pvt(struct ipblink *link)
+{
+       spin_lock(&link->lock);
+       __ipblink_del_pvt(link);
+       spin_unlock(&link->lock);
+}
+
+static __inline__ void __ipblink_flush_pvt(struct ipblink *link)
+{
+       if (!ipblink_empty(link))
+               ipblink_del_pvt(link);
+}
+
+static __inline__ void ipblink_flush_pvt(struct ipblink *link)
+{
+       spin_lock(&link->lock);
+       __ipblink_flush_pvt(link);
+       spin_unlock(&link->lock);
+}
+
+#define ipblink_for_each(bid, link) \
+       for (bid = (link)->top; bid != BID_NULL; bid = bid_to_ipbuf(bid)->p->next)
diff --git a/arch/arm/plat-omap/dsp/mblog.c b/arch/arm/plat-omap/dsp/mblog.c
new file mode 100644 (file)
index 0000000..53ac4ae
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2003-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <asm/arch/mailbox.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+
+char *subcmd_name(struct mbcmd *mb)
+{
+       u8 cmd_h = mb->cmd_h;
+       u8 cmd_l = mb->cmd_l;
+       char *s;
+
+       switch (cmd_h) {
+       case MBOX_CMD_DSP_RUNLEVEL:
+               s = (cmd_l == RUNLEVEL_USER)     ? "USER":
+                   (cmd_l == RUNLEVEL_SUPER)    ? "SUPER":
+                   (cmd_l == RUNLEVEL_RECOVERY) ? "RECOVERY":
+                   NULL;
+               break;
+       case MBOX_CMD_DSP_PM:
+               s = (cmd_l == PM_DISABLE) ? "DISABLE":
+                   (cmd_l == PM_ENABLE)  ? "ENABLE":
+                   NULL;
+               break;
+       case MBOX_CMD_DSP_KFUNC:
+               s = (cmd_l == KFUNC_FBCTL) ? "FBCTL":
+                   (cmd_l == KFUNC_POWER) ? "POWER":
+                   NULL;
+               break;
+       case MBOX_CMD_DSP_DSPCFG:
+               {
+                       u8 cfgc = cmd_l & 0x7f;
+                       s = (cfgc == DSPCFG_REQ)     ? "REQ":
+                           (cfgc == DSPCFG_SYSADRH) ? "SYSADRH":
+                           (cfgc == DSPCFG_SYSADRL) ? "SYSADRL":
+                           (cfgc == DSPCFG_ABORT)   ? "ABORT":
+                           (cfgc == DSPCFG_PROTREV) ? "PROTREV":
+                           NULL;
+                       break;
+               }
+       case MBOX_CMD_DSP_REGRW:
+               s = (cmd_l == REGRW_MEMR) ? "MEMR":
+                   (cmd_l == REGRW_MEMW) ? "MEMW":
+                   (cmd_l == REGRW_IOR)  ? "IOR":
+                   (cmd_l == REGRW_IOW)  ? "IOW":
+                   (cmd_l == REGRW_DATA) ? "DATA":
+                   NULL;
+               break;
+       case MBOX_CMD_DSP_GETVAR:
+       case MBOX_CMD_DSP_SETVAR:
+               s = (cmd_l == VARID_ICRMASK)  ? "ICRMASK":
+                   (cmd_l == VARID_LOADINFO) ? "LOADINFO":
+                   NULL;
+               break;
+       case MBOX_CMD_DSP_ERR:
+               s = (cmd_l == EID_BADTID)     ? "BADTID":
+                   (cmd_l == EID_BADTCN)     ? "BADTCN":
+                   (cmd_l == EID_BADBID)     ? "BADBID":
+                   (cmd_l == EID_BADCNT)     ? "BADCNT":
+                   (cmd_l == EID_NOTLOCKED)  ? "NOTLOCKED":
+                   (cmd_l == EID_STVBUF)     ? "STVBUF":
+                   (cmd_l == EID_BADADR)     ? "BADADR":
+                   (cmd_l == EID_BADTCTL)    ? "BADTCTL":
+                   (cmd_l == EID_BADPARAM)   ? "BADPARAM":
+                   (cmd_l == EID_FATAL)      ? "FATAL":
+                   (cmd_l == EID_WDT)        ? "WDT":
+                   (cmd_l == EID_NOMEM)      ? "NOMEM":
+                   (cmd_l == EID_NORES)      ? "NORES":
+                   (cmd_l == EID_IPBFULL)    ? "IPBFULL":
+                   (cmd_l == EID_TASKNOTRDY) ? "TASKNOTRDY":
+                   (cmd_l == EID_TASKBSY)    ? "TASKBSY":
+                   (cmd_l == EID_TASKERR)    ? "TASKERR":
+                   (cmd_l == EID_BADCFGTYP)  ? "BADCFGTYP":
+                   (cmd_l == EID_DEBUG)      ? "DEBUG":
+                   (cmd_l == EID_BADSEQ)     ? "BADSEQ":
+                   (cmd_l == EID_BADCMD)     ? "BADCMD":
+                   NULL;
+               break;
+       default:
+               s = NULL;
+       }
+
+       return s;
+}
+
+/* output of show() method should fit to PAGE_SIZE */
+#define MBLOG_DEPTH    64
+
+struct mblogent {
+       unsigned long jiffies;
+       mbox_msg_t msg;
+       arm_dsp_dir_t dir;
+};
+
+static struct {
+       spinlock_t lock;
+       int wp;
+       unsigned long cnt, cnt_ad, cnt_da;
+       struct mblogent ent[MBLOG_DEPTH];
+} mblog = {
+       .lock = SPIN_LOCK_UNLOCKED,
+};
+
+#ifdef CONFIG_OMAP_DSP_MBCMD_VERBOSE
+static inline void mblog_print_cmd(struct mbcmd *mb, arm_dsp_dir_t dir)
+{
+       const struct cmdinfo *ci = cmdinfo[mb->cmd_h];
+       char *dir_str;
+       char *subname;
+
+       dir_str = (dir == DIR_A2D) ? "sending  " : "receiving";
+       switch (ci->cmd_l_type) {
+       case CMD_L_TYPE_SUBCMD:
+               subname = subcmd_name(mb);
+               if (unlikely(!subname))
+                       subname = "Unknown";
+               printk(KERN_DEBUG
+                      "mbox: %s seq=%d, cmd=%02x:%02x(%s:%s), data=%04x\n",
+                      dir_str, mb->seq, mb->cmd_h, mb->cmd_l,
+                      ci->name, subname, mb->data);
+               break;
+       case CMD_L_TYPE_TID:
+               printk(KERN_DEBUG
+                      "mbox: %s seq=%d, cmd=%02x:%02x(%s:task %d), data=%04x\n",
+                      dir_str, mb->seq, mb->cmd_h, mb->cmd_l,
+                      ci->name, mb->cmd_l, mb->data);
+               break;
+       case CMD_L_TYPE_NULL:
+               printk(KERN_DEBUG
+                      "mbox: %s seq=%d, cmd=%02x:%02x(%s), data=%04x\n",
+                      dir_str, mb->seq, mb->cmd_h, mb->cmd_l,
+                      ci->name, mb->data);
+               break;
+       }
+}
+#else
+static inline void mblog_print_cmd(struct mbcmd *mb, arm_dsp_dir_t dir) { }
+#endif
+
+void mblog_add(struct mbcmd *mb, arm_dsp_dir_t dir)
+{
+       struct mblogent *ent;
+
+       spin_lock(&mblog.lock);
+       ent = &mblog.ent[mblog.wp];
+       ent->jiffies = jiffies;
+       ent->msg = *(mbox_msg_t *)mb;
+       ent->dir = dir;
+       if (mblog.cnt < 0xffffffff)
+               mblog.cnt++;
+       switch (dir) {
+       case DIR_A2D:
+               if (mblog.cnt_ad < 0xffffffff)
+                       mblog.cnt_ad++;
+               break;
+       case DIR_D2A:
+               if (mblog.cnt_da < 0xffffffff)
+                       mblog.cnt_da++;
+               break;
+       }
+       if (++mblog.wp == MBLOG_DEPTH)
+               mblog.wp = 0;
+       spin_unlock(&mblog.lock);
+
+       mblog_print_cmd(mb, dir);
+}
+
+/*
+ * sysfs file
+ */
+static ssize_t mblog_show(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       int len = 0;
+       int wp;
+       int i;
+
+       spin_lock(&mblog.lock);
+
+       wp = mblog.wp;
+       len += sprintf(buf + len,
+                      "log count:%ld / ARM->DSP:%ld, DSP->ARM:%ld\n",
+                      mblog.cnt, mblog.cnt_ad, mblog.cnt_da);
+       if (mblog.cnt == 0)
+               goto done;
+
+       len += sprintf(buf + len, "           ARM->DSP   ARM<-DSP\n");
+       len += sprintf(buf + len, " jiffies  cmd  data  cmd  data\n");
+       i = (mblog.cnt >= MBLOG_DEPTH) ? wp : 0;
+       do {
+               struct mblogent *ent = &mblog.ent[i];
+               struct mbcmd *mb = (struct mbcmd *)&ent->msg;
+               char *subname;
+               struct cmdinfo ci_null = {
+                       .name = "Unknown",
+                       .cmd_l_type = CMD_L_TYPE_NULL,
+               };
+               const struct cmdinfo *ci;
+
+               len += sprintf(buf + len,
+                              (ent->dir == DIR_A2D) ?
+                               "%08lx  %04x %04x            ":
+                               "%08lx             %04x %04x ",
+                              ent->jiffies,
+                              (ent->msg >> 16) & 0x7fff, ent->msg & 0xffff);
+
+               if ((ci = cmdinfo[mb->cmd_h]) == NULL)
+                       ci = &ci_null;
+
+               switch (ci->cmd_l_type) {
+               case CMD_L_TYPE_SUBCMD:
+                       if ((subname = subcmd_name(mb)) == NULL)
+                               subname = "Unknown";
+                       len += sprintf(buf + len, "%s:%s\n",
+                                      ci->name, subname);
+                       break;
+               case CMD_L_TYPE_TID:
+                       len += sprintf(buf + len, "%s:task %d\n",
+                                      ci->name, mb->cmd_l);
+                       break;
+               case CMD_L_TYPE_NULL:
+                       len += sprintf(buf + len, "%s\n", ci->name);
+                       break;
+               }
+
+               if (++i == MBLOG_DEPTH)
+                       i = 0;
+       } while (i != wp);
+
+done:
+       spin_unlock(&mblog.lock);
+
+       return len;
+}
+
+static struct device_attribute dev_attr_mblog = __ATTR_RO(mblog);
+
+void __init mblog_init(void)
+{
+       int ret;
+
+       ret = device_create_file(omap_dsp->dev, &dev_attr_mblog);
+       if (ret)
+               printk(KERN_ERR "device_create_file failed: %d\n", ret);
+}
+
+void mblog_exit(void)
+{
+       device_remove_file(omap_dsp->dev, &dev_attr_mblog);
+}
diff --git a/arch/arm/plat-omap/dsp/proclist.h b/arch/arm/plat-omap/dsp/proclist.h
new file mode 100644 (file)
index 0000000..cc5c3e0
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2004-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+struct proc_list {
+       struct list_head list_head;
+       pid_t pid;
+       struct file *file;
+};
+
+static __inline__ void proc_list_add(spinlock_t *lock, struct list_head *list,
+                                    struct task_struct *tsk, struct file *file)
+{
+       struct proc_list *new;
+
+       new = kmalloc(sizeof(struct proc_list), GFP_KERNEL);
+       new->pid = tsk->pid;
+       new->file = file;
+       spin_lock(lock);
+       list_add_tail(&new->list_head, list);
+       spin_unlock(lock);
+}
+
+static __inline__ void proc_list_del(spinlock_t *lock, struct list_head *list,
+                                    struct task_struct *tsk, struct file *file)
+{
+       struct proc_list *pl;
+
+       spin_lock(lock);
+       list_for_each_entry(pl, list, list_head) {
+               if (pl->file == file) {
+                       list_del(&pl->list_head);
+                       kfree(pl);
+                       spin_unlock(lock);
+                       return;
+               }
+       }
+
+       /* correspinding file struct isn't found in the list ???  */
+       printk(KERN_ERR "proc_list_del(): proc_list is inconsistent!\n"
+                       "struct file (%p) not found\n", file);
+       printk(KERN_ERR "listing proc_list...\n");
+       list_for_each_entry(pl, list, list_head)
+               printk(KERN_ERR "  pid:%d file:%p\n", pl->pid, pl->file);
+       spin_unlock(lock);
+}
+
+static __inline__ void proc_list_flush(spinlock_t *lock, struct list_head *list)
+{
+       struct proc_list *pl;
+
+       spin_lock(lock);
+       while (!list_empty(list)) {
+               pl = list_entry(list->next, struct proc_list, list_head);
+               list_del(&pl->list_head);
+               kfree(pl);
+       }
+       spin_unlock(lock);
+}
diff --git a/arch/arm/plat-omap/dsp/task.c b/arch/arm/plat-omap/dsp/task.c
new file mode 100644 (file)
index 0000000..807c408
--- /dev/null
@@ -0,0 +1,3025 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/arch/mailbox.h>
+#include "uaccess_dsp.h"
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.h"
+#include "fifo.h"
+#include "proclist.h"
+#include "ioctl.h"
+
+#define is_aligned(adr,align)  (!((adr)&((align)-1)))
+
+/*
+ * devstate: task device state machine
+ * NOTASK:     task is not attached.
+ * ATTACHED:   task is attached.
+ * GARBAGE:    task is detached. waiting for all processes to close this device.
+ * ADDREQ:     requesting for tadd
+ * DELREQ:     requesting for tdel. no process is opening this device.
+ * FREEZED:    task is attached, but reserved to be killed.
+ * ADDFAIL:    tadd failed.
+ * ADDING:     tadd in process.
+ * DELING:     tdel in process.
+ * KILLING:    tkill in process.
+ */
+#define TASKDEV_ST_NOTASK      0x00000001
+#define TASKDEV_ST_ATTACHED    0x00000002
+#define TASKDEV_ST_GARBAGE     0x00000004
+#define TASKDEV_ST_INVALID     0x00000008
+#define TASKDEV_ST_ADDREQ      0x00000100
+#define TASKDEV_ST_DELREQ      0x00000200
+#define TASKDEV_ST_FREEZED     0x00000400
+#define TASKDEV_ST_ADDFAIL     0x00001000
+#define TASKDEV_ST_ADDING      0x00010000
+#define TASKDEV_ST_DELING      0x00020000
+#define TASKDEV_ST_KILLING     0x00040000
+#define TASKDEV_ST_STATE_MASK  0x7fffffff
+#define TASKDEV_ST_STALE       0x80000000
+
+struct {
+       long state;
+       char *name;
+} devstate_desc[] = {
+       { TASKDEV_ST_NOTASK,   "notask" },
+       { TASKDEV_ST_ATTACHED, "attached" },
+       { TASKDEV_ST_GARBAGE,  "garbage" },
+       { TASKDEV_ST_INVALID,  "invalid" },
+       { TASKDEV_ST_ADDREQ,   "addreq" },
+       { TASKDEV_ST_DELREQ,   "delreq" },
+       { TASKDEV_ST_FREEZED,  "freezed" },
+       { TASKDEV_ST_ADDFAIL,  "addfail" },
+       { TASKDEV_ST_ADDING,   "adding" },
+       { TASKDEV_ST_DELING,   "deling" },
+       { TASKDEV_ST_KILLING,  "killing" },
+};
+
+static char *devstate_name(long state) {
+       int i;
+       int max = ARRAY_SIZE(devstate_desc);
+
+       for (i = 0; i < max; i++) {
+               if (state & devstate_desc[i].state)
+                       return devstate_desc[i].name;
+       }
+       return "unknown";
+}
+
+struct rcvdt_bk_struct {
+       struct ipblink link;
+       unsigned int rp;
+};
+
+struct taskdev {
+       struct bus_type *bus;
+       struct device dev;      /* Generic device interface */
+
+       long state;
+       struct rw_semaphore state_sem;
+       wait_queue_head_t state_wait_q;
+       struct mutex usecount_lock;
+       unsigned int usecount;
+       char name[TNM_LEN];
+       struct file_operations fops;
+       spinlock_t proc_list_lock;
+       struct list_head proc_list;
+       struct dsptask *task;
+
+       /* read stuff */
+       wait_queue_head_t read_wait_q;
+       struct mutex read_mutex;
+       union {
+               struct fifo_struct fifo;        /* for active word */
+               struct rcvdt_bk_struct bk;
+       } rcvdt;
+
+       /* write stuff */
+       wait_queue_head_t write_wait_q;
+       struct mutex write_mutex;
+       spinlock_t wsz_lock;
+       size_t wsz;
+
+       /* tctl stuff */
+       wait_queue_head_t tctl_wait_q;
+       struct mutex tctl_mutex;
+       int tctl_stat;
+       int tctl_ret;   /* return value for tctl_show() */
+
+       /* device lock */
+       struct mutex lock;
+       pid_t lock_pid;
+};
+
+#define to_taskdev(n) container_of(n, struct taskdev, dev)
+
+struct dsptask {
+       enum {
+               TASK_ST_ERR = 0,
+               TASK_ST_READY,
+               TASK_ST_CFGREQ
+       } state;
+       u8 tid;
+       char name[TNM_LEN];
+       u16 ttyp;
+       struct taskdev *dev;
+
+       /* read stuff */
+       struct ipbuf_p *ipbuf_pvt_r;
+
+       /* write stuff */
+       struct ipbuf_p *ipbuf_pvt_w;
+
+       /* mmap stuff */
+       void *map_base;
+       size_t map_length;
+};
+
+#define sndtyp_acv(ttyp)       ((ttyp) & TTYP_ASND)
+#define sndtyp_psv(ttyp)       (!((ttyp) & TTYP_ASND))
+#define sndtyp_bk(ttyp)                ((ttyp) & TTYP_BKDM)
+#define sndtyp_wd(ttyp)                (!((ttyp) & TTYP_BKDM))
+#define sndtyp_pvt(ttyp)       ((ttyp) & TTYP_PVDM)
+#define sndtyp_gbl(ttyp)       (!((ttyp) & TTYP_PVDM))
+#define rcvtyp_acv(ttyp)       ((ttyp) & TTYP_ARCV)
+#define rcvtyp_psv(ttyp)       (!((ttyp) & TTYP_ARCV))
+#define rcvtyp_bk(ttyp)                ((ttyp) & TTYP_BKMD)
+#define rcvtyp_wd(ttyp)                (!((ttyp) & TTYP_BKMD))
+#define rcvtyp_pvt(ttyp)       ((ttyp) & TTYP_PVMD)
+#define rcvtyp_gbl(ttyp)       (!((ttyp) & TTYP_PVMD))
+
+static __inline__ int has_taskdev_lock(struct taskdev *dev);
+static int dsp_rmdev_minor(unsigned char minor);
+static int taskdev_init(struct taskdev *dev, char *name, unsigned char minor);
+static void taskdev_delete(unsigned char minor);
+static int taskdev_attach_task(struct taskdev *dev, struct dsptask *task);
+static int dsp_tdel_bh(struct taskdev *dev, u16 type);
+
+static struct bus_type dsptask_bus = {
+       .name = "dsptask",
+};
+
+static struct class *dsp_task_class;
+static DEFINE_MUTEX(devmgr_lock);
+static struct taskdev *taskdev[TASKDEV_MAX];
+static struct dsptask *dsptask[TASKDEV_MAX];
+static DEFINE_MUTEX(cfg_lock);
+static u16 cfg_cmd;
+static u8 cfg_tid;
+static DECLARE_WAIT_QUEUE_HEAD(cfg_wait_q);
+static u8 n_task;      /* static task count */
+static void *heap;
+
+#define is_dynamic_task(tid)   ((tid) >= n_task)
+
+#define devstate_read_lock(dev, devstate) \
+               devstate_read_lock_timeout(dev, devstate, 0)
+#define devstate_read_unlock(dev)      up_read(&(dev)->state_sem)
+#define devstate_write_lock(dev, devstate) \
+               devstate_write_lock_timeout(dev, devstate, 0)
+#define devstate_write_unlock(dev)     up_write(&(dev)->state_sem)
+
+static ssize_t devname_show(struct device *d, struct device_attribute *attr,
+                           char *buf);
+static ssize_t devstate_show(struct device *d, struct device_attribute *attr,
+                            char *buf);
+static ssize_t proc_list_show(struct device *d, struct device_attribute *attr,
+                             char *buf);
+static ssize_t taskname_show(struct device *d, struct device_attribute *attr,
+                            char *buf);
+static ssize_t ttyp_show(struct device *d, struct device_attribute *attr,
+                        char *buf);
+static ssize_t fifosz_show(struct device *d, struct device_attribute *attr,
+                          char *buf);
+static int fifosz_store(struct device *d, struct device_attribute *attr,
+                       const char *buf, size_t count);
+static ssize_t fifocnt_show(struct device *d, struct device_attribute *attr,
+                           char *buf);
+static ssize_t ipblink_show(struct device *d, struct device_attribute *attr,
+                           char *buf);
+static ssize_t wsz_show(struct device *d, struct device_attribute *attr,
+                       char *buf);
+static ssize_t mmap_show(struct device *d, struct device_attribute *attr,
+                        char *buf);
+
+#define __ATTR_RW(_name,_mode) { \
+       .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE },     \
+       .show   = _name##_show,                                 \
+       .store  = _name##_store,                                        \
+}
+
+static struct device_attribute dev_attr_devname   = __ATTR_RO(devname);
+static struct device_attribute dev_attr_devstate  = __ATTR_RO(devstate);
+static struct device_attribute dev_attr_proc_list = __ATTR_RO(proc_list);
+static struct device_attribute dev_attr_taskname  = __ATTR_RO(taskname);
+static struct device_attribute dev_attr_ttyp      = __ATTR_RO(ttyp);
+static struct device_attribute dev_attr_fifosz    = __ATTR_RW(fifosz, 0666);
+static struct device_attribute dev_attr_fifocnt   = __ATTR_RO(fifocnt);
+static struct device_attribute dev_attr_ipblink   = __ATTR_RO(ipblink);
+static struct device_attribute dev_attr_wsz       = __ATTR_RO(wsz);
+static struct device_attribute dev_attr_mmap      = __ATTR_RO(mmap);
+
+/*
+ * devstate_read_lock_timeout()
+ * devstate_write_lock_timeout():
+ * timeout != 0: dev->state can be diffeent from what you want.
+ * timeout == 0: no timeout
+ */
+static int devstate_read_lock_timeout(struct taskdev *dev, long devstate,
+                                     int timeout)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       long current_state = current->state;
+       int ret = 0;
+
+       down_read(&dev->state_sem);
+       if (dev->state & devstate)
+               return 0;
+
+       add_wait_queue(&dev->state_wait_q, &wait);
+       do {
+               set_current_state(TASK_INTERRUPTIBLE);
+               up_read(&dev->state_sem);
+               if (timeout) {
+                       if ((timeout = schedule_timeout(timeout)) == 0) {
+                               /* timeout */
+                               down_read(&dev->state_sem);
+                               break;
+                       }
+               } else
+                       schedule();
+               if (signal_pending(current)) {
+                       ret = -EINTR;
+                       break;
+               }
+               down_read(&dev->state_sem);
+       } while (!(dev->state & devstate));
+       remove_wait_queue(&dev->state_wait_q, &wait);
+       set_current_state(current_state);
+       return ret;
+}
+
+static int devstate_read_lock_and_test(struct taskdev *dev, long devstate)
+{
+       down_read(&dev->state_sem);
+       if (dev->state & devstate)
+               return 1;       /* success */
+       /* failure */
+       up_read(&dev->state_sem);
+       return 0;
+}
+
+static int devstate_write_lock_timeout(struct taskdev *dev, long devstate,
+                                      int timeout)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       long current_state = current->state;
+       int ret = 0;
+
+       down_write(&dev->state_sem);
+       if (dev->state & devstate)
+               return 0;
+
+       add_wait_queue(&dev->state_wait_q, &wait);
+       do {
+               set_current_state(TASK_INTERRUPTIBLE);
+               up_write(&dev->state_sem);
+               if (timeout) {
+                       if ((timeout = schedule_timeout(timeout)) == 0) {
+                               /* timeout */
+                               down_write(&dev->state_sem);
+                               break;
+                       }
+               } else
+                       schedule();
+               if (signal_pending(current)) {
+                       ret = -EINTR;
+                       break;
+               }
+               down_write(&dev->state_sem);
+       } while (!(dev->state & devstate));
+       remove_wait_queue(&dev->state_wait_q, &wait);
+       set_current_state(current_state);
+       return ret;
+}
+
+static int devstate_write_lock_and_test(struct taskdev *dev, long devstate)
+{
+       down_write(&dev->state_sem);
+       if (dev->state & devstate)      /* success */
+               return 1;
+
+       /* failure */
+       up_write(&dev->state_sem);
+       return -1;
+}
+
+static int taskdev_lock_interruptible(struct taskdev *dev,
+                                     struct mutex *lock)
+{
+       int ret;
+
+       if (has_taskdev_lock(dev))
+               ret = mutex_lock_interruptible(lock);
+       else {
+               if ((ret = mutex_lock_interruptible(&dev->lock)) != 0)
+                       return ret;
+               ret = mutex_lock_interruptible(lock);
+               mutex_unlock(&dev->lock);
+       }
+
+       return ret;
+}
+
+static int taskdev_lock_and_statelock_attached(struct taskdev *dev,
+                                              struct mutex *lock)
+{
+       int ret;
+
+       if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+               return -ENODEV;
+
+       if ((ret = taskdev_lock_interruptible(dev, lock)) != 0)
+               devstate_read_unlock(dev);
+
+       return ret;
+}
+
+static __inline__ void taskdev_unlock_and_stateunlock(struct taskdev *dev,
+                                                     struct mutex *lock)
+{
+       mutex_unlock(lock);
+       devstate_read_unlock(dev);
+}
+
+/*
+ * taskdev_flush_buf()
+ * must be called under state_lock(ATTACHED) and dev->read_mutex.
+ */
+static int taskdev_flush_buf(struct taskdev *dev)
+{
+       u16 ttyp = dev->task->ttyp;
+
+       if (sndtyp_wd(ttyp)) {
+               /* word receiving */
+               flush_fifo(&dev->rcvdt.fifo);
+       } else {
+               /* block receiving */
+               struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk;
+
+               if (sndtyp_gbl(ttyp))
+                       ipblink_flush(&rcvdt->link);
+               else {
+                       ipblink_flush_pvt(&rcvdt->link);
+                       release_ipbuf_pvt(dev->task->ipbuf_pvt_r);
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * taskdev_set_fifosz()
+ * must be called under dev->read_mutex.
+ */
+static int taskdev_set_fifosz(struct taskdev *dev, unsigned long sz)
+{
+       u16 ttyp = dev->task->ttyp;
+       int stat;
+
+       if (!(sndtyp_wd(ttyp) && sndtyp_acv(ttyp))) {
+               printk(KERN_ERR
+                      "omapdsp: buffer size can be changed only for "
+                      "active word sending task.\n");
+               return -EINVAL;
+       }
+       if ((sz == 0) || (sz & 1)) {
+               printk(KERN_ERR "omapdsp: illegal buffer size! (%ld)\n"
+                               "it must be even and non-zero value.\n", sz);
+               return -EINVAL;
+       }
+
+       stat = realloc_fifo(&dev->rcvdt.fifo, sz);
+       if (stat == -EBUSY) {
+               printk(KERN_ERR "omapdsp: buffer is not empty!\n");
+               return stat;
+       } else if (stat < 0) {
+               printk(KERN_ERR
+                      "omapdsp: unable to change receive buffer size. "
+                      "(%ld bytes for %s)\n", sz, dev->name);
+               return stat;
+       }
+
+       return 0;
+}
+
+static __inline__ int has_taskdev_lock(struct taskdev *dev)
+{
+       return (dev->lock_pid == current->pid);
+}
+
+static int taskdev_lock(struct taskdev *dev)
+{
+       if (mutex_lock_interruptible(&dev->lock))
+               return -EINTR;
+       dev->lock_pid = current->pid;
+       return 0;
+}
+
+static int taskdev_unlock(struct taskdev *dev)
+{
+       if (!has_taskdev_lock(dev)) {
+               printk(KERN_ERR
+                      "omapdsp: an illegal process attempted to "
+                      "unlock the dsptask lock!\n");
+               return -EINVAL;
+       }
+       dev->lock_pid = 0;
+       mutex_unlock(&dev->lock);
+       return 0;
+}
+
+static int dsp_task_config(struct dsptask *task, u8 tid)
+{
+       u16 ttyp;
+       int ret;
+
+       task->tid = tid;
+       dsptask[tid] = task;
+
+       /* TCFG request */
+       task->state = TASK_ST_CFGREQ;
+       if (mutex_lock_interruptible(&cfg_lock)) {
+               ret = -EINTR;
+               goto fail_out;
+       }
+       cfg_cmd = MBOX_CMD_DSP_TCFG;
+       mbcompose_send_and_wait(TCFG, tid, 0, &cfg_wait_q);
+       cfg_cmd = 0;
+       mutex_unlock(&cfg_lock);
+
+       if (task->state != TASK_ST_READY) {
+               printk(KERN_ERR "omapdsp: task %d configuration error!\n", tid);
+               ret = -EINVAL;
+               goto fail_out;
+       }
+
+       if (strlen(task->name) <= 1)
+               sprintf(task->name, "%d", tid);
+       printk(KERN_INFO "omapdsp: task %d: name %s\n", tid, task->name);
+
+       ttyp = task->ttyp;
+
+       /*
+        * task info sanity check
+        */
+
+       /* task type check */
+       if (rcvtyp_psv(ttyp) && rcvtyp_pvt(ttyp)) {
+               printk(KERN_ERR "omapdsp: illegal task type(0x%04x), tid=%d\n",
+                      tid, ttyp);
+               ret = -EINVAL;
+               goto fail_out;
+       }
+
+       /* private buffer address check */
+       if (sndtyp_pvt(ttyp) &&
+           (ipbuf_p_validate(task->ipbuf_pvt_r, DIR_D2A) < 0)) {
+               ret = -EINVAL;
+               goto fail_out;
+       }
+       if (rcvtyp_pvt(ttyp) &&
+           (ipbuf_p_validate(task->ipbuf_pvt_w, DIR_A2D) < 0)) {
+               ret = -EINVAL;
+               goto fail_out;
+       }
+
+       /* mmap buffer configuration check */
+       if ((task->map_length > 0) &&
+           ((!is_aligned((unsigned long)task->map_base, PAGE_SIZE)) ||
+            (!is_aligned(task->map_length, PAGE_SIZE)) ||
+            (dsp_mem_type(task->map_base, task->map_length) != MEM_TYPE_EXTERN))) {
+               printk(KERN_ERR
+                      "omapdsp: illegal mmap buffer address(0x%p) or "
+                      "length(0x%x).\n"
+                      "  It needs to be page-aligned and located at "
+                      "external memory.\n",
+                      task->map_base, task->map_length);
+               ret = -EINVAL;
+               goto fail_out;
+       }
+
+       return 0;
+
+fail_out:
+       dsptask[tid] = NULL;
+       return ret;
+}
+
+static void dsp_task_init(struct dsptask *task)
+{
+       mbcompose_send(TCTL, task->tid, TCTL_TINIT);
+}
+
+int dsp_task_config_all(u8 n)
+{
+       int i, ret;
+       struct taskdev *devheap;
+       struct dsptask *taskheap;
+       size_t devheapsz, taskheapsz;
+
+       printk(KERN_INFO "omapdsp: found %d task(s)\n", n);
+       if (n == 0)
+               return 0;
+
+       /*
+        * reducing kmalloc!
+        */
+       devheapsz  = sizeof(struct taskdev) * n;
+       taskheapsz = sizeof(struct dsptask) * n;
+       heap = kzalloc(devheapsz + taskheapsz, GFP_KERNEL);
+       if (heap == NULL)
+               return -ENOMEM;
+       devheap  = heap;
+       taskheap = heap + devheapsz;
+
+       n_task = n;
+       for (i = 0; i < n; i++) {
+               struct taskdev *dev  = &devheap[i];
+               struct dsptask *task = &taskheap[i];
+
+               if ((ret = dsp_task_config(task, i)) < 0)
+                       return ret;
+               if ((ret = taskdev_init(dev, task->name, i)) < 0)
+                       return ret;
+               if ((ret = taskdev_attach_task(dev, task)) < 0)
+                       return ret;
+               dsp_task_init(task);
+               printk(KERN_INFO "omapdsp: taskdev %s enabled.\n", dev->name);
+       }
+
+       return 0;
+}
+
+static void dsp_task_unconfig(struct dsptask *task)
+{
+       dsptask[task->tid] = NULL;
+}
+
+void dsp_task_unconfig_all(void)
+{
+       unsigned char minor;
+       u8 tid;
+       struct dsptask *task;
+
+       for (minor = 0; minor < n_task; minor++) {
+               /*
+                * taskdev[minor] can be NULL in case of
+                * configuration failure
+                */
+               if (taskdev[minor])
+                       taskdev_delete(minor);
+       }
+       for (; minor < TASKDEV_MAX; minor++) {
+               if (taskdev[minor])
+                       dsp_rmdev_minor(minor);
+       }
+
+       for (tid = 0; tid < n_task; tid++) {
+               /*
+                * dsptask[tid] can be NULL in case of
+                * configuration failure
+                */
+               task = dsptask[tid];
+               if (task)
+                       dsp_task_unconfig(task);
+       }
+       for (; tid < TASKDEV_MAX; tid++) {
+               task = dsptask[tid];
+               if (task) {
+                       /*
+                        * on-demand tasks should be deleted in
+                        * rmdev_minor(), but just in case.
+                        */
+                       dsp_task_unconfig(task);
+                       kfree(task);
+               }
+       }
+
+       if (heap) {
+               kfree(heap);
+               heap = NULL;
+       }
+
+       n_task = 0;
+}
+
+static struct device_driver dsptask_driver = {
+       .name   = "dsptask",
+       .bus    = &dsptask_bus,
+};
+
+u8 dsp_task_count(void)
+{
+       return n_task;
+}
+
+int dsp_taskmod_busy(void)
+{
+       struct taskdev *dev;
+       unsigned char minor;
+       unsigned int usecount;
+
+       for (minor = 0; minor < TASKDEV_MAX; minor++) {
+               dev = taskdev[minor];
+               if (dev == NULL)
+                       continue;
+               if ((usecount = dev->usecount) > 0) {
+                       printk("dsp_taskmod_busy(): %s: usecount=%d\n",
+                              dev->name, usecount);
+                       return 1;
+               }
+/*
+               if ((dev->state & (TASKDEV_ST_ADDREQ |
+                                  TASKDEV_ST_DELREQ)) {
+*/
+               if (dev->state & TASKDEV_ST_ADDREQ) {
+                       printk("dsp_taskmod_busy(): %s is in %s\n",
+                              dev->name, devstate_name(dev->state));
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/*
+ * DSP task device file operations
+ */
+static ssize_t dsp_task_read_wd_acv(struct file *file, char __user *buf,
+                                   size_t count, loff_t *ppos)
+{
+       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       int ret = 0;
+
+       if (count == 0) {
+               return 0;
+       } else if (count & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: odd count is illegal for DSP task device.\n");
+               return -EINVAL;
+       }
+
+       if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+               return -ENODEV;
+
+       if (fifo_empty(&dev->rcvdt.fifo)) {
+               long current_state = current->state;
+               DECLARE_WAITQUEUE(wait, current);
+
+               set_current_state(TASK_INTERRUPTIBLE);
+               add_wait_queue(&dev->read_wait_q, &wait);
+               if (fifo_empty(&dev->rcvdt.fifo))       /* last check */
+                       schedule();
+               set_current_state(current_state);
+               remove_wait_queue(&dev->read_wait_q, &wait);
+               if (fifo_empty(&dev->rcvdt.fifo)) {
+                       /* failure */
+                       if (signal_pending(current))
+                               ret = -EINTR;
+                       goto up_out;
+               }
+       }
+
+       ret = copy_to_user_fm_fifo(buf, &dev->rcvdt.fifo, count);
+
+up_out:
+       taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+       return ret;
+}
+
+static ssize_t dsp_task_read_bk_acv(struct file *file, char __user *buf,
+                                   size_t count, loff_t *ppos)
+{
+       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk;
+       ssize_t ret = 0;
+
+       if (count == 0) {
+               return 0;
+       } else if (count & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: odd count is illegal for DSP task device.\n");
+               return -EINVAL;
+       } else if ((int)buf & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: buf should be word aligned for "
+                      "dsp_task_read().\n");
+               return -EINVAL;
+       }
+
+       if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+               return -ENODEV;
+
+       if (ipblink_empty(&rcvdt->link)) {
+               long current_state;
+               DECLARE_WAITQUEUE(wait, current);
+
+               add_wait_queue(&dev->read_wait_q, &wait);
+               current_state = current->state;
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (ipblink_empty(&rcvdt->link))        /* last check */
+                       schedule();
+               set_current_state(current_state);
+               remove_wait_queue(&dev->read_wait_q, &wait);
+               if (ipblink_empty(&rcvdt->link)) {
+                       /* failure */
+                       if (signal_pending(current))
+                               ret = -EINTR;
+                       goto up_out;
+               }
+       }
+
+       /* copy from delayed IPBUF */
+       if (sndtyp_pvt(dev->task->ttyp)) {
+               /* private */
+               if (!ipblink_empty(&rcvdt->link)) {
+                       struct ipbuf_p *ipbp = dev->task->ipbuf_pvt_r;
+                       unsigned char *base, *src;
+                       size_t bkcnt;
+
+                       if (dsp_mem_enable(ipbp) < 0) {
+                               ret = -EBUSY;
+                               goto up_out;
+                       }
+                       base = MKVIRT(ipbp->ah, ipbp->al);
+                       bkcnt = ((unsigned long)ipbp->c) * 2 - rcvdt->rp;
+                       if (dsp_address_validate(base, bkcnt,
+                                                "task %s read buffer",
+                                                dev->task->name) < 0) {
+                               ret = -EINVAL;
+                               goto pv_out1;
+                       }
+                       if (dsp_mem_enable(base) < 0) {
+                               ret = -EBUSY;
+                               goto pv_out1;
+                       }
+                       src = base + rcvdt->rp;
+                       if (bkcnt > count) {
+                               if (copy_to_user_dsp(buf, src, count)) {
+                                       ret = -EFAULT;
+                                       goto pv_out2;
+                               }
+                               ret = count;
+                               rcvdt->rp += count;
+                       } else {
+                               if (copy_to_user_dsp(buf, src, bkcnt)) {
+                                       ret = -EFAULT;
+                                       goto pv_out2;
+                               }
+                               ret = bkcnt;
+                               ipblink_del_pvt(&rcvdt->link);
+                               release_ipbuf_pvt(ipbp);
+                               rcvdt->rp = 0;
+                       }
+pv_out2:
+                       dsp_mem_disable(src);
+pv_out1:
+                       dsp_mem_disable(ipbp);
+               }
+       } else {
+               /* global */
+               if (dsp_mem_enable_ipbuf() < 0) {
+                       ret = -EBUSY;
+                       goto up_out;
+               }
+               while (!ipblink_empty(&rcvdt->link)) {
+                       unsigned char *src;
+                       size_t bkcnt;
+                       struct ipbuf_head *ipb_h = bid_to_ipbuf(rcvdt->link.top);
+
+                       src = ipb_h->p->d + rcvdt->rp;
+                       bkcnt = ((unsigned long)ipb_h->p->c) * 2 - rcvdt->rp;
+                       if (bkcnt > count) {
+                               if (copy_to_user_dsp(buf, src, count)) {
+                                       ret = -EFAULT;
+                                       goto gb_out;
+                               }
+                               ret += count;
+                               rcvdt->rp += count;
+                               break;
+                       } else {
+                               if (copy_to_user_dsp(buf, src, bkcnt)) {
+                                       ret = -EFAULT;
+                                       goto gb_out;
+                               }
+                               ret += bkcnt;
+                               buf += bkcnt;
+                               count -= bkcnt;
+                               ipblink_del_top(&rcvdt->link);
+                               unuse_ipbuf(ipb_h);
+                               rcvdt->rp = 0;
+                       }
+               }
+gb_out:
+               dsp_mem_disable_ipbuf();
+       }
+
+up_out:
+       taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+       return ret;
+}
+
+static ssize_t dsp_task_read_wd_psv(struct file *file, char __user *buf,
+                                   size_t count, loff_t *ppos)
+{
+       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       int ret = 0;
+
+       if (count == 0) {
+               return 0;
+       } else if (count & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: odd count is illegal for DSP task device.\n");
+               return -EINVAL;
+       } else {
+               /* force! */
+               count = 2;
+       }
+
+       if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+               return -ENODEV;
+
+       mbcompose_send_and_wait(WDREQ, dev->task->tid, 0, &dev->read_wait_q);
+
+       if (fifo_empty(&dev->rcvdt.fifo)) {
+               /* failure */
+               if (signal_pending(current))
+                       ret = -EINTR;
+               goto up_out;
+       }
+
+       ret = copy_to_user_fm_fifo(buf, &dev->rcvdt.fifo, count);
+
+up_out:
+       taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+       return ret;
+}
+
+static ssize_t dsp_task_read_bk_psv(struct file *file, char __user *buf,
+                                   size_t count, loff_t *ppos)
+{
+       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk;
+       int ret = 0;
+
+       if (count == 0) {
+               return 0;
+       } else if (count & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: odd count is illegal for DSP task device.\n");
+               return -EINVAL;
+       } else if ((int)buf & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: buf should be word aligned for "
+                      "dsp_task_read().\n");
+               return -EINVAL;
+       }
+
+       if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+               return -ENODEV;
+
+       mbcompose_send_and_wait(BKREQ, dev->task->tid, count/2,
+                               &dev->read_wait_q);
+
+       if (ipblink_empty(&rcvdt->link)) {
+               /* failure */
+               if (signal_pending(current))
+                       ret = -EINTR;
+               goto up_out;
+       }
+
+       /*
+        * We will not receive more than requested count.
+        */
+       if (sndtyp_pvt(dev->task->ttyp)) {
+               /* private */
+               struct ipbuf_p *ipbp = dev->task->ipbuf_pvt_r;
+               size_t rcvcnt;
+               void *src;
+
+               if (dsp_mem_enable(ipbp) < 0) {
+                       ret = -EBUSY;
+                       goto up_out;
+               }
+               src = MKVIRT(ipbp->ah, ipbp->al);
+               rcvcnt = ((unsigned long)ipbp->c) * 2;
+               if (dsp_address_validate(src, rcvcnt, "task %s read buffer",
+                                        dev->task->name) < 0) {
+                       ret = -EINVAL;
+                       goto pv_out1;
+               }
+               if (dsp_mem_enable(src) < 0) {
+                       ret = -EBUSY;
+                       goto pv_out1;
+               }
+               if (count > rcvcnt)
+                       count = rcvcnt;
+               if (copy_to_user_dsp(buf, src, count)) {
+                       ret = -EFAULT;
+                       goto pv_out2;
+               }
+               ipblink_del_pvt(&rcvdt->link);
+               release_ipbuf_pvt(ipbp);
+               ret = count;
+pv_out2:
+               dsp_mem_disable(src);
+pv_out1:
+               dsp_mem_disable(ipbp);
+       } else {
+               /* global */
+               struct ipbuf_head *ipb_h = bid_to_ipbuf(rcvdt->link.top);
+               size_t rcvcnt;
+
+               if (dsp_mem_enable_ipbuf() < 0) {
+                       ret = -EBUSY;
+                       goto up_out;
+               }
+               rcvcnt = ((unsigned long)ipb_h->p->c) * 2;
+               if (count > rcvcnt)
+                       count = rcvcnt;
+               if (copy_to_user_dsp(buf, ipb_h->p->d, count)) {
+                       ret = -EFAULT;
+                       goto gb_out;
+               }
+               ipblink_del_top(&rcvdt->link);
+               unuse_ipbuf(ipb_h);
+               ret = count;
+gb_out:
+               dsp_mem_disable_ipbuf();
+       }
+
+up_out:
+       taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+       return ret;
+}
+
+static ssize_t dsp_task_write_wd(struct file *file, const char __user *buf,
+                                size_t count, loff_t *ppos)
+{
+       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       u16 wd;
+       int ret = 0;
+
+       if (count == 0) {
+               return 0;
+       } else if (count & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: odd count is illegal for DSP task device.\n");
+               return -EINVAL;
+       } else {
+               /* force! */
+               count = 2;
+       }
+
+       if (taskdev_lock_and_statelock_attached(dev, &dev->write_mutex))
+               return -ENODEV;
+
+       if (dev->wsz == 0) {
+               long current_state;
+               DECLARE_WAITQUEUE(wait, current);
+
+               add_wait_queue(&dev->write_wait_q, &wait);
+               current_state = current->state;
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (dev->wsz == 0)      /* last check */
+                       schedule();
+               set_current_state(current_state);
+               remove_wait_queue(&dev->write_wait_q, &wait);
+               if (dev->wsz == 0) {
+                       /* failure */
+                       if (signal_pending(current))
+                               ret = -EINTR;
+                       goto up_out;
+               }
+       }
+
+       if (copy_from_user(&wd, buf, count)) {
+               ret = -EFAULT;
+               goto up_out;
+       }
+
+       spin_lock(&dev->wsz_lock);
+       if (mbcompose_send(WDSND, dev->task->tid, wd) < 0) {
+               spin_unlock(&dev->wsz_lock);
+               goto up_out;
+       }
+       ret = count;
+       if (rcvtyp_acv(dev->task->ttyp))
+               dev->wsz = 0;
+       spin_unlock(&dev->wsz_lock);
+
+up_out:
+       taskdev_unlock_and_stateunlock(dev, &dev->write_mutex);
+       return ret;
+}
+
+static ssize_t dsp_task_write_bk(struct file *file, const char __user *buf,
+                                size_t count, loff_t *ppos)
+{
+       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       int ret = 0;
+
+       if (count == 0) {
+               return 0;
+       } else if (count & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: odd count is illegal for DSP task device.\n");
+               return -EINVAL;
+       } else if ((int)buf & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: buf should be word aligned for "
+                      "dsp_task_write().\n");
+               return -EINVAL;
+       }
+
+       if (taskdev_lock_and_statelock_attached(dev, &dev->write_mutex))
+               return -ENODEV;
+
+       if (dev->wsz == 0) {
+               long current_state;
+               DECLARE_WAITQUEUE(wait, current);
+
+               add_wait_queue(&dev->write_wait_q, &wait);
+               current_state = current->state;
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (dev->wsz == 0)      /* last check */
+                       schedule();
+               set_current_state(current_state);
+               remove_wait_queue(&dev->write_wait_q, &wait);
+               if (dev->wsz == 0) {
+                       /* failure */
+                       if (signal_pending(current))
+                               ret = -EINTR;
+                       goto up_out;
+               }
+       }
+
+       if (count > dev->wsz)
+               count = dev->wsz;
+
+       if (rcvtyp_pvt(dev->task->ttyp)) {
+               /* private */
+               struct ipbuf_p *ipbp = dev->task->ipbuf_pvt_w;
+               unsigned char *dst;
+
+               if (dsp_mem_enable(ipbp) < 0) {
+                       ret = -EBUSY;
+                       goto up_out;
+               }
+               dst = MKVIRT(ipbp->ah, ipbp->al);
+               if (dsp_address_validate(dst, count, "task %s write buffer",
+                                        dev->task->name) < 0) {
+                       ret = -EINVAL;
+                       goto pv_out1;
+               }
+               if (dsp_mem_enable(dst) < 0) {
+                       ret = -EBUSY;
+                       goto pv_out1;
+               }
+               if (copy_from_user_dsp(dst, buf, count)) {
+                       ret = -EFAULT;
+                       goto pv_out2;
+               }
+               ipbp->c = count/2;
+               ipbp->s = dev->task->tid;
+               spin_lock(&dev->wsz_lock);
+               if (mbcompose_send(BKSNDP, dev->task->tid, 0) == 0) {
+                       if (rcvtyp_acv(dev->task->ttyp))
+                               dev->wsz = 0;
+                       ret = count;
+               }
+               spin_unlock(&dev->wsz_lock);
+pv_out2:
+               dsp_mem_disable(dst);
+pv_out1:
+               dsp_mem_disable(ipbp);
+       } else {
+               /* global */
+               struct ipbuf_head *ipb_h;
+
+               if (dsp_mem_enable_ipbuf() < 0) {
+                       ret = -EBUSY;
+                       goto up_out;
+               }
+               if ((ipb_h = get_free_ipbuf(dev->task->tid)) == NULL)
+                       goto gb_out;
+               if (copy_from_user_dsp(ipb_h->p->d, buf, count)) {
+                       release_ipbuf(ipb_h);
+                       ret = -EFAULT;
+                       goto gb_out;
+               }
+               ipb_h->p->c  = count/2;
+               ipb_h->p->sa = dev->task->tid;
+               spin_lock(&dev->wsz_lock);
+               if (mbcompose_send(BKSND, dev->task->tid, ipb_h->bid) == 0) {
+                       if (rcvtyp_acv(dev->task->ttyp))
+                               dev->wsz = 0;
+                       ret = count;
+                       ipb_bsycnt_inc(&ipbcfg);
+               } else
+                       release_ipbuf(ipb_h);
+               spin_unlock(&dev->wsz_lock);
+gb_out:
+               dsp_mem_disable_ipbuf();
+       }
+
+up_out:
+       taskdev_unlock_and_stateunlock(dev, &dev->write_mutex);
+       return ret;
+}
+
+static unsigned int dsp_task_poll(struct file * file, poll_table * wait)
+{
+       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       struct dsptask *task = dev->task;
+       unsigned int mask = 0;
+
+       if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+               return 0;
+       poll_wait(file, &dev->read_wait_q, wait);
+       poll_wait(file, &dev->write_wait_q, wait);
+       if (sndtyp_psv(task->ttyp) ||
+           (sndtyp_wd(task->ttyp) && !fifo_empty(&dev->rcvdt.fifo)) ||
+           (sndtyp_bk(task->ttyp) && !ipblink_empty(&dev->rcvdt.bk.link)))
+               mask |= POLLIN | POLLRDNORM;
+       if (dev->wsz)
+               mask |= POLLOUT | POLLWRNORM;
+       devstate_read_unlock(dev);
+
+       return mask;
+}
+
+static int dsp_tctl_issue(struct taskdev *dev, u16 cmd, int argc, u16 argv[])
+{
+       int tctl_argc;
+       struct mb_exarg mbarg, *mbargp;
+       int interactive;
+       u8 tid;
+       int ret = 0;
+
+       if (cmd < 0x8000) {
+               /*
+                * 0x0000 - 0x7fff
+                * system reserved TCTL commands
+                */
+               switch (cmd) {
+               case TCTL_TEN:
+               case TCTL_TDIS:
+                       tctl_argc = 0;
+                       interactive = 0;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+       /*
+        * 0x8000 - 0xffff
+        * user-defined TCTL commands
+        */
+       else if (cmd < 0x8100) {
+               /* 0x8000-0x80ff: no arg, non-interactive */
+               tctl_argc = 0;
+               interactive = 0;
+       } else if (cmd < 0x8200) {
+               /* 0x8100-0x81ff: 1 arg, non-interactive */
+               tctl_argc = 1;
+               interactive = 0;
+       } else if (cmd < 0x9000) {
+               /* 0x8200-0x8fff: reserved */
+               return -EINVAL;
+       } else if (cmd < 0x9100) {
+               /* 0x9000-0x90ff: no arg, interactive */
+               tctl_argc = 0;
+               interactive = 1;
+       } else if (cmd < 0x9200) {
+               /* 0x9100-0x91ff: 1 arg, interactive */
+               tctl_argc = 1;
+               interactive = 1;
+       } else {
+               /* 0x9200-0xffff: reserved */
+               return -EINVAL;
+       }
+
+       /*
+        * if argc < 0, use tctl_argc as is.
+        * if argc >= 0, check arg count.
+        */
+       if ((argc >= 0) && (argc != tctl_argc))
+               return -EINVAL;
+
+       /*
+        * issue TCTL
+        */
+       if (taskdev_lock_interruptible(dev, &dev->tctl_mutex))
+               return -EINTR;
+
+       tid = dev->task->tid;
+       if (tctl_argc > 0) {
+               mbarg.argc = tctl_argc;
+               mbarg.tid  = tid;
+               mbarg.argv = argv;
+               mbargp = &mbarg;
+       } else
+               mbargp = NULL;
+
+       if (interactive) {
+               dev->tctl_stat = -EINVAL;
+
+               mbcompose_send_and_wait_exarg(TCTL, tid, cmd, mbargp,
+                                             &dev->tctl_wait_q);
+               if (signal_pending(current)) {
+                       ret = -EINTR;
+                       goto up_out;
+               }
+               if ((ret = dev->tctl_stat) < 0) {
+                       printk(KERN_ERR "omapdsp: TCTL not responding.\n");
+                       goto up_out;
+               }
+       } else
+               mbcompose_send_exarg(TCTL, tid, cmd, mbargp);
+
+up_out:
+       mutex_unlock(&dev->tctl_mutex);
+       return ret;
+}
+
+static int dsp_task_ioctl(struct inode *inode, struct file *file,
+                         unsigned int cmd, unsigned long arg)
+{
+       unsigned int minor = MINOR(inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       int ret;
+
+       if (cmd < 0x10000) {
+               /* issue TCTL */
+               u16 mbargv[1];
+
+               mbargv[0] = arg & 0xffff;
+               return dsp_tctl_issue(dev, cmd, -1, mbargv);
+       }
+
+       /* non TCTL ioctls */
+       switch (cmd) {
+
+       case TASK_IOCTL_LOCK:
+               ret = taskdev_lock(dev);
+               break;
+
+       case TASK_IOCTL_UNLOCK:
+               ret = taskdev_unlock(dev);
+               break;
+
+       case TASK_IOCTL_BFLSH:
+               if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+                       return -ENODEV;
+               ret = taskdev_flush_buf(dev);
+               taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+               break;
+
+       case TASK_IOCTL_SETBSZ:
+               if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+                       return -ENODEV;
+               ret = taskdev_set_fifosz(dev, arg);
+               taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+               break;
+
+       case TASK_IOCTL_GETNAME:
+               ret = 0;
+               if (copy_to_user((void __user *)arg, dev->name,
+                                strlen(dev->name) + 1))
+                       ret = -EFAULT;
+               break;
+
+       default:
+               ret = -ENOIOCTLCMD;
+
+       }
+
+       return ret;
+}
+
+static void dsp_task_mmap_open(struct vm_area_struct *vma)
+{
+       struct taskdev *dev = (struct taskdev *)vma->vm_private_data;
+       struct dsptask *task;
+       size_t len = vma->vm_end - vma->vm_start;
+
+       BUG_ON(!(dev->state & TASKDEV_ST_ATTACHED));
+       task = dev->task;
+       exmap_use(task->map_base, len);
+}
+
+static void dsp_task_mmap_close(struct vm_area_struct *vma)
+{
+       struct taskdev *dev = (struct taskdev *)vma->vm_private_data;
+       struct dsptask *task;
+       size_t len = vma->vm_end - vma->vm_start;
+
+       BUG_ON(!(dev->state & TASKDEV_ST_ATTACHED));
+       task = dev->task;
+       exmap_unuse(task->map_base, len);
+}
+
+/**
+ * On demand page allocation is not allowed. The mapping area is defined by
+ * corresponding DSP tasks.
+ */
+static struct page *dsp_task_mmap_nopage(struct vm_area_struct *vma,
+                                        unsigned long address, int *type)
+{
+       return NOPAGE_SIGBUS;
+}
+
+static struct vm_operations_struct dsp_task_vm_ops = {
+       .open = dsp_task_mmap_open,
+       .close = dsp_task_mmap_close,
+       .nopage = dsp_task_mmap_nopage,
+};
+
+static int dsp_task_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       void *tmp_vadr;
+       unsigned long tmp_padr, tmp_vmadr, off;
+       size_t req_len, tmp_len;
+       unsigned int minor = MINOR(filp->f_dentry->d_inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       struct dsptask *task;
+       int ret = 0;
+
+       if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+               return -ENODEV;
+       task = dev->task;
+
+       /*
+        * Don't swap this area out
+        * Don't dump this area to a core file
+        */
+       vma->vm_flags |= VM_RESERVED | VM_IO;
+
+       /* Do not cache this area */
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+       req_len = vma->vm_end - vma->vm_start;
+       off = vma->vm_pgoff << PAGE_SHIFT;
+       tmp_vmadr = vma->vm_start;
+       tmp_vadr = task->map_base + off;
+       do {
+               tmp_padr = dsp_virt_to_phys(tmp_vadr, &tmp_len);
+               if (tmp_padr == 0) {
+                       printk(KERN_ERR
+                              "omapdsp: task %s: illegal address "
+                              "for mmap: %p", task->name, tmp_vadr);
+                       /* partial mapping will be cleared in upper layer */
+                       ret = -EINVAL;
+                       goto unlock_out;
+               }
+               if (tmp_len > req_len)
+                       tmp_len = req_len;
+
+               printk(KERN_DEBUG
+                      "omapdsp: mmap info: "
+                      "vmadr = %08lx, padr = %08lx, len = %x\n",
+                      tmp_vmadr, tmp_padr, tmp_len);
+               if (remap_pfn_range(vma, tmp_vmadr, tmp_padr >> PAGE_SHIFT,
+                                   tmp_len, vma->vm_page_prot) != 0) {
+                       printk(KERN_ERR
+                              "omapdsp: task %s: remap_page_range() failed.\n",
+                              task->name);
+                       /* partial mapping will be cleared in upper layer */
+                       ret = -EINVAL;
+                       goto unlock_out;
+               }
+
+               req_len   -= tmp_len;
+               tmp_vmadr += tmp_len;
+               tmp_vadr  += tmp_len;
+       } while (req_len);
+
+       vma->vm_ops = &dsp_task_vm_ops;
+       vma->vm_private_data = dev;
+       exmap_use(task->map_base, vma->vm_end - vma->vm_start);
+
+unlock_out:
+       devstate_read_unlock(dev);
+       return ret;
+}
+
+static int dsp_task_open(struct inode *inode, struct file *file)
+{
+       unsigned int minor = MINOR(inode->i_rdev);
+       struct taskdev *dev;
+       int ret = 0;
+
+       if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL))
+               return -ENODEV;
+
+restart:
+       mutex_lock(&dev->usecount_lock);
+       down_write(&dev->state_sem);
+
+       /* state can be NOTASK, ATTACHED/FREEZED, KILLING, GARBAGE or INVALID here. */
+       switch (dev->state & TASKDEV_ST_STATE_MASK) {
+               case TASKDEV_ST_NOTASK:
+                       break;
+               case TASKDEV_ST_ATTACHED:
+                       goto attached;
+
+               case TASKDEV_ST_INVALID:
+                       up_write(&dev->state_sem);
+                       mutex_unlock(&dev->usecount_lock);
+                       return -ENODEV;
+
+               case TASKDEV_ST_FREEZED:
+               case TASKDEV_ST_KILLING:
+               case TASKDEV_ST_GARBAGE:
+               case TASKDEV_ST_DELREQ:
+                       /* on the kill process. wait until it becomes NOTASK. */
+                       up_write(&dev->state_sem);
+                       mutex_unlock(&dev->usecount_lock);
+                       if (devstate_write_lock(dev, TASKDEV_ST_NOTASK) < 0)
+                               return -EINTR;
+                       devstate_write_unlock(dev);
+                       goto restart;
+       }
+
+       /* NOTASK */
+       dev->state = TASKDEV_ST_ADDREQ;
+       /* wake up twch daemon for tadd */
+       dsp_twch_touch();
+       up_write(&dev->state_sem);
+       if (devstate_write_lock(dev, TASKDEV_ST_ATTACHED |
+                                    TASKDEV_ST_ADDFAIL) < 0) {
+               /* cancelled */
+               if (!devstate_write_lock_and_test(dev, TASKDEV_ST_ADDREQ)) {
+                       mutex_unlock(&dev->usecount_lock);
+                       /* out of control ??? */
+                       return -EINTR;
+               }
+               dev->state = TASKDEV_ST_NOTASK;
+               ret = -EINTR;
+               goto change_out;
+       }
+       if (dev->state & TASKDEV_ST_ADDFAIL) {
+               printk(KERN_ERR "omapdsp: task attach failed for %s!\n",
+                      dev->name);
+               ret = -EBUSY;
+               dev->state = TASKDEV_ST_NOTASK;
+               goto change_out;
+       }
+
+attached:
+       /* ATTACHED */
+#ifndef CONFIG_OMAP_DSP_TASK_MULTIOPEN
+       if (dev->usecount > 0) {
+               up_write(&dev->state_sem);
+               return -EBUSY;
+       }
+#endif
+       dev->usecount++;
+       proc_list_add(&dev->proc_list_lock, &dev->proc_list, current, file);
+       file->f_op = &dev->fops;
+       up_write(&dev->state_sem);
+       mutex_unlock(&dev->usecount_lock);
+
+#ifdef DSP_PTE_FREE    /* not used currently. */
+       dsp_map_update(current);
+       dsp_cur_users_add(current);
+#endif /* DSP_PTE_FREE */
+       return 0;
+
+change_out:
+       wake_up_interruptible_all(&dev->state_wait_q);
+       up_write(&dev->state_sem);
+       mutex_unlock(&dev->usecount_lock);
+       return ret;
+}
+
+static int dsp_task_release(struct inode *inode, struct file *file)
+{
+       unsigned int minor = MINOR(inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+
+#ifdef DSP_PTE_FREE    /* not used currently. */
+       dsp_cur_users_del(current);
+#endif /* DSP_PTE_FREE */
+
+       if (has_taskdev_lock(dev))
+               taskdev_unlock(dev);
+
+       proc_list_del(&dev->proc_list_lock, &dev->proc_list, current, file);
+       mutex_lock(&dev->usecount_lock);
+       if (--dev->usecount > 0) {
+               /* other processes are using this device. no state change. */
+               mutex_unlock(&dev->usecount_lock);
+               return 0;
+       }
+
+       /* usecount == 0 */
+       down_write(&dev->state_sem);
+
+       /* state can be ATTACHED/FREEZED, KILLING or GARBAGE here. */
+       switch (dev->state & TASKDEV_ST_STATE_MASK) {
+
+       case TASKDEV_ST_KILLING:
+               break;
+
+       case TASKDEV_ST_GARBAGE:
+               dev->state = TASKDEV_ST_NOTASK;
+               wake_up_interruptible_all(&dev->state_wait_q);
+               break;
+
+       case TASKDEV_ST_ATTACHED:
+       case TASKDEV_ST_FREEZED:
+               if (is_dynamic_task(minor)) {
+                       dev->state = TASKDEV_ST_DELREQ;
+                       /* wake up twch daemon for tdel */
+                       dsp_twch_touch();
+               }
+               break;
+
+       }
+
+       up_write(&dev->state_sem);
+       mutex_unlock(&dev->usecount_lock);
+       return 0;
+}
+
+/*
+ * mkdev / rmdev
+ */
+int dsp_mkdev(char *name)
+{
+       struct taskdev *dev;
+       int status;
+       unsigned char minor;
+       int ret;
+
+       if (dsp_cfgstat_get_stat() != CFGSTAT_READY) {
+               printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
+               return -EINVAL;
+       }
+
+       if (mutex_lock_interruptible(&devmgr_lock))
+               return -EINTR;
+
+       /* naming check */
+       for (minor = 0; minor < TASKDEV_MAX; minor++) {
+               if (taskdev[minor] && !strcmp(taskdev[minor]->name, name)) {
+                       printk(KERN_ERR
+                              "omapdsp: task device name %s is already "
+                              "in use.\n", name);
+                       ret = -EINVAL;
+                       goto out;
+               }
+       }
+
+       /* find free minor number */
+       for (minor = n_task; minor < TASKDEV_MAX; minor++) {
+               if (taskdev[minor] == NULL)
+                       goto do_make;
+       }
+       printk(KERN_ERR "omapdsp: Too many task devices.\n");
+       ret = -EBUSY;
+       goto out;
+
+do_make:
+       if ((dev = kzalloc(sizeof(struct taskdev), GFP_KERNEL)) == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       if ((status = taskdev_init(dev, name, minor)) < 0) {
+               kfree(dev);
+               ret = status;
+               goto out;
+       }
+       ret = minor;
+
+out:
+       mutex_unlock(&devmgr_lock);
+       return ret;
+}
+
+int dsp_rmdev(char *name)
+{
+       unsigned char minor;
+       int status;
+       int ret;
+
+       if (dsp_cfgstat_get_stat() != CFGSTAT_READY) {
+               printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
+               return -EINVAL;
+       }
+
+       if (mutex_lock_interruptible(&devmgr_lock))
+               return -EINTR;
+
+       /* find in dynamic devices */
+       for (minor = n_task; minor < TASKDEV_MAX; minor++) {
+               if (taskdev[minor] && !strcmp(taskdev[minor]->name, name))
+                       goto do_remove;
+       }
+
+       /* find in static devices */
+       for (minor = 0; minor < n_task; minor++) {
+               if (taskdev[minor] && !strcmp(taskdev[minor]->name, name)) {
+                       printk(KERN_ERR
+                              "omapdsp: task device %s is static.\n", name);
+                       ret = -EINVAL;
+                       goto out;
+               }
+       }
+
+       printk(KERN_ERR "omapdsp: task device %s not found.\n", name);
+       return -EINVAL;
+
+do_remove:
+       ret = minor;
+       if ((status = dsp_rmdev_minor(minor)) < 0)
+               ret = status;
+out:
+       mutex_unlock(&devmgr_lock);
+       return ret;
+}
+
+static int dsp_rmdev_minor(unsigned char minor)
+{
+       struct taskdev *dev = taskdev[minor];
+
+       while (!down_write_trylock(&dev->state_sem)) {
+               down_read(&dev->state_sem);
+               if (dev->state & (TASKDEV_ST_ATTACHED |
+                                 TASKDEV_ST_FREEZED)) {
+                       /*
+                        * task is working. kill it.
+                        * ATTACHED -> FREEZED can be changed under
+                        * down_read of state_sem..
+                        */
+                       dev->state = TASKDEV_ST_FREEZED;
+                       wake_up_interruptible_all(&dev->read_wait_q);
+                       wake_up_interruptible_all(&dev->write_wait_q);
+                       wake_up_interruptible_all(&dev->tctl_wait_q);
+               }
+               up_read(&dev->state_sem);
+               schedule();
+       }
+
+       switch (dev->state & TASKDEV_ST_STATE_MASK) {
+
+       case TASKDEV_ST_NOTASK:
+               /* fine */
+               goto notask;
+
+       case TASKDEV_ST_ATTACHED:
+       case TASKDEV_ST_FREEZED:
+               /* task is working. kill it. */
+               dev->state = TASKDEV_ST_KILLING;
+               up_write(&dev->state_sem);
+               dsp_tdel_bh(dev, TDEL_KILL);
+               goto invalidate;
+
+       case TASKDEV_ST_ADDREQ:
+               /* open() is waiting. drain it. */
+               dev->state = TASKDEV_ST_ADDFAIL;
+               wake_up_interruptible_all(&dev->state_wait_q);
+               break;
+
+       case TASKDEV_ST_DELREQ:
+               /* nobody is waiting. */
+               dev->state = TASKDEV_ST_NOTASK;
+               wake_up_interruptible_all(&dev->state_wait_q);
+               break;
+
+       case TASKDEV_ST_ADDING:
+       case TASKDEV_ST_DELING:
+       case TASKDEV_ST_KILLING:
+       case TASKDEV_ST_GARBAGE:
+       case TASKDEV_ST_ADDFAIL:
+               /* transient state. wait for a moment. */
+               break;
+
+       }
+
+       up_write(&dev->state_sem);
+
+invalidate:
+       /* wait for some time and hope the state is settled */
+       devstate_read_lock_timeout(dev, TASKDEV_ST_NOTASK, 5 * HZ);
+       if (!(dev->state & TASKDEV_ST_NOTASK)) {
+               printk(KERN_WARNING
+                      "omapdsp: illegal device state (%s) on rmdev %s.\n",
+                      devstate_name(dev->state), dev->name);
+       }
+notask:
+       dev->state = TASKDEV_ST_INVALID;
+       devstate_read_unlock(dev);
+
+       taskdev_delete(minor);
+       kfree(dev);
+
+       return 0;
+}
+
+struct file_operations dsp_task_fops = {
+       .owner   = THIS_MODULE,
+       .poll    = dsp_task_poll,
+       .ioctl   = dsp_task_ioctl,
+       .open    = dsp_task_open,
+       .release = dsp_task_release,
+};
+
+static void dsptask_dev_release(struct device *dev)
+{
+}
+
+static int taskdev_init(struct taskdev *dev, char *name, unsigned char minor)
+{
+       int ret;
+
+       taskdev[minor] = dev;
+
+       spin_lock_init(&dev->proc_list_lock);
+       INIT_LIST_HEAD(&dev->proc_list);
+       init_waitqueue_head(&dev->read_wait_q);
+       init_waitqueue_head(&dev->write_wait_q);
+       init_waitqueue_head(&dev->tctl_wait_q);
+       mutex_init(&dev->read_mutex);
+       mutex_init(&dev->write_mutex);
+       mutex_init(&dev->tctl_mutex);
+       mutex_init(&dev->lock);
+       spin_lock_init(&dev->wsz_lock);
+       dev->tctl_ret = -EINVAL;
+       dev->lock_pid = 0;
+
+       strncpy(dev->name, name, TNM_LEN);
+       dev->name[TNM_LEN-1] = '\0';
+       dev->state = (minor < n_task) ? TASKDEV_ST_ATTACHED : TASKDEV_ST_NOTASK;
+       dev->usecount = 0;
+       mutex_init(&dev->usecount_lock);
+       memcpy(&dev->fops, &dsp_task_fops, sizeof(struct file_operations));
+
+       dev->dev.parent = omap_dsp->dev;
+       dev->dev.bus = &dsptask_bus;
+       sprintf(dev->dev.bus_id, "dsptask%d", minor);
+       dev->dev.release = dsptask_dev_release;
+       ret = device_register(&dev->dev);
+       if (ret)
+               printk(KERN_ERR "device_register failed: %d\n", ret);
+       ret = device_create_file(&dev->dev, &dev_attr_devname);
+       ret |= device_create_file(&dev->dev, &dev_attr_devstate);
+       ret |= device_create_file(&dev->dev, &dev_attr_proc_list);
+       if (ret)
+               printk(KERN_ERR "device_create_file failed: %d\n", ret);
+       class_device_create(dsp_task_class, NULL,
+                           MKDEV(OMAP_DSP_TASK_MAJOR, minor),
+                           NULL, "dsptask%d", minor);
+
+       init_waitqueue_head(&dev->state_wait_q);
+       init_rwsem(&dev->state_sem);
+
+       return 0;
+}
+
+static void taskdev_delete(unsigned char minor)
+{
+       struct taskdev *dev = taskdev[minor];
+
+       if (!dev)
+               return;
+       device_remove_file(&dev->dev, &dev_attr_devname);
+       device_remove_file(&dev->dev, &dev_attr_devstate);
+       device_remove_file(&dev->dev, &dev_attr_proc_list);
+       class_device_destroy(dsp_task_class, MKDEV(OMAP_DSP_TASK_MAJOR, minor));
+       device_unregister(&dev->dev);
+       proc_list_flush(&dev->proc_list_lock, &dev->proc_list);
+       taskdev[minor] = NULL;
+}
+
+static int taskdev_attach_task(struct taskdev *dev, struct dsptask *task)
+{
+       u16 ttyp = task->ttyp;
+       int ret;
+
+       dev->fops.read =
+               sndtyp_acv(ttyp) ?
+                       sndtyp_wd(ttyp) ? dsp_task_read_wd_acv:
+                       /* sndtyp_bk */   dsp_task_read_bk_acv:
+               /* sndtyp_psv */
+                       sndtyp_wd(ttyp) ? dsp_task_read_wd_psv:
+                       /* sndtyp_bk */   dsp_task_read_bk_psv;
+       if (sndtyp_wd(ttyp)) {
+               /* word */
+               size_t fifosz;
+
+               fifosz = sndtyp_psv(ttyp) ? 2 : /* passive */
+                                           32; /* active */
+               if (init_fifo(&dev->rcvdt.fifo, fifosz) < 0) {
+                       printk(KERN_ERR
+                              "omapdsp: unable to allocate receive buffer. "
+                              "(%d bytes for %s)\n", fifosz, dev->name);
+                       return -ENOMEM;
+               }
+       } else {
+               /* block */
+               INIT_IPBLINK(&dev->rcvdt.bk.link);
+               dev->rcvdt.bk.rp = 0;
+       }
+
+       dev->fops.write =
+               rcvtyp_wd(ttyp) ? dsp_task_write_wd:
+               /* rcvbyp_bk */   dsp_task_write_bk;
+       dev->wsz = rcvtyp_acv(ttyp) ? 0 :               /* active */
+                  rcvtyp_wd(ttyp)  ? 2 :               /* passive word */
+                                     ipbcfg.lsz*2;     /* passive block */
+
+       if (task->map_length)
+               dev->fops.mmap = dsp_task_mmap;
+
+       ret = device_create_file(&dev->dev, &dev_attr_taskname);
+       ret |= device_create_file(&dev->dev, &dev_attr_ttyp);
+       if (sndtyp_wd(ttyp)) {
+               ret |= device_create_file(&dev->dev, &dev_attr_fifosz);
+               ret |= device_create_file(&dev->dev, &dev_attr_fifocnt);
+       } else
+               ret |= device_create_file(&dev->dev, &dev_attr_ipblink);
+       ret |= device_create_file(&dev->dev, &dev_attr_wsz);
+       if (task->map_length)
+               ret |= device_create_file(&dev->dev, &dev_attr_mmap);
+       if (ret)
+               printk(KERN_ERR "device_create_file failed: %d\n", ret);
+
+       dev->task = task;
+       task->dev = dev;
+
+       return 0;
+}
+
+static void taskdev_detach_task(struct taskdev *dev)
+{
+       u16 ttyp = dev->task->ttyp;
+
+       device_remove_file(&dev->dev, &dev_attr_taskname);
+       device_remove_file(&dev->dev, &dev_attr_ttyp);
+       if (sndtyp_wd(ttyp)) {
+               device_remove_file(&dev->dev, &dev_attr_fifosz);
+               device_remove_file(&dev->dev, &dev_attr_fifocnt);
+       } else
+               device_remove_file(&dev->dev, &dev_attr_ipblink);
+       device_remove_file(&dev->dev, &dev_attr_wsz);
+       if (dev->task->map_length)
+               device_remove_file(&dev->dev, &dev_attr_mmap);
+
+       dev->fops.read = NULL;
+       taskdev_flush_buf(dev);
+       if (sndtyp_wd(ttyp))
+               free_fifo(&dev->rcvdt.fifo);
+
+       dev->fops.write = NULL;
+       dev->wsz = 0;
+
+       printk(KERN_INFO "omapdsp: taskdev %s disabled.\n", dev->name);
+       dev->task = NULL;
+}
+
+/*
+ * tadd / tdel / tkill
+ */
+static int dsp_tadd(struct taskdev *dev, dsp_long_t adr)
+{
+       struct dsptask *task;
+       struct mb_exarg arg;
+       u8 tid, tid_response;
+       u16 argv[2];
+       int ret = 0;
+
+       if (!devstate_write_lock_and_test(dev, TASKDEV_ST_ADDREQ)) {
+               printk(KERN_ERR
+                      "omapdsp: taskdev %s is not requesting for tadd. "
+                      "(state is %s)\n", dev->name, devstate_name(dev->state));
+               return -EINVAL;
+       }
+       dev->state = TASKDEV_ST_ADDING;
+       devstate_write_unlock(dev);
+
+       if (adr == TADD_ABORTADR) {
+               /* aborting tadd intentionally */
+               printk(KERN_INFO "omapdsp: tadd address is ABORTADR.\n");
+               goto fail_out;
+       }
+       if (adr >= DSPSPACE_SIZE) {
+               printk(KERN_ERR
+                      "omapdsp: illegal address 0x%08x for tadd\n", adr);
+               ret = -EINVAL;
+               goto fail_out;
+       }
+
+       adr >>= 1;      /* word address */
+       argv[0] = adr >> 16;    /* addrh */
+       argv[1] = adr & 0xffff; /* addrl */
+
+       if (mutex_lock_interruptible(&cfg_lock)) {
+               ret = -EINTR;
+               goto fail_out;
+       }
+       cfg_tid = TID_ANON;
+       cfg_cmd = MBOX_CMD_DSP_TADD;
+       arg.tid  = TID_ANON;
+       arg.argc = 2;
+       arg.argv = argv;
+
+       if (dsp_mem_sync_inc() < 0) {
+               printk(KERN_ERR "omapdsp: memory sync failed!\n");
+               ret = -EBUSY;
+               goto fail_out;
+       }
+       mbcompose_send_and_wait_exarg(TADD, 0, 0, &arg, &cfg_wait_q);
+
+       tid = cfg_tid;
+       cfg_tid = TID_ANON;
+       cfg_cmd = 0;
+       mutex_unlock(&cfg_lock);
+
+       if (tid == TID_ANON) {
+               printk(KERN_ERR "omapdsp: tadd failed!\n");
+               ret = -EINVAL;
+               goto fail_out;
+       }
+       if ((tid < n_task) || dsptask[tid]) {
+               printk(KERN_ERR "omapdsp: illegal tid (%d)!\n", tid);
+               ret = -EINVAL;
+               goto fail_out;
+       }
+       if ((task = kzalloc(sizeof(struct dsptask), GFP_KERNEL)) == NULL) {
+               ret = -ENOMEM;
+               goto del_out;
+       }
+
+       if ((ret = dsp_task_config(task, tid)) < 0)
+               goto free_out;
+
+       if (strcmp(dev->name, task->name)) {
+               printk(KERN_ERR
+                      "omapdsp: task name (%s) doesn't match with "
+                      "device name (%s).\n", task->name, dev->name);
+               ret = -EINVAL;
+               goto free_out;
+       }
+
+       if ((ret = taskdev_attach_task(dev, task)) < 0)
+               goto free_out;
+
+       dsp_task_init(task);
+       printk(KERN_INFO "omapdsp: taskdev %s enabled.\n", dev->name);
+       dev->state = TASKDEV_ST_ATTACHED;
+       wake_up_interruptible_all(&dev->state_wait_q);
+       return 0;
+
+free_out:
+       kfree(task);
+
+del_out:
+       printk(KERN_ERR "omapdsp: deleting the task...\n");
+
+       dev->state = TASKDEV_ST_DELING;
+
+       if (mutex_lock_interruptible(&cfg_lock)) {
+               printk(KERN_ERR "omapdsp: aborting tdel process. "
+                               "DSP side could be corrupted.\n");
+               goto fail_out;
+       }
+       cfg_tid = TID_ANON;
+       cfg_cmd = MBOX_CMD_DSP_TDEL;
+       mbcompose_send_and_wait(TDEL, tid, TDEL_KILL, &cfg_wait_q);
+       tid_response = cfg_tid;
+       cfg_tid = TID_ANON;
+       cfg_cmd = 0;
+       mutex_unlock(&cfg_lock);
+
+       if (tid_response != tid)
+               printk(KERN_ERR "omapdsp: tdel failed. "
+                               "DSP side could be corrupted.\n");
+
+fail_out:
+       dev->state = TASKDEV_ST_ADDFAIL;
+       wake_up_interruptible_all(&dev->state_wait_q);
+       return ret;
+}
+
+int dsp_tadd_minor(unsigned char minor, dsp_long_t adr)
+{
+       struct taskdev *dev;
+       int status;
+       int ret;
+
+       if (mutex_lock_interruptible(&devmgr_lock))
+               return -EINTR;
+
+       if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
+               printk(KERN_ERR
+                      "omapdsp: no task device with minor %d\n", minor);
+               ret = -EINVAL;
+               goto out;
+       }
+       ret = minor;
+       if ((status = dsp_tadd(dev, adr)) < 0)
+               ret = status;
+
+out:
+       mutex_unlock(&devmgr_lock);
+       return ret;
+}
+
+static int dsp_tdel(struct taskdev *dev)
+{
+       if (!devstate_write_lock_and_test(dev, TASKDEV_ST_DELREQ)) {
+               printk(KERN_ERR
+                      "omapdsp: taskdev %s is not requesting for tdel. "
+                      "(state is %s)\n", dev->name, devstate_name(dev->state));
+               return -EINVAL;
+       }
+       dev->state = TASKDEV_ST_DELING;
+       devstate_write_unlock(dev);
+
+       return dsp_tdel_bh(dev, TDEL_SAFE);
+}
+
+int dsp_tdel_minor(unsigned char minor)
+{
+       struct taskdev *dev;
+       int status;
+       int ret;
+
+       if (mutex_lock_interruptible(&devmgr_lock))
+               return -EINTR;
+
+       if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
+               printk(KERN_ERR
+                      "omapdsp: no task device with minor %d\n", minor);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = minor;
+       if ((status = dsp_tdel(dev)) < 0)
+               ret = status;
+
+out:
+       mutex_unlock(&devmgr_lock);
+       return ret;
+}
+
+static int dsp_tkill(struct taskdev *dev)
+{
+       while (!down_write_trylock(&dev->state_sem)) {
+               if (!devstate_read_lock_and_test(dev, (TASKDEV_ST_ATTACHED |
+                                                      TASKDEV_ST_FREEZED))) {
+                       printk(KERN_ERR
+                              "omapdsp: task has not been attached for "
+                              "taskdev %s\n", dev->name);
+                       return -EINVAL;
+               }
+               /* ATTACHED -> FREEZED can be changed under read semaphore. */
+               dev->state = TASKDEV_ST_FREEZED;
+               wake_up_interruptible_all(&dev->read_wait_q);
+               wake_up_interruptible_all(&dev->write_wait_q);
+               wake_up_interruptible_all(&dev->tctl_wait_q);
+               devstate_read_unlock(dev);
+               schedule();
+       }
+
+       if (!(dev->state & (TASKDEV_ST_ATTACHED |
+                           TASKDEV_ST_FREEZED))) {
+               printk(KERN_ERR
+                      "omapdsp: task has not been attached for taskdev %s\n",
+                      dev->name);
+               devstate_write_unlock(dev);
+               return -EINVAL;
+       }
+       if (!is_dynamic_task(dev->task->tid)) {
+               printk(KERN_ERR "omapdsp: task %s is not a dynamic task.\n",
+                      dev->name);
+               devstate_write_unlock(dev);
+               return -EINVAL;
+       }
+       dev->state = TASKDEV_ST_KILLING;
+       devstate_write_unlock(dev);
+
+       return dsp_tdel_bh(dev, TDEL_KILL);
+}
+
+int dsp_tkill_minor(unsigned char minor)
+{
+       struct taskdev *dev;
+       int status;
+       int ret;
+
+       if (mutex_lock_interruptible(&devmgr_lock))
+               return -EINTR;
+
+       if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
+               printk(KERN_ERR
+                      "omapdsp: no task device with minor %d\n", minor);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = minor;
+       if ((status = dsp_tkill(dev)) < 0)
+               ret = status;
+
+out:
+       mutex_unlock(&devmgr_lock);
+       return ret;
+}
+
+static int dsp_tdel_bh(struct taskdev *dev, u16 type)
+{
+       struct dsptask *task;
+       u8 tid, tid_response;
+       int ret = 0;
+
+       task = dev->task;
+       tid = task->tid;
+       if (mutex_lock_interruptible(&cfg_lock)) {
+               if (type == TDEL_SAFE) {
+                       dev->state = TASKDEV_ST_DELREQ;
+                       return -EINTR;
+               } else {
+                       tid_response = TID_ANON;
+                       ret = -EINTR;
+                       goto detach_out;
+               }
+       }
+       cfg_tid = TID_ANON;
+       cfg_cmd = MBOX_CMD_DSP_TDEL;
+       mbcompose_send_and_wait(TDEL, tid, type, &cfg_wait_q);
+       tid_response = cfg_tid;
+       cfg_tid = TID_ANON;
+       cfg_cmd = 0;
+       mutex_unlock(&cfg_lock);
+
+detach_out:
+       taskdev_detach_task(dev);
+       dsp_task_unconfig(task);
+       kfree(task);
+
+       if (tid_response != tid) {
+               printk(KERN_ERR "omapdsp: %s failed!\n",
+                      (type == TDEL_SAFE) ? "tdel" : "tkill");
+               ret = -EINVAL;
+       }
+       down_write(&dev->state_sem);
+       dev->state = (dev->usecount > 0) ? TASKDEV_ST_GARBAGE :
+                                          TASKDEV_ST_NOTASK;
+       wake_up_interruptible_all(&dev->state_wait_q);
+       up_write(&dev->state_sem);
+
+       return ret;
+}
+
+/*
+ * state inquiry
+ */
+long taskdev_state_stale(unsigned char minor)
+{
+       if (taskdev[minor]) {
+               long state = taskdev[minor]->state;
+               taskdev[minor]->state |= TASKDEV_ST_STALE;
+               return state;
+       } else
+               return TASKDEV_ST_NOTASK;
+}
+
+/*
+ * functions called from mailbox interrupt routine
+ */
+void mbox_wdsnd(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       struct dsptask *task = dsptask[tid];
+
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: WDSND with illegal tid! %d\n", tid);
+               return;
+       }
+       if (sndtyp_bk(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: WDSND from block sending task! (task%d)\n", tid);
+               return;
+       }
+       if (sndtyp_psv(task->ttyp) &&
+           !waitqueue_active(&task->dev->read_wait_q)) {
+               printk(KERN_WARNING
+                      "mbox: WDSND from passive sending task (task%d) "
+                      "without request!\n", tid);
+               return;
+       }
+
+       write_word_to_fifo(&task->dev->rcvdt.fifo, mb->data);
+       wake_up_interruptible(&task->dev->read_wait_q);
+}
+
+void mbox_wdreq(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       struct dsptask *task = dsptask[tid];
+       struct taskdev *dev;
+
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: WDREQ with illegal tid! %d\n", tid);
+               return;
+       }
+       if (rcvtyp_psv(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: WDREQ from passive receiving task! (task%d)\n",
+                      tid);
+               return;
+       }
+
+       dev = task->dev;
+       spin_lock(&dev->wsz_lock);
+       dev->wsz = 2;
+       spin_unlock(&dev->wsz_lock);
+       wake_up_interruptible(&dev->write_wait_q);
+}
+
+void mbox_bksnd(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       u16 bid = mb->data;
+       struct dsptask *task = dsptask[tid];
+       struct ipbuf_head *ipb_h;
+       u16 cnt;
+
+       if (bid >= ipbcfg.ln) {
+               printk(KERN_ERR "mbox: BKSND with illegal bid! %d\n", bid);
+               return;
+       }
+       ipb_h = bid_to_ipbuf(bid);
+       ipb_bsycnt_dec(&ipbcfg);
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: BKSND with illegal tid! %d\n", tid);
+               goto unuse_ipbuf_out;
+       }
+       if (sndtyp_wd(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKSND from word sending task! (task%d)\n", tid);
+               goto unuse_ipbuf_out;
+       }
+       if (sndtyp_pvt(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKSND from private sending task! (task%d)\n", tid);
+               goto unuse_ipbuf_out;
+       }
+       if (sync_with_dsp(&ipb_h->p->sd, tid, 10) < 0) {
+               printk(KERN_ERR "mbox: BKSND - IPBUF sync failed!\n");
+               return;
+       }
+
+       /* should be done in DSP, but just in case. */
+       ipb_h->p->next = BID_NULL;
+
+       cnt = ipb_h->p->c;
+       if (cnt > ipbcfg.lsz) {
+               printk(KERN_ERR "mbox: BKSND cnt(%d) > ipbuf line size(%d)!\n",
+                      cnt, ipbcfg.lsz);
+               goto unuse_ipbuf_out;
+       }
+
+       if (cnt == 0) {
+               /* 0-byte send from DSP */
+               unuse_ipbuf_nowait(ipb_h);
+               goto done;
+       }
+       ipblink_add_tail(&task->dev->rcvdt.bk.link, bid);
+       /* we keep coming bid and return alternative line to DSP. */
+       balance_ipbuf();
+
+done:
+       wake_up_interruptible(&task->dev->read_wait_q);
+       return;
+
+unuse_ipbuf_out:
+       unuse_ipbuf_nowait(ipb_h);
+       return;
+}
+
+void mbox_bkreq(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       u16 cnt = mb->data;
+       struct dsptask *task = dsptask[tid];
+       struct taskdev *dev;
+
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: BKREQ with illegal tid! %d\n", tid);
+               return;
+       }
+       if (rcvtyp_wd(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKREQ from word receiving task! (task%d)\n", tid);
+               return;
+       }
+       if (rcvtyp_pvt(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKREQ from private receiving task! (task%d)\n",
+                      tid);
+               return;
+       }
+       if (rcvtyp_psv(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKREQ from passive receiving task! (task%d)\n",
+                      tid);
+               return;
+       }
+
+       dev = task->dev;
+       spin_lock(&dev->wsz_lock);
+       dev->wsz = cnt*2;
+       spin_unlock(&dev->wsz_lock);
+       wake_up_interruptible(&dev->write_wait_q);
+}
+
+void mbox_bkyld(struct mbcmd *mb)
+{
+       u16 bid = mb->data;
+       struct ipbuf_head *ipb_h;
+
+       if (bid >= ipbcfg.ln) {
+               printk(KERN_ERR "mbox: BKYLD with illegal bid! %d\n", bid);
+               return;
+       }
+       ipb_h = bid_to_ipbuf(bid);
+
+       /* should be done in DSP, but just in case. */
+       ipb_h->p->next = BID_NULL;
+
+       /* we don't need to sync with DSP */
+       ipb_bsycnt_dec(&ipbcfg);
+       release_ipbuf(ipb_h);
+}
+
+void mbox_bksndp(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       struct dsptask *task = dsptask[tid];
+       struct ipbuf_p *ipbp;
+
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: BKSNDP with illegal tid! %d\n", tid);
+               return;
+       }
+       if (sndtyp_wd(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKSNDP from word sending task! (task%d)\n", tid);
+               return;
+       }
+       if (sndtyp_gbl(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKSNDP from non-private sending task! (task%d)\n",
+                      tid);
+               return;
+       }
+
+       /*
+        * we should not have delayed block at this point
+        * because read() routine releases the lock of the buffer and
+        * until then DSP can't send next data.
+        */
+
+       ipbp = task->ipbuf_pvt_r;
+       if (sync_with_dsp(&ipbp->s, tid, 10) < 0) {
+               printk(KERN_ERR "mbox: BKSNDP - IPBUF sync failed!\n");
+               return;
+       }
+       printk(KERN_DEBUG "mbox: ipbuf_pvt_r->a = 0x%08lx\n",
+              MKLONG(ipbp->ah, ipbp->al));
+       ipblink_add_pvt(&task->dev->rcvdt.bk.link);
+       wake_up_interruptible(&task->dev->read_wait_q);
+}
+
+void mbox_bkreqp(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       struct dsptask *task = dsptask[tid];
+       struct taskdev *dev;
+       struct ipbuf_p *ipbp;
+
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: BKREQP with illegal tid! %d\n", tid);
+               return;
+       }
+       if (rcvtyp_wd(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKREQP from word receiving task! (task%d)\n", tid);
+               return;
+       }
+       if (rcvtyp_gbl(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKREQP from non-private receiving task! (task%d)\n", tid);
+               return;
+       }
+       if (rcvtyp_psv(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKREQP from passive receiving task! (task%d)\n", tid);
+               return;
+       }
+
+       ipbp = task->ipbuf_pvt_w;
+       if (sync_with_dsp(&ipbp->s, TID_FREE, 10) < 0) {
+               printk(KERN_ERR "mbox: BKREQP - IPBUF sync failed!\n");
+               return;
+       }
+       printk(KERN_DEBUG "mbox: ipbuf_pvt_w->a = 0x%08lx\n",
+              MKLONG(ipbp->ah, ipbp->al));
+       dev = task->dev;
+       spin_lock(&dev->wsz_lock);
+       dev->wsz = ipbp->c*2;
+       spin_unlock(&dev->wsz_lock);
+       wake_up_interruptible(&dev->write_wait_q);
+}
+
+void mbox_tctl(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       struct dsptask *task = dsptask[tid];
+
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: TCTL with illegal tid! %d\n", tid);
+               return;
+       }
+
+       if (!waitqueue_active(&task->dev->tctl_wait_q)) {
+               printk(KERN_WARNING "mbox: unexpected TCTL from DSP!\n");
+               return;
+       }
+
+       task->dev->tctl_stat = mb->data;
+       wake_up_interruptible(&task->dev->tctl_wait_q);
+}
+
+void mbox_tcfg(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       struct dsptask *task = dsptask[tid];
+       u16 *tnm;
+       volatile u16 *buf;
+       int i;
+
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: TCFG with illegal tid! %d\n", tid);
+               return;
+       }
+       if ((task->state != TASK_ST_CFGREQ) || (cfg_cmd != MBOX_CMD_DSP_TCFG)) {
+               printk(KERN_WARNING "mbox: unexpected TCFG from DSP!\n");
+               return;
+       }
+
+       if (dsp_mem_enable(ipbuf_sys_da) < 0) {
+               printk(KERN_ERR "mbox: TCFG - ipbuf_sys_da read failed!\n");
+               dsp_mem_disable(ipbuf_sys_da);
+               goto out;
+       }
+       if (sync_with_dsp(&ipbuf_sys_da->s, tid, 10) < 0) {
+               printk(KERN_ERR "mbox: TCFG - IPBUF sync failed!\n");
+               dsp_mem_disable(ipbuf_sys_da);
+               goto out;
+       }
+
+       /*
+        * read configuration data on system IPBUF
+        */
+       buf = ipbuf_sys_da->d;
+       task->ttyp        = buf[0];
+       task->ipbuf_pvt_r = MKVIRT(buf[1], buf[2]);
+       task->ipbuf_pvt_w = MKVIRT(buf[3], buf[4]);
+       task->map_base    = MKVIRT(buf[5], buf[6]);
+       task->map_length  = MKLONG(buf[7], buf[8]) << 1;        /* word -> byte */
+       tnm               = MKVIRT(buf[9], buf[10]);
+       release_ipbuf_pvt(ipbuf_sys_da);
+       dsp_mem_disable(ipbuf_sys_da);
+
+       /*
+        * copy task name string
+        */
+       if (dsp_address_validate(tnm, TNM_LEN, "task name buffer") < 0) {
+               task->name[0] = '\0';
+               goto out;
+       }
+
+       for (i = 0; i < TNM_LEN-1; i++) {
+               /* avoiding byte access */
+               u16 tmp = tnm[i];
+               task->name[i] = tmp & 0x00ff;
+               if (!tmp)
+                       break;
+       }
+       task->name[TNM_LEN-1] = '\0';
+
+       task->state = TASK_ST_READY;
+out:
+       wake_up_interruptible(&cfg_wait_q);
+}
+
+void mbox_tadd(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+
+       if ((!waitqueue_active(&cfg_wait_q)) || (cfg_cmd != MBOX_CMD_DSP_TADD)) {
+               printk(KERN_WARNING "mbox: unexpected TADD from DSP!\n");
+               return;
+       }
+       cfg_tid = tid;
+       wake_up_interruptible(&cfg_wait_q);
+}
+
+void mbox_tdel(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+
+       if ((!waitqueue_active(&cfg_wait_q)) || (cfg_cmd != MBOX_CMD_DSP_TDEL)) {
+               printk(KERN_WARNING "mbox: unexpected TDEL from DSP!\n");
+               return;
+       }
+       cfg_tid = tid;
+       wake_up_interruptible(&cfg_wait_q);
+}
+
+void mbox_err_fatal(u8 tid)
+{
+       struct dsptask *task = dsptask[tid];
+       struct taskdev *dev;
+
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: FATAL ERR with illegal tid! %d\n", tid);
+               return;
+       }
+
+       /* wake up waiting processes */
+       dev = task->dev;
+       wake_up_interruptible_all(&dev->read_wait_q);
+       wake_up_interruptible_all(&dev->write_wait_q);
+       wake_up_interruptible_all(&dev->tctl_wait_q);
+}
+
+static u16 *dbg_buf;
+static u16 dbg_buf_sz, dbg_line_sz;
+static int dbg_rp;
+
+int dsp_dbg_config(u16 *buf, u16 sz, u16 lsz)
+{
+#ifdef OLD_BINARY_SUPPORT
+       if ((mbox_revision == MBREV_3_0) || (mbox_revision == MBREV_3_2)) {
+               dbg_buf = NULL;
+               dbg_buf_sz = 0;
+               dbg_line_sz = 0;
+               dbg_rp = 0;
+               return 0;
+       }
+#endif
+
+       if (dsp_address_validate(buf, sz, "debug buffer") < 0)
+               return -1;
+
+       if (lsz > sz) {
+               printk(KERN_ERR
+                      "omapdsp: dbg_buf lsz (%d) is greater than its "
+                      "buffer size (%d)\n", lsz, sz);
+               return -1;
+       }
+
+       dbg_buf = buf;
+       dbg_buf_sz = sz;
+       dbg_line_sz = lsz;
+       dbg_rp = 0;
+
+       return 0;
+}
+
+void dsp_dbg_stop(void)
+{
+       dbg_buf = NULL;
+}
+
+#ifdef OLD_BINARY_SUPPORT
+static void mbox_dbg_old(struct mbcmd *mb);
+#endif
+
+void mbox_dbg(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       int cnt = mb->data;
+       char s[80], *s_end = &s[79], *p;
+       u16 *src;
+       int i;
+
+#ifdef OLD_BINARY_SUPPORT
+       if ((mbox_revision == MBREV_3_0) || (mbox_revision == MBREV_3_2)) {
+               mbox_dbg_old(mb);
+               return;
+       }
+#endif
+
+       if (((tid >= TASKDEV_MAX) || (dsptask[tid] == NULL)) &&
+           (tid != TID_ANON)) {
+               printk(KERN_ERR "mbox: DBG with illegal tid! %d\n", tid);
+               return;
+       }
+       if (dbg_buf == NULL) {
+               printk(KERN_ERR "mbox: DBG command received, but "
+                      "dbg_buf has not been configured yet.\n");
+               return;
+       }
+
+       if (dsp_mem_enable(dbg_buf) < 0)
+               return;
+
+       src = &dbg_buf[dbg_rp];
+       p = s;
+       for (i = 0; i < cnt; i++) {
+               u16 tmp;
+               /*
+                * Be carefull that dbg_buf should not be read with
+                * 1-byte access since it might be placed in DARAM/SARAM
+                * and it can cause unexpected byteswap.
+                * For example,
+                *   *(p++) = *(src++) & 0xff;
+                * causes 1-byte access!
+                */
+               tmp = *src++;
+               *(p++) = tmp & 0xff;
+               if (*(p-1) == '\n') {
+                       *p = '\0';
+                       printk(KERN_INFO "%s", s);
+                       p = s;
+                       continue;
+               }
+               if (p == s_end) {
+                       *p = '\0';
+                       printk(KERN_INFO "%s\n", s);
+                       p = s;
+                       continue;
+               }
+       }
+       if (p > s) {
+               *p = '\0';
+               printk(KERN_INFO "%s\n", s);
+       }
+       if ((dbg_rp += cnt + 1) > dbg_buf_sz - dbg_line_sz)
+               dbg_rp = 0;
+
+       dsp_mem_disable(dbg_buf);
+}
+
+#ifdef OLD_BINARY_SUPPORT
+static void mbox_dbg_old(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       char s[80], *s_end = &s[79], *p;
+       u16 *src;
+       volatile u16 *buf;
+       int cnt;
+       int i;
+
+       if (((tid >= TASKDEV_MAX) || (dsptask[tid] == NULL)) &&
+           (tid != TID_ANON)) {
+               printk(KERN_ERR "mbox: DBG with illegal tid! %d\n", tid);
+               return;
+       }
+       if (dsp_mem_enable(ipbuf_sys_da) < 0) {
+               printk(KERN_ERR "mbox: DBG - ipbuf_sys_da read failed!\n");
+               return;
+       }
+       if (sync_with_dsp(&ipbuf_sys_da->s, tid, 10) < 0) {
+               printk(KERN_ERR "mbox: DBG - IPBUF sync failed!\n");
+               goto out1;
+       }
+       buf = ipbuf_sys_da->d;
+       cnt = buf[0];
+       src = MKVIRT(buf[1], buf[2]);
+       if (dsp_address_validate(src, cnt, "dbg buffer") < 0)
+               goto out2;
+
+       if (dsp_mem_enable(src) < 0)
+               goto out2;
+
+       p = s;
+       for (i = 0; i < cnt; i++) {
+               u16 tmp;
+               /*
+                * Be carefull that ipbuf should not be read with
+                * 1-byte access since it might be placed in DARAM/SARAM
+                * and it can cause unexpected byteswap.
+                * For example,
+                *   *(p++) = *(src++) & 0xff;
+                * causes 1-byte access!
+                */
+               tmp = *src++;
+               *(p++) = tmp & 0xff;
+               if (*(p-1) == '\n') {
+                       *p = '\0';
+                       printk(KERN_INFO "%s", s);
+                       p = s;
+                       continue;
+               }
+               if (p == s_end) {
+                       *p = '\0';
+                       printk(KERN_INFO "%s\n", s);
+                       p = s;
+                       continue;
+               }
+       }
+       if (p > s) {
+               *p = '\0';
+               printk(KERN_INFO "%s\n", s);
+       }
+
+       dsp_mem_disable(src);
+out2:
+       release_ipbuf_pvt(ipbuf_sys_da);
+out1:
+       dsp_mem_disable(ipbuf_sys_da);
+}
+#endif /* OLD_BINARY_SUPPORT */
+
+/*
+ * sysfs files: for each device
+ */
+
+/* devname */
+static ssize_t devname_show(struct device *d, struct device_attribute *attr,
+                           char *buf)
+{
+       return sprintf(buf, "%s\n", to_taskdev(d)->name);
+}
+
+/* devstate */
+static ssize_t devstate_show(struct device *d, struct device_attribute *attr,
+                            char *buf)
+{
+       return sprintf(buf, "%s\n", devstate_name(to_taskdev(d)->state));
+}
+
+/* proc_list */
+static ssize_t proc_list_show(struct device *d, struct device_attribute *attr,
+                             char *buf)
+{
+       struct taskdev *dev;
+       struct proc_list *pl;
+       int len = 0;
+
+       dev = to_taskdev(d);
+       spin_lock(&dev->proc_list_lock);
+       list_for_each_entry(pl, &dev->proc_list, list_head) {
+               /* need to lock tasklist_lock before calling
+                * find_task_by_pid_type. */
+               if (find_task_by_pid_type(PIDTYPE_PID, pl->pid) != NULL)
+                       len += sprintf(buf + len, "%d\n", pl->pid);
+               read_unlock(&tasklist_lock);
+       }
+       spin_unlock(&dev->proc_list_lock);
+
+       return len;
+}
+
+/* taskname */
+static ssize_t taskname_show(struct device *d, struct device_attribute *attr,
+                            char *buf)
+{
+       struct taskdev *dev = to_taskdev(d);
+       int len;
+
+       if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+               return -ENODEV;
+
+       len = sprintf(buf, "%s\n", dev->task->name);
+
+       devstate_read_unlock(dev);
+       return len;
+}
+
+/* ttyp */
+static ssize_t ttyp_show(struct device *d, struct device_attribute *attr,
+                        char *buf)
+{
+       struct taskdev *dev = to_taskdev(d);
+       u16 ttyp;
+       int len = 0;
+
+       if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+               return -ENODEV;
+
+       ttyp = dev->task->ttyp;
+       len += sprintf(buf + len, "0x%04x\n", ttyp);
+       len += sprintf(buf + len, "%s %s send\n",
+                       (sndtyp_acv(ttyp)) ? "active" :
+                                            "passive",
+                       (sndtyp_wd(ttyp))  ? "word" :
+                       (sndtyp_pvt(ttyp)) ? "private block" :
+                                            "global block");
+       len += sprintf(buf + len, "%s %s receive\n",
+                       (rcvtyp_acv(ttyp)) ? "active" :
+                                            "passive",
+                       (rcvtyp_wd(ttyp))  ? "word" :
+                       (rcvtyp_pvt(ttyp)) ? "private block" :
+                                            "global block");
+
+       devstate_read_unlock(dev);
+       return len;
+}
+
+/* fifosz */
+static ssize_t fifosz_show(struct device *d, struct device_attribute *attr,
+                          char *buf)
+{
+       struct fifo_struct *fifo = &to_taskdev(d)->rcvdt.fifo;
+       return sprintf(buf, "%d\n", fifo->sz);
+}
+
+static int fifosz_store(struct device *d, struct device_attribute *attr,
+                       const char *buf, size_t count)
+{
+       struct taskdev *dev = to_taskdev(d);
+       unsigned long fifosz;
+       int ret;
+
+       fifosz = simple_strtol(buf, NULL, 10);
+       ret = taskdev_set_fifosz(dev, fifosz);
+
+       return (ret < 0) ? ret : strlen(buf);
+}
+
+/* fifocnt */
+static ssize_t fifocnt_show(struct device *d, struct device_attribute *attr,
+                           char *buf)
+{
+       struct fifo_struct *fifo = &to_taskdev(d)->rcvdt.fifo;
+       return sprintf(buf, "%d\n", fifo->cnt);
+}
+
+/* ipblink */
+static __inline__ char *bid_name(u16 bid)
+{
+       static char s[6];
+
+       switch (bid) {
+       case BID_NULL:
+               return "NULL";
+       case BID_PVT:
+               return "PRIVATE";
+       default:
+               sprintf(s, "%d", bid);
+               return s;
+       }
+}
+
+static ssize_t ipblink_show(struct device *d, struct device_attribute *attr,
+                           char *buf)
+{
+       struct rcvdt_bk_struct *rcvdt = &to_taskdev(d)->rcvdt.bk;
+       int len;
+
+       spin_lock(&rcvdt->link.lock);
+       len = sprintf(buf, "top  %s\ntail %s\n",
+                     bid_name(rcvdt->link.top), bid_name(rcvdt->link.tail));
+       spin_unlock(&rcvdt->link.lock);
+
+       return len;
+}
+
+/* wsz */
+static ssize_t wsz_show(struct device *d, struct device_attribute *attr,
+                       char *buf)
+{
+       return sprintf(buf, "%d\n", to_taskdev(d)->wsz);
+}
+
+/* mmap */
+static ssize_t mmap_show(struct device *d, struct device_attribute *attr,
+                        char *buf)
+{
+       struct dsptask *task = to_taskdev(d)->task;
+       return sprintf(buf, "0x%p 0x%x\n", task->map_base, task->map_length);
+}
+
+/*
+ * called from ipbuf_show()
+ */
+int ipbuf_is_held(u8 tid, u16 bid)
+{
+       struct dsptask *task = dsptask[tid];
+       struct ipblink *link;
+       u16 b;
+       int ret = 0;
+
+       if (task == NULL)
+               return 0;
+
+       link = &task->dev->rcvdt.bk.link;
+       spin_lock(&link->lock);
+       ipblink_for_each(b, link) {
+               if (b == bid) { /* found */
+                       ret = 1;
+                       break;
+               }
+       }
+       spin_unlock(&link->lock);
+
+       return ret;
+}
+
+int __init dsp_taskmod_init(void)
+{
+       int retval;
+
+       memset(taskdev, 0, sizeof(void *) * TASKDEV_MAX);
+       memset(dsptask, 0, sizeof(void *) * TASKDEV_MAX);
+
+       retval = register_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask",
+                                &dsp_task_fops);
+       if (retval < 0) {
+               printk(KERN_ERR
+                      "omapdsp: failed to register task device: %d\n", retval);
+               return retval;
+       }
+
+       retval = bus_register(&dsptask_bus);
+       if (retval) {
+               printk(KERN_ERR
+                      "omapdsp: failed to register DSP task bus: %d\n",
+                      retval);
+               unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
+               return -EINVAL;
+       }
+       retval = driver_register(&dsptask_driver);
+       if (retval) {
+               printk(KERN_ERR
+                      "omapdsp: failed to register DSP task driver: %d\n",
+                      retval);
+               bus_unregister(&dsptask_bus);
+               unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
+               return -EINVAL;
+       }
+       dsp_task_class = class_create(THIS_MODULE, "dsptask");
+
+       return 0;
+}
+
+void dsp_taskmod_exit(void)
+{
+       class_destroy(dsp_task_class);
+       driver_unregister(&dsptask_driver);
+       bus_unregister(&dsptask_bus);
+       unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
+}
diff --git a/arch/arm/plat-omap/dsp/taskwatch.c b/arch/arm/plat-omap/dsp/taskwatch.c
new file mode 100644 (file)
index 0000000..cfec6b3
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <asm/uaccess.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ioctl.h"
+
+static DECLARE_WAIT_QUEUE_HEAD(read_wait_q);
+static unsigned int change_cnt;
+
+void dsp_twch_touch(void)
+{
+       change_cnt++;
+       wake_up_interruptible(&read_wait_q);
+}
+
+/*
+ * @count: represents the device counts of the user's interst
+ */
+static ssize_t dsp_twch_read(struct file *file, char __user *buf, size_t count,
+                            loff_t *ppos)
+{
+       long taskstat[TASKDEV_MAX];
+       int devcount = count / sizeof(long);
+       int i;
+
+       if (dsp_cfgstat_get_stat() != CFGSTAT_READY) {
+               printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
+               return -EINVAL;
+       }
+
+       if (change_cnt == 0) {
+               long current_state;
+               DECLARE_WAITQUEUE(wait, current);
+
+               add_wait_queue(&read_wait_q, &wait);
+               current_state = current->state;
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (change_cnt == 0)    /* last check */
+                       schedule();
+               set_current_state(current_state);
+               remove_wait_queue(&read_wait_q, &wait);
+
+               /* unconfigured while waiting ;-( */
+               if (dsp_cfgstat_get_stat() != CFGSTAT_READY)
+                       return -EINVAL;
+       }
+
+       if (devcount > TASKDEV_MAX)
+               devcount = TASKDEV_MAX;
+
+       count = devcount * sizeof(long);
+       change_cnt = 0;
+       for (i = 0; i < devcount; i++) {
+               /*
+                * once the device state is read, the 'STALE' bit will be set
+                * so that the Dynamic Loader can distinguish the new request
+                * from the old one.
+                */
+               taskstat[i] = taskdev_state_stale(i);
+       }
+
+       if (copy_to_user(buf, taskstat, count))
+               return -EFAULT;
+
+       return count;
+}
+
+static unsigned int dsp_twch_poll(struct file *file, poll_table *wait)
+{
+       unsigned int mask = 0;
+
+       poll_wait(file, &read_wait_q, wait);
+       if (change_cnt)
+               mask |= POLLIN | POLLRDNORM;
+
+       return mask;
+}
+
+static int dsp_twch_ioctl(struct inode *inode, struct file *file,
+                         unsigned int cmd, unsigned long arg)
+{
+       int ret;
+
+       switch (cmd) {
+       case TWCH_IOCTL_MKDEV:
+               {
+                       char name[TNM_LEN];
+                       if (copy_from_user(name, (void __user *)arg, TNM_LEN))
+                               return -EFAULT;
+                       name[TNM_LEN-1] = '\0';
+                       ret = dsp_mkdev(name);
+                       break;
+               }
+
+       case TWCH_IOCTL_RMDEV:
+               {
+                       char name[TNM_LEN];
+                       if (copy_from_user(name, (void __user *)arg, TNM_LEN))
+                               return -EFAULT;
+                       name[TNM_LEN-1] = '\0';
+                       ret = dsp_rmdev(name);
+                       break;
+               }
+
+       case TWCH_IOCTL_TADD:
+               {
+                       struct omap_dsp_taddinfo ti;
+                       if (copy_from_user(&ti, (void __user *)arg, sizeof(ti)))
+                               return -EFAULT;
+                       ret = dsp_tadd_minor(ti.minor, ti.taskadr);
+                       break;
+               }
+
+       case TWCH_IOCTL_TDEL:
+               ret = dsp_tdel_minor(arg);
+               break;
+
+       case TWCH_IOCTL_TKILL:
+               ret = dsp_tkill_minor(arg);
+               break;
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+
+       return ret;
+}
+
+struct file_operations dsp_twch_fops = {
+       .owner = THIS_MODULE,
+       .read  = dsp_twch_read,
+       .poll  = dsp_twch_poll,
+       .ioctl = dsp_twch_ioctl,
+};
+
+void dsp_twch_start(void)
+{
+       change_cnt = 1;         /* first read will not wait */
+}
+
+void dsp_twch_stop(void)
+{
+       wake_up_interruptible(&read_wait_q);
+}
diff --git a/arch/arm/plat-omap/dsp/uaccess_dsp.S b/arch/arm/plat-omap/dsp/uaccess_dsp.S
new file mode 100644 (file)
index 0000000..bcf4a54
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2004-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+               .text
+
+/* Prototype: int __copy_to_user_dsp_2b(void *to, const char *from)
+ * Purpose  : copy 2 bytes to user memory from kernel(DSP) memory
+ *            escaping from unexpected byte swap using __copy_to_user()
+ *            in OMAP architecture.
+ * Params   : to   - user memory
+ *          : from - kernel(DSP) memory
+ * Returns  : success = 0, failure = 2
+ */
+
+ENTRY(__copy_to_user_dsp_2b)
+               stmfd   sp!, {r4, lr}
+               ldrb    r3, [r1], #1
+               ldrb    r4, [r1], #1
+USER(          strbt   r4, [r0], #1)                   @ May fault
+USER(          strbt   r3, [r0], #1)                   @ May fault
+               mov     r0, #0
+               ldmfd   sp!, {r4, pc}
+
+               .section .fixup,"ax"
+               .align  0
+9001:          mov     r0, #2
+               ldmfd   sp!, {r4, pc}
+               .previous
+
+/* Prototype: unsigned long __copy_from_user_dsp_2b(void *to, const void *from);
+ * Purpose  : copy 2 bytes from user memory to kernel(DSP) memory
+ *            escaping from unexpected byte swap using __copy_to_user()
+ *            in OMAP architecture.
+ * Params   : to   - kernel (DSP) memory
+ *          : from - user memory
+ * Returns  : success = 0, failure = 2
+ */
+
+ENTRY(__copy_from_user_dsp_2b)
+               stmfd   sp!, {r4, lr}
+USER(          ldrbt   r3, [r1], #1)                   @ May fault
+USER(          ldrbt   r4, [r1], #1)                   @ May fault
+               strb    r4, [r0], #1
+               strb    r3, [r0], #1
+               mov     r0, #0
+               ldmfd   sp!, {r4, pc}
+
+               .section .fixup,"ax"
+               .align  0
+9001:          mov     r3, #0
+               strh    r3, [r0], #2
+               mov     r0, #2
+               ldmfd   sp!, {r4, pc}
+               .previous
diff --git a/arch/arm/plat-omap/dsp/uaccess_dsp.h b/arch/arm/plat-omap/dsp/uaccess_dsp.h
new file mode 100644 (file)
index 0000000..a2ac7b6
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef _OMAP_DSP_UACCESS_DSP_H
+#define _OMAP_DSP_UACCESS_DSP_H
+
+#include <asm/uaccess.h>
+#include "dsp_common.h"
+
+#define HAVE_ASM_COPY_FROM_USER_DSP_2B
+
+#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
+extern unsigned long __copy_from_user_dsp_2b(void *to,
+                                                 const void __user *from);
+extern unsigned long __copy_to_user_dsp_2b(void __user *to,
+                                               const void *from);
+#endif
+
+#ifndef HAVE_ASM_COPY_FROM_USER_DSP_2B
+static __inline__ unsigned long copy_from_user_dsp_2b(void *to,
+                                                     const void *from)
+{
+       unsigned short tmp;
+
+       if (__copy_from_user(&tmp, from, 2))
+               return 2;
+       /* expecting compiler to generate "strh" instruction */
+       *((unsigned short *)to) = tmp;
+       return 0;
+}
+#endif
+
+/*
+ * @n must be multiple of 2
+ */
+static __inline__ unsigned long copy_from_user_dsp(void *to, const void *from,
+                                                  unsigned long n)
+{
+       if (access_ok(VERIFY_READ, from, n)) {
+               if ((is_dsp_internal_mem(to)) &&
+                   (((unsigned long)to & 2) || (n & 2))) {
+                       /*
+                        * DARAM/SARAM with odd word alignment
+                        */
+                       unsigned long n4;
+                       unsigned long last_n;
+
+                       /* dest not aligned -- copy 2 bytes */
+                       if (((unsigned long)to & 2) && (n >= 2)) {
+#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
+                               if (__copy_from_user_dsp_2b(to, from))
+#else
+                               if (copy_from_user_dsp_2b(to, from))
+#endif
+                                       return n;
+                               to += 2;
+                               from += 2;
+                               n -= 2;
+                       }
+                       /* middle 4*n bytes */
+                       last_n = n & 2;
+                       n4 = n - last_n;
+                       if ((n = __copy_from_user(to, from, n4)) != 0)
+                               return n + last_n;
+                       /* last 2 bytes */
+                       if (last_n) {
+                               to += n4;
+                               from += n4;
+#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
+                               if (__copy_from_user_dsp_2b(to, from))
+#else
+                               if (copy_from_user_dsp_2b(to, from))
+#endif
+                                       return 2;
+                               n = 0;
+                       }
+               } else {
+                       /*
+                        * DARAM/SARAM with 4-byte alignment or
+                        * external memory
+                        */
+                       n = __copy_from_user(to, from, n);
+               }
+       }
+       else    /* security hole - plug it */
+               memzero(to, n);
+       return n;
+}
+
+#ifndef HAVE_ASM_COPY_FROM_USER_DSP_2B
+static __inline__ unsigned long copy_to_user_dsp_2b(void *to, const void *from)
+{
+       /* expecting compiler to generate "strh" instruction */
+       unsigned short tmp = *(unsigned short *)from;
+
+       return __copy_to_user(to, &tmp, 2);
+}
+#endif
+
+/*
+ * @n must be multiple of 2
+ */
+static __inline__ unsigned long copy_to_user_dsp(void *to, const void *from,
+                                                unsigned long n)
+{
+       if (access_ok(VERIFY_WRITE, to, n)) {
+               if ((is_dsp_internal_mem(from)) &&
+                   (((unsigned long)to & 2) || (n & 2))) {
+                       /*
+                        * DARAM/SARAM with odd word alignment
+                        */
+                       unsigned long n4;
+                       unsigned long last_n;
+
+                       /* dest not aligned -- copy 2 bytes */
+                       if (((unsigned long)to & 2) && (n >= 2)) {
+#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
+                               if (__copy_to_user_dsp_2b(to, from))
+#else
+                               if (copy_to_user_dsp_2b(to, from))
+#endif
+                                       return n;
+                               to += 2;
+                               from += 2;
+                               n -= 2;
+                       }
+                       /* middle 4*n bytes */
+                       last_n = n & 2;
+                       n4 = n - last_n;
+                       if ((n = __copy_to_user(to, from, n4)) != 0)
+                               return n + last_n;
+                       /* last 2 bytes */
+                       if (last_n) {
+                               to += n4;
+                               from += n4;
+#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
+                               if (__copy_to_user_dsp_2b(to, from))
+#else
+                               if (copy_to_user_dsp_2b(to, from))
+#endif
+                                       return 2;
+                               n = 0;
+                       }
+               } else {
+                       /*
+                        * DARAM/SARAM with 4-byte alignment or
+                        * external memory
+                        */
+                       n = __copy_to_user(to, from, n);
+               }
+       }
+       return n;
+}
+
+#endif /* _OMAP_DSP_UACCESS_DSP_H */
diff --git a/arch/arm/plat-omap/gpio-switch.c b/arch/arm/plat-omap/gpio-switch.c
new file mode 100644 (file)
index 0000000..cd96c00
--- /dev/null
@@ -0,0 +1,549 @@
+/*
+ *  linux/arch/arm/plat-omap/gpio-switch.c
+ *
+ *  Copyright (C) 2004-2006 Nokia Corporation
+ *  Written by Juha Yrjölä <juha.yrjola@nokia.com>
+ *         and Paul Mundt <paul.mundt@nokia.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/sched.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/timer.h>
+#include <linux/err.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/board.h>
+#include <asm/arch/gpio-switch.h>
+
+struct gpio_switch {
+       char            name[14];
+       u16             gpio;
+       unsigned        flags:4;
+       unsigned        type:4;
+       unsigned        state:1;
+       unsigned        both_edges:1;
+
+       u16             debounce_rising;
+       u16             debounce_falling;
+
+       void (* notify)(void *data, int state);
+       void *notify_data;
+
+       struct work_struct      work;
+       struct timer_list       timer;
+       struct platform_device  pdev;
+
+       struct list_head        node;
+};
+
+static LIST_HEAD(gpio_switches);
+static struct platform_device *gpio_sw_platform_dev;
+static struct platform_driver gpio_sw_driver;
+
+static const struct omap_gpio_switch *board_gpio_sw_table;
+static int board_gpio_sw_count;
+
+static const char *cover_str[2] = { "open", "closed" };
+static const char *connection_str[2] = { "disconnected", "connected" };
+static const char *activity_str[2] = { "inactive", "active" };
+
+/*
+ * GPIO switch state default debounce delay in ms
+ */
+#define OMAP_GPIO_SW_DEFAULT_DEBOUNCE          10
+
+static const char **get_sw_str(struct gpio_switch *sw)
+{
+       switch (sw->type) {
+       case OMAP_GPIO_SWITCH_TYPE_COVER:
+               return cover_str;
+       case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
+               return connection_str;
+       case OMAP_GPIO_SWITCH_TYPE_ACTIVITY:
+               return activity_str;
+       default:
+               BUG();
+               return NULL;
+       }
+}
+
+static const char *get_sw_type(struct gpio_switch *sw)
+{
+       switch (sw->type) {
+       case OMAP_GPIO_SWITCH_TYPE_COVER:
+               return "cover";
+       case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
+               return "connection";
+       case OMAP_GPIO_SWITCH_TYPE_ACTIVITY:
+               return "activity";
+       default:
+               BUG();
+               return NULL;
+       }
+}
+
+static void print_sw_state(struct gpio_switch *sw, int state)
+{
+       const char **str;
+
+       str = get_sw_str(sw);
+       if (str != NULL)
+               printk(KERN_INFO "%s (GPIO %d) is now %s\n", sw->name, sw->gpio, str[state]);
+}
+
+static int gpio_sw_get_state(struct gpio_switch *sw)
+{
+       int state;
+
+       state = omap_get_gpio_datain(sw->gpio);
+       if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED)
+               state = !state;
+
+       return state;
+}
+
+static ssize_t gpio_sw_state_store(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf,
+                                  size_t count)
+{
+       struct gpio_switch *sw = dev_get_drvdata(dev);
+       const char **str;
+       char state[16];
+       int enable;
+
+       if (!(sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT))
+               return -EPERM;
+
+       if (sscanf(buf, "%15s", state) != 1)
+               return -EINVAL;
+
+       str = get_sw_str(sw);
+       if (strcmp(state, str[0]) == 0)
+               enable = 0;
+       else if (strcmp(state, str[1]) == 0)
+               enable = 1;
+       else
+               return -EINVAL;
+       if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED)
+               enable = !enable;
+       omap_set_gpio_dataout(sw->gpio, enable);
+
+       return count;
+}
+
+static ssize_t gpio_sw_state_show(struct device *dev,
+                                 struct device_attribute *attr,
+                                 char *buf)
+{
+       struct gpio_switch *sw = dev_get_drvdata(dev);
+       const char **str;
+
+       str = get_sw_str(sw);
+       return sprintf(buf, "%s\n", str[sw->state]);
+}
+
+static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, gpio_sw_state_show,
+                  gpio_sw_state_store);
+
+static ssize_t gpio_sw_type_show(struct device *dev,
+                                struct device_attribute *attr,
+                                char *buf)
+{
+       struct gpio_switch *sw = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%s\n", get_sw_type(sw));
+}
+
+static DEVICE_ATTR(type, S_IRUGO, gpio_sw_type_show, NULL);
+
+static ssize_t gpio_sw_direction_show(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf)
+{
+       struct gpio_switch *sw = dev_get_drvdata(dev);
+       int is_output;
+
+       is_output = sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT;
+       return sprintf(buf, "%s\n", is_output ? "output" : "input");
+}
+
+static DEVICE_ATTR(direction, S_IRUGO, gpio_sw_direction_show, NULL);
+
+
+static irqreturn_t gpio_sw_irq_handler(int irq, void *arg)
+{
+       struct gpio_switch *sw = arg;
+       unsigned long timeout;
+       int state;
+
+       if (!sw->both_edges) {
+               if (omap_get_gpio_datain(sw->gpio))
+                       set_irq_type(OMAP_GPIO_IRQ(sw->gpio), IRQT_FALLING);
+               else
+                       set_irq_type(OMAP_GPIO_IRQ(sw->gpio), IRQT_RISING);
+       }
+
+       state = gpio_sw_get_state(sw);
+       if (sw->state == state)
+               return IRQ_HANDLED;
+
+       if (state)
+               timeout = sw->debounce_rising;
+       else
+               timeout = sw->debounce_falling;
+       if (!timeout)
+               schedule_work(&sw->work);
+       else
+               mod_timer(&sw->timer, jiffies + msecs_to_jiffies(timeout));
+
+       return IRQ_HANDLED;
+}
+
+static void gpio_sw_timer(unsigned long arg)
+{
+       struct gpio_switch *sw = (struct gpio_switch *) arg;
+
+       schedule_work(&sw->work);
+}
+
+static void gpio_sw_handler(struct work_struct *work)
+{
+       struct gpio_switch *sw = container_of(work, struct gpio_switch, work);
+       int state;
+
+       state = gpio_sw_get_state(sw);
+       if (sw->state == state)
+               return;
+
+       sw->state = state;
+       if (sw->notify != NULL)
+               sw->notify(sw->notify_data, state);
+       sysfs_notify(&sw->pdev.dev.kobj, NULL, "state");
+       print_sw_state(sw, state);
+}
+
+static int __init can_do_both_edges(struct gpio_switch *sw)
+{
+       if (!cpu_class_is_omap1())
+               return 1;
+       if (OMAP_GPIO_IS_MPUIO(sw->gpio))
+               return 0;
+       else
+               return 1;
+}
+
+static void gpio_sw_release(struct device *dev)
+{
+}
+
+static int __init new_switch(struct gpio_switch *sw)
+{
+       int r, direction, trigger;
+
+       switch (sw->type) {
+       case OMAP_GPIO_SWITCH_TYPE_COVER:
+       case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
+       case OMAP_GPIO_SWITCH_TYPE_ACTIVITY:
+               break;
+       default:
+               printk(KERN_ERR "invalid GPIO switch type: %d\n", sw->type);
+               return -EINVAL;
+       }
+
+       sw->pdev.name   = sw->name;
+       sw->pdev.id     = -1;
+
+       sw->pdev.dev.parent = &gpio_sw_platform_dev->dev;
+       sw->pdev.dev.driver = &gpio_sw_driver.driver;
+       sw->pdev.dev.release = gpio_sw_release;
+
+       r = platform_device_register(&sw->pdev);
+       if (r) {
+               printk(KERN_ERR "gpio-switch: platform device registration "
+                      "failed for %s", sw->name);
+               return r;
+       }
+       dev_set_drvdata(&sw->pdev.dev, sw);
+
+       r = omap_request_gpio(sw->gpio);
+       if (r < 0) {
+               platform_device_unregister(&sw->pdev);
+               return r;
+       }
+
+       /* input: 1, output: 0 */
+       direction = !(sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT);
+       omap_set_gpio_direction(sw->gpio, direction);
+
+       sw->state = gpio_sw_get_state(sw);
+
+       r = 0;
+       r |= device_create_file(&sw->pdev.dev, &dev_attr_state);
+       r |= device_create_file(&sw->pdev.dev, &dev_attr_type);
+       r |= device_create_file(&sw->pdev.dev, &dev_attr_direction);
+       if (r)
+               printk(KERN_ERR "gpio-switch: attribute file creation "
+                      "failed for %s\n", sw->name);
+
+       if (!direction)
+               return 0;
+
+       if (can_do_both_edges(sw)) {
+               trigger = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
+               sw->both_edges = 1;
+       } else {
+               if (omap_get_gpio_datain(sw->gpio))
+                       trigger = IRQF_TRIGGER_FALLING;
+               else
+                       trigger = IRQF_TRIGGER_RISING;
+       }
+       r = request_irq(OMAP_GPIO_IRQ(sw->gpio), gpio_sw_irq_handler,
+                       IRQF_SHARED | trigger, sw->name, sw);
+       if (r < 0) {
+               printk(KERN_ERR "gpio-switch: request_irq() failed "
+                      "for GPIO %d\n", sw->gpio);
+               platform_device_unregister(&sw->pdev);
+               omap_free_gpio(sw->gpio);
+               return r;
+       }
+
+       INIT_WORK(&sw->work, gpio_sw_handler);
+       init_timer(&sw->timer);
+
+       sw->timer.function = gpio_sw_timer;
+       sw->timer.data = (unsigned long)sw;
+
+       list_add(&sw->node, &gpio_switches);
+
+       return 0;
+}
+
+static int __init add_atag_switches(void)
+{
+       const struct omap_gpio_switch_config *cfg;
+       struct gpio_switch *sw;
+       int i, r;
+
+       for (i = 0; ; i++) {
+               cfg = omap_get_nr_config(OMAP_TAG_GPIO_SWITCH,
+                                        struct omap_gpio_switch_config, i);
+               if (cfg == NULL)
+                       break;
+               sw = kzalloc(sizeof(*sw), GFP_KERNEL);
+               if (sw == NULL) {
+                       printk(KERN_ERR "gpio-switch: kmalloc failed\n");
+                       return -ENOMEM;
+               }
+               strncpy(sw->name, cfg->name, sizeof(cfg->name));
+               sw->gpio = cfg->gpio;
+               sw->flags = cfg->flags;
+               sw->type = cfg->type;
+               sw->debounce_rising = OMAP_GPIO_SW_DEFAULT_DEBOUNCE;
+               sw->debounce_falling = OMAP_GPIO_SW_DEFAULT_DEBOUNCE;
+               if ((r = new_switch(sw)) < 0) {
+                       kfree(sw);
+                       return r;
+               }
+       }
+       return 0;
+}
+
+static struct gpio_switch * __init find_switch(int gpio, const char *name)
+{
+       struct gpio_switch *sw;
+
+       list_for_each_entry(sw, &gpio_switches, node) {
+               if ((gpio < 0 || sw->gpio != gpio) &&
+                   (name == NULL || strcmp(sw->name, name) != 0))
+                       continue;
+
+               if (gpio < 0 || name == NULL)
+                       goto no_check;
+
+               if (strcmp(sw->name, name) != 0)
+                       printk("gpio-switch: name mismatch for %d (%s, %s)\n",
+                              gpio, name, sw->name);
+               else if (sw->gpio != gpio)
+                       printk("gpio-switch: GPIO mismatch for %s (%d, %d)\n",
+                              name, gpio, sw->gpio);
+no_check:
+               return sw;
+       }
+       return NULL;
+}
+
+static int __init add_board_switches(void)
+{
+       int i;
+
+       for (i = 0; i < board_gpio_sw_count; i++) {
+               const struct omap_gpio_switch *cfg;
+               struct gpio_switch *sw;
+               int r;
+
+               cfg = board_gpio_sw_table + i;
+               if (strlen(cfg->name) > sizeof(sw->name) - 1)
+                       return -EINVAL;
+               /* Check whether we only update an existing switch
+                * or add a new switch. */
+               sw = find_switch(cfg->gpio, cfg->name);
+               if (sw != NULL) {
+                       sw->debounce_rising = cfg->debounce_rising;
+                       sw->debounce_falling = cfg->debounce_falling;
+                       sw->notify = cfg->notify;
+                       sw->notify_data = cfg->notify_data;
+                       continue;
+               } else {
+                       if (cfg->gpio < 0 || cfg->name == NULL) {
+                               printk("gpio-switch: required switch not "
+                                      "found (%d, %s)\n", cfg->gpio,
+                                      cfg->name);
+                               continue;
+                       }
+               }
+               sw = kzalloc(sizeof(*sw), GFP_KERNEL);
+               if (sw == NULL) {
+                       printk(KERN_ERR "gpio-switch: kmalloc failed\n");
+                       return -ENOMEM;
+               }
+               strlcpy(sw->name, cfg->name, sizeof(sw->name));
+               sw->gpio = cfg->gpio;
+               sw->flags = cfg->flags;
+               sw->type = cfg->type;
+               sw->debounce_rising = cfg->debounce_rising;
+               sw->debounce_falling = cfg->debounce_falling;
+               sw->notify = cfg->notify;
+               sw->notify_data = cfg->notify_data;
+               if ((r = new_switch(sw)) < 0) {
+                       kfree(sw);
+                       return r;
+               }
+       }
+       return 0;
+}
+
+static void gpio_sw_cleanup(void)
+{
+       struct gpio_switch *sw = NULL, *old = NULL;
+
+       list_for_each_entry(sw, &gpio_switches, node) {
+               if (old != NULL)
+                       kfree(old);
+               flush_scheduled_work();
+               del_timer_sync(&sw->timer);
+
+               free_irq(OMAP_GPIO_IRQ(sw->gpio), sw);
+
+               device_remove_file(&sw->pdev.dev, &dev_attr_state);
+               device_remove_file(&sw->pdev.dev, &dev_attr_type);
+               device_remove_file(&sw->pdev.dev, &dev_attr_direction);
+
+               platform_device_unregister(&sw->pdev);
+               omap_free_gpio(sw->gpio);
+               old = sw;
+       }
+       kfree(old);
+}
+
+static void __init report_initial_state(void)
+{
+       struct gpio_switch *sw;
+
+       list_for_each_entry(sw, &gpio_switches, node) {
+               int state;
+
+               state = omap_get_gpio_datain(sw->gpio);
+               if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED)
+                       state = !state;
+               if (sw->notify != NULL)
+                       sw->notify(sw->notify_data, state);
+               print_sw_state(sw, state);
+       }
+}
+
+static int gpio_sw_remove(struct platform_device *dev)
+{
+       return 0;
+}
+
+static struct platform_driver gpio_sw_driver = {
+       .remove         = gpio_sw_remove,
+       .driver         = {
+               .name   = "gpio-switch",
+       },
+};
+
+void __init omap_register_gpio_switches(const struct omap_gpio_switch *tbl,
+                                       int count)
+{
+       BUG_ON(board_gpio_sw_table != NULL);
+
+       board_gpio_sw_table = tbl;
+       board_gpio_sw_count = count;
+}
+
+static int __init gpio_sw_init(void)
+{
+       int r;
+
+       printk(KERN_INFO "OMAP GPIO switch handler initializing\n");
+
+       r = platform_driver_register(&gpio_sw_driver);
+       if (r)
+               return r;
+
+       gpio_sw_platform_dev = platform_device_register_simple("gpio-switch",
+                                                              -1, NULL, 0);
+       if (IS_ERR(gpio_sw_platform_dev)) {
+               r = PTR_ERR(gpio_sw_platform_dev);
+               goto err1;
+       }
+
+       r = add_atag_switches();
+       if (r < 0)
+               goto err2;
+
+       r = add_board_switches();
+       if (r < 0)
+               goto err2;
+
+       report_initial_state();
+
+       return 0;
+err2:
+       gpio_sw_cleanup();
+       platform_device_unregister(gpio_sw_platform_dev);
+err1:
+       platform_driver_unregister(&gpio_sw_driver);
+       return r;
+}
+
+static void __exit gpio_sw_exit(void)
+{
+       gpio_sw_cleanup();
+       platform_device_unregister(gpio_sw_platform_dev);
+       platform_driver_unregister(&gpio_sw_driver);
+}
+
+#ifndef MODULE
+late_initcall(gpio_sw_init);
+#else
+module_init(gpio_sw_init);
+#endif
+module_exit(gpio_sw_exit);
+
+MODULE_AUTHOR("Juha Yrjölä <juha.yrjola@nokia.com>, Paul Mundt <paul.mundt@nokia.com");
+MODULE_DESCRIPTION("GPIO switch driver");
+MODULE_LICENSE("GPL");
index 7e90cea37a4251a5f08dfb919bacdeaad0f2a4b3..250e8b2d7b3843a00c37db195eab49eca4b476e3 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/sysdev.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/delay.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
index 665b1ae9d48ffdbc0c51ea309c5bac8009110226..ab71d53d0bd3ff5a76d2fce4e5b80cba37871683 100644 (file)
@@ -109,9 +109,10 @@ EXPORT_SYMBOL(omap_mbox_msg_send);
 /*
  * Message receiver(workqueue)
  */
-static void mbox_msg_receiver(void *p)
+static void mbox_msg_receiver(struct work_struct *work)
 {
-       struct omap_mbox *mbox = (struct omap_mbox *)p;
+       struct omap_mbox *mbox =
+               container_of(work, struct omap_mbox, msg_receive);
        struct omap_mbq *mbq = mbox->mbq;
        mbox_msg_t msg;
        int was_full;
@@ -239,14 +240,14 @@ static int omap_mbox_init(struct omap_mbox *mbox)
        }
 
        spin_lock_init(&mbox->lock);
-       INIT_WORK(&mbox->msg_receive, mbox_msg_receiver, mbox);
+       INIT_WORK(&mbox->msg_receive, mbox_msg_receiver);
        init_waitqueue_head(&mbox->tx_waitq);
 
        ret = mbq_init(&mbox->mbq);
        if (unlikely(ret))
                goto fail2;
 
-       ret = request_irq(mbox->irq, mbox_interrupt, SA_INTERRUPT,
+       ret = request_irq(mbox->irq, mbox_interrupt, IRQF_DISABLED,
                          mbox->name, mbox);
        if (unlikely(ret)) {
                printk(KERN_ERR
diff --git a/arch/arm/plat-omap/sti/Makefile b/arch/arm/plat-omap/sti/Makefile
new file mode 100644 (file)
index 0000000..6ad9bb3
--- /dev/null
@@ -0,0 +1,4 @@
+obj-y += sti.o sti-fifo.o
+
+obj-$(CONFIG_OMAP_STI_CONSOLE) += sti-console.o
+obj-$(CONFIG_NET)              += sti-netlink.o
diff --git a/arch/arm/plat-omap/sti/sti-console.c b/arch/arm/plat-omap/sti/sti-console.c
new file mode 100644 (file)
index 0000000..451a139
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * Console support for OMAP STI/XTI
+ *
+ * Copyright (C) 2004, 2005, 2006 Nokia Corporation
+ * Written by: Paul Mundt <paul.mundt@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <asm/arch/sti.h>
+#include <asm/arch/board.h>
+
+#define DRV_NAME "sticon"
+
+static struct tty_driver *tty_driver;
+static DEFINE_SPINLOCK(sti_console_lock);
+static unsigned int sti_console_channel = -1;
+static int sti_line_done = -1;
+
+/*
+ * Write a string to any channel (including terminating NULL)
+ * Returns number of characters written.
+ */
+static int sti_channel_puts(const char *string, unsigned int channel, int len)
+{
+       int count = 0;
+
+       /*
+        * sti_line_done is needed to determine when we have reached the
+        * end of the line. write() has a tendency to hand us small
+        * strings which otherwise end up creating newlines.. we need to
+        * keep the channel open and in append mode until the line has
+        * been terminated.
+        */
+       if (sti_line_done != 0) {
+#ifdef __LITTLE_ENDIAN
+               sti_channel_writeb(0xc3, channel);
+#else
+               sti_channel_writeb(0xc0, channel);
+#endif
+               xchg(&sti_line_done, 0);
+       }
+
+       while (*string && count != len) {
+               char c = *string++;
+
+               count++;
+
+               if (c == '\n') {
+                       xchg(&sti_line_done, 1);
+                       sti_channel_writeb(0, channel);
+                       break;
+               } else
+                       sti_channel_writeb(c, channel);
+       }
+
+       if (sti_line_done)
+               sti_channel_flush(channel);
+
+       return count;
+}
+
+static int sti_tty_open(struct tty_struct *tty, struct file *filp)
+{
+       return 0;
+}
+
+static int sti_tty_write(struct tty_struct *tty,
+                        const unsigned char *buf, int len)
+{
+       unsigned long flags;
+       int bytes;
+
+       spin_lock_irqsave(&sti_console_lock, flags);
+       bytes = sti_channel_puts(buf, sti_console_channel, len);
+       spin_unlock_irqrestore(&sti_console_lock, flags);
+
+       return bytes;
+}
+
+static int sti_tty_write_room(struct tty_struct *tty)
+{
+       return 0x100000;
+}
+
+static int sti_tty_chars_in_buffer(struct tty_struct *tty)
+{
+       return 0;
+}
+
+static struct tty_operations sti_tty_ops = {
+       .open                   = sti_tty_open,
+       .write                  = sti_tty_write,
+       .write_room             = sti_tty_write_room,
+       .chars_in_buffer        = sti_tty_chars_in_buffer,
+};
+
+static void sti_console_write(struct console *c, const char *s, unsigned n)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&sti_console_lock, flags);
+       sti_channel_puts(s, sti_console_channel, n);
+       spin_unlock_irqrestore(&sti_console_lock, flags);
+}
+
+static struct tty_driver *sti_console_device(struct console *c, int *index)
+{
+       *index = c->index;
+       return tty_driver;
+}
+
+static int sti_console_setup(struct console *c, char *opts)
+{
+       return 0;
+}
+
+static struct console sti_console = {
+       .name           = DRV_NAME,
+       .write          = sti_console_write,
+       .device         = sti_console_device,
+       .setup          = sti_console_setup,
+       .flags          = CON_PRINTBUFFER | CON_ENABLED,
+       .index          = -1,
+};
+
+static int __init sti_console_init(void)
+{
+       const struct omap_sti_console_config *info;
+
+       info = omap_get_config(OMAP_TAG_STI_CONSOLE,
+                              struct omap_sti_console_config);
+       if (info && info->enable) {
+               add_preferred_console(DRV_NAME, 0, NULL);
+
+               sti_console_channel = info->channel;
+       }
+
+       if (unlikely(sti_console_channel == -1))
+               return -EINVAL;
+
+       register_console(&sti_console);
+
+       return 0;
+}
+__initcall(sti_console_init);
+
+static int __init sti_tty_init(void)
+{
+       struct tty_driver *tty;
+       int ret;
+
+       tty = alloc_tty_driver(1);
+       if (!tty)
+               return -ENOMEM;
+
+       tty->name               = DRV_NAME;
+       tty->driver_name        = DRV_NAME;
+       tty->major              = 0;    /* dynamic major */
+       tty->minor_start        = 0;
+       tty->type               = TTY_DRIVER_TYPE_SYSTEM;
+       tty->subtype            = SYSTEM_TYPE_SYSCONS;
+       tty->init_termios       = tty_std_termios;
+
+       tty_set_operations(tty, &sti_tty_ops);
+
+       ret = tty_register_driver(tty);
+       if (ret) {
+               put_tty_driver(tty);
+               return ret;
+       }
+
+       tty_driver = tty;
+       return 0;
+}
+late_initcall(sti_tty_init);
+
+module_param(sti_console_channel, uint, 0);
+MODULE_PARM_DESC(sti_console_channel, "STI console channel");
+MODULE_AUTHOR("Paul Mundt");
+MODULE_DESCRIPTION("OMAP STI console support");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/plat-omap/sti/sti-fifo.c b/arch/arm/plat-omap/sti/sti-fifo.c
new file mode 100644 (file)
index 0000000..4069d9b
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * STI RX FIFO Support
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation
+ * Written by:  Paul Mundt <paul.mundt@nokia.com> and
+ *             Roman Tereshonkov <roman.tereshonkov@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <asm/arch/sti.h>
+
+#define STI_READ_BUFFER_SIZE   1024
+#define sti_buf_pos(pos)       ((sti_crb->bufpos + (pos)) % \
+                                STI_READ_BUFFER_SIZE)
+
+static struct sti_cycle_buffer {
+       int bufpos;
+       int datalen;
+       unsigned char *buf;
+} *sti_crb;
+
+/**
+ * sti_read_packet - STI read packet (read an entire STI packet)
+ * @buf: Buffer to store the packet.
+ * @maxsize: Maximum size requested.
+ *
+ * This reads in a single completed STI packet from the RX FIFOs and
+ * places it in @buf for further processing.
+ *
+ * The return value is < 0 on error, and >= 0 for the number of bytes
+ * actually read. As per the STI specification, we require a 0xC1 to
+ * indicate the end of the packet, and we don't return the packet until
+ * we've read the entire thing in.
+ *
+ * Due to the size of the FIFOs, it's unrealistic to constantly drain
+ * this for 1 or 2 bytes at a time, so we assemble it here and return
+ * the whole thing.
+ */
+int sti_read_packet(unsigned char *buf, int maxsize)
+{
+       unsigned int pos;
+
+       if (unlikely(!buf))
+               return -EINVAL;
+       if (!sti_crb->datalen)
+               return 0;
+
+       pos = sti_buf_pos(sti_crb->datalen - 1);
+       /* End of packet */
+       if (sti_crb->buf[pos] == 0xC1) {
+               int i;
+
+               for (i = 0; i < sti_crb->datalen && i < maxsize; i++) {
+                       pos = sti_buf_pos(i);
+                       buf[i] = sti_crb->buf[pos];
+               }
+
+               sti_crb->bufpos = sti_buf_pos(i);
+               sti_crb->datalen -= i;
+
+               return i;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(sti_read_packet);
+
+static void sti_fifo_irq(unsigned long arg)
+{
+       /* If there is data read it */
+       while (!(sti_readl(STI_RX_STATUS) & STI_RXFIFO_EMPTY)) {
+               unsigned int pos = sti_buf_pos(sti_crb->datalen);
+
+               sti_crb->buf[pos] = sti_readl(STI_RX_DR);
+               sti_crb->datalen++;
+       }
+
+       sti_ack_irq(STI_RX_INT);
+}
+
+static int __init sti_fifo_init(void)
+{
+       unsigned int size;
+       int ret;
+
+       size = sizeof(struct sti_cycle_buffer) + STI_READ_BUFFER_SIZE;
+       sti_crb = kmalloc(size, GFP_KERNEL);
+       if (!sti_crb)
+               return -ENOMEM;
+
+       sti_crb->bufpos = sti_crb->datalen = 0;
+       sti_crb->buf = (unsigned char *)(sti_crb + sizeof(*sti_crb));
+
+       ret = sti_request_irq(STI_RX_INT, sti_fifo_irq, 0);
+       if (ret != 0)
+               kfree(sti_crb);
+
+       return ret;
+}
+
+static void __exit sti_fifo_exit(void)
+{
+       sti_free_irq(STI_RX_INT);
+       kfree(sti_crb);
+}
+
+module_init(sti_fifo_init);
+module_exit(sti_fifo_exit);
+
+MODULE_AUTHOR("Paul Mundt, Roman Tereshonkov");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/plat-omap/sti/sti-netlink.c b/arch/arm/plat-omap/sti/sti-netlink.c
new file mode 100644 (file)
index 0000000..5593aee
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * OMAP STI/XTI communications interface via netlink socket.
+ *
+ * Copyright (C) 2004, 2005, 2006 Nokia Corporation
+ * Written by: Paul Mundt <paul.mundt@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/netlink.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <linux/mutex.h>
+#include <net/sock.h>
+#include <asm/arch/sti.h>
+
+static struct sock *sti_sock;
+static DEFINE_MUTEX(sti_netlink_mutex);
+
+enum {
+       STI_READ,
+       STI_WRITE,
+};
+
+static int sti_netlink_read(int pid, int seq, void *payload, int size)
+{
+       struct sk_buff *skb;
+       struct nlmsghdr *nlh;
+       int ret, len = NLMSG_SPACE(size);
+       unsigned char *tail;
+
+       skb = alloc_skb(len, GFP_KERNEL);
+       if (!skb)
+               return -ENOMEM;
+
+       tail = skb->tail;
+       nlh = NLMSG_PUT(skb, pid, seq, STI_READ,
+                       len - (sizeof(struct nlmsghdr)));
+       nlh->nlmsg_flags = 0;
+       memcpy(NLMSG_DATA(nlh), payload, size);
+       nlh->nlmsg_len = skb->tail - tail;
+
+       ret = netlink_unicast(sti_sock, skb, pid, MSG_DONTWAIT);
+       if (ret > 0)
+               ret = 0;
+
+       return ret;
+
+nlmsg_failure:
+       if (skb)
+               kfree_skb(skb);
+
+       return -EINVAL;
+}
+
+/*
+ * We abuse nlmsg_type and nlmsg_flags for our purposes.
+ *
+ * The ID is encoded into the upper 8 bits of the nlmsg_type, while the
+ * channel number is encoded into the upper 8 bits of the nlmsg_flags.
+ */
+static int sti_netlink_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+{
+       void *data;
+       u8 chan, id;
+       int size, ret = 0, len = 0;
+
+       data    = NLMSG_DATA(nlh);
+       chan    = (nlh->nlmsg_flags >> 8) & 0xff;
+       id      = (nlh->nlmsg_type  >> 8) & 0xff;
+       size    = (int)(nlh->nlmsg_len - ((char *)data - (char *)nlh));
+
+       switch (nlh->nlmsg_type & 0xff) {
+       case STI_WRITE:
+               sti_channel_write_trace(size, id, data, chan);
+               break;
+       case STI_READ:
+               data = kmalloc(size, GFP_KERNEL);
+               if (!data)
+                       return -ENOMEM;
+               memset(data, 0, size);
+
+               len = sti_read_packet(data, size);
+               ret = sti_netlink_read(NETLINK_CB(skb).pid, nlh->nlmsg_seq,
+                                      data, len);
+               kfree(data);
+               break;
+       default:
+               return -ENOTTY;
+       }
+
+       return ret;
+}
+
+static int sti_netlink_receive_skb(struct sk_buff *skb)
+{
+       while (skb->len >= NLMSG_SPACE(0)) {
+               struct nlmsghdr *nlh;
+               u32 rlen;
+               int ret;
+
+               nlh = (struct nlmsghdr *)skb->data;
+               if (nlh->nlmsg_len < sizeof(struct nlmsghdr) ||
+                   skb->len < nlh->nlmsg_len)
+                       break;
+
+               rlen = NLMSG_ALIGN(nlh->nlmsg_len);
+               if (rlen > skb->len)
+                       rlen = skb->len;
+
+               ret = sti_netlink_receive_msg(skb, nlh);
+               if (ret)
+                       netlink_ack(skb, nlh, -ret);
+               else if (nlh->nlmsg_flags & NLM_F_ACK)
+                       netlink_ack(skb, nlh, 0);
+
+               skb_pull(skb, rlen);
+       }
+
+       return 0;
+}
+
+static void sti_netlink_receive(struct sock *sk, int len)
+{
+       struct sk_buff *skb;
+
+       if (!mutex_trylock(&sti_netlink_mutex))
+               return;
+
+       while ((skb = skb_dequeue(&sk->sk_receive_queue)))
+               if (sti_netlink_receive_skb(skb) && skb->len)
+                       skb_queue_head(&sk->sk_receive_queue, skb);
+               else
+                       kfree_skb(skb);
+
+       mutex_unlock(&sti_netlink_mutex);
+}
+
+static int __init sti_netlink_init(void)
+{
+       sti_sock = netlink_kernel_create(NETLINK_USERSOCK, 0,
+                                        sti_netlink_receive, THIS_MODULE);
+       if (!sti_sock) {
+               printk(KERN_ERR "STI: Failed to create netlink socket\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+module_init(sti_netlink_init);
+
+MODULE_AUTHOR("Paul Mundt");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("STI netlink-driven communications interface");
diff --git a/arch/arm/plat-omap/sti/sti.c b/arch/arm/plat-omap/sti/sti.c
new file mode 100644 (file)
index 0000000..e828860
--- /dev/null
@@ -0,0 +1,432 @@
+/*
+ * Support functions for OMAP STI/XTI (Serial Tracing Interface)
+ *
+ * Copyright (C) 2004, 2005, 2006 Nokia Corporation
+ * Written by: Paul Mundt <paul.mundt@nokia.com>
+ *
+ * STI initialization code and channel handling
+ * from Juha Yrjölä <juha.yrjola@nokia.com>.
+ *
+ * XTI initialization
+ * from Roman Tereshonkov <roman.tereshonkov@nokia.com>.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <asm/arch/sti.h>
+#include <asm/byteorder.h>
+
+static struct clk *sti_ck;
+unsigned long sti_base, sti_channel_base;
+static unsigned long sti_kern_mask = STIEn;
+static unsigned long sti_irq_mask = STI_IRQSTATUS_MASK;
+static DEFINE_SPINLOCK(sti_lock);
+
+static struct sti_irqdesc {
+       irqreturn_t (*func)(unsigned long);
+       unsigned long data;
+} ____cacheline_aligned sti_irq_desc[STI_NR_IRQS];
+
+void sti_channel_write_trace(int len, int id, void *data, unsigned int channel)
+{
+       const u8 *tpntr = data;
+
+       sti_channel_writeb(id, channel);
+
+       if (cpu_is_omap16xx())
+               /* Check u32 boundary */
+               if (!((u32)data & (STI_PERCHANNEL_SIZE - 1)) &&
+                    (len >= STI_PERCHANNEL_SIZE)) {
+                       const u32 *asrc = data;
+
+                       do {
+                               sti_channel_writel(cpu_to_be32(*asrc++),
+                                                  channel);
+                               len -= STI_PERCHANNEL_SIZE;
+                       } while (len >= STI_PERCHANNEL_SIZE);
+
+                       tpntr = (const u8 *)asrc;
+               }
+
+       while (len--)
+               sti_channel_writeb(*tpntr++, channel);
+
+       sti_channel_flush(channel);
+}
+EXPORT_SYMBOL(sti_channel_write_trace);
+
+void sti_enable_irq(unsigned int id)
+{
+       spin_lock_irq(&sti_lock);
+       sti_writel(1 << id, STI_IRQSETEN);
+       spin_unlock_irq(&sti_lock);
+}
+EXPORT_SYMBOL(sti_enable_irq);
+
+void sti_disable_irq(unsigned int id)
+{
+       spin_lock_irq(&sti_lock);
+
+       if (cpu_is_omap16xx())
+               sti_writel(1 << id, STI_IRQCLREN);
+       else if (cpu_is_omap24xx())
+               sti_writel(sti_readl(STI_IRQSETEN) & ~(1 << id), STI_IRQSETEN);
+       else
+               BUG();
+
+       spin_unlock_irq(&sti_lock);
+}
+EXPORT_SYMBOL(sti_disable_irq);
+
+void sti_ack_irq(unsigned int id)
+{
+       /* Even though the clear state is 0, we have to write 1 to clear */
+       sti_writel(1 << id, STI_IRQSTATUS);
+}
+EXPORT_SYMBOL(sti_ack_irq);
+
+int sti_request_irq(unsigned int irq, void *handler, unsigned long arg)
+{
+       struct sti_irqdesc *desc;
+
+       if (unlikely(!handler || irq > STI_NR_IRQS))
+               return -EINVAL;
+
+       desc = sti_irq_desc + irq;
+       if (unlikely(desc->func)) {
+               printk(KERN_WARNING "STI: Attempting to request in-use IRQ "
+                                   "%d, consider fixing your code..\n", irq);
+               return -EBUSY;
+       }
+
+       desc->func = handler;
+       desc->data = arg;
+
+       sti_enable_irq(irq);
+       return 0;
+}
+EXPORT_SYMBOL(sti_request_irq);
+
+void sti_free_irq(unsigned int irq)
+{
+       struct sti_irqdesc *desc = sti_irq_desc + irq;
+
+       if (unlikely(irq > STI_NR_IRQS))
+               return;
+
+       sti_disable_irq(irq);
+
+       desc->func = NULL;
+       desc->data = 0;
+}
+EXPORT_SYMBOL(sti_free_irq);
+
+/*
+ * This is a bit heavy, so normally we would defer this to a tasklet.
+ * Unfortunately tasklets are too slow for the RX FIFO interrupt (and
+ * possibly some others), so we just do the irqdesc walking here.
+ */
+static irqreturn_t sti_interrupt(int irq, void *dev_id)
+{
+       int ret = IRQ_NONE;
+       u16 status;
+       int i;
+
+       status = sti_readl(STI_IRQSTATUS) & sti_irq_mask;
+
+       for (i = 0; status; i++) {
+               struct sti_irqdesc *desc = sti_irq_desc + i;
+               u16 id = 1 << i;
+
+               if (!(status & id))
+                       continue;
+
+               if (likely(desc && desc->func))
+                       ret |= desc->func(desc->data);
+               if (unlikely(ret == IRQ_NONE)) {
+                       printk("STI: spurious interrupt (id %d)\n", id);
+                       sti_disable_irq(i);
+                       sti_ack_irq(i);
+                       ret = IRQ_HANDLED;
+               }
+
+               status &= ~id;
+       }
+
+       return IRQ_RETVAL(ret);
+}
+
+static void omap_sti_reset(void)
+{
+       int i;
+
+       /* Reset STI module */
+       sti_writel(0x02, STI_SYSCONFIG);
+
+       /* Wait a while for the STI module to complete its reset */
+       for (i = 0; i < 10000; i++)
+               if (sti_readl(STI_SYSSTATUS) & 1)
+                       break;
+}
+
+static int __init sti_init(void)
+{
+       char buf[64];
+       int i;
+
+       if (cpu_is_omap16xx()) {
+               /* Release ARM Rhea buses peripherals enable */
+               sti_writel(sti_readl(ARM_RSTCT2) | 0x0001, ARM_RSTCT2);
+
+               /* Enable TC1_CK (functional clock) */
+               sti_ck = clk_get(NULL, "tc1_ck");
+       } else if (cpu_is_omap24xx())
+               /* Enable emulation tools clock */
+               sti_ck = clk_get(NULL, "emul_ck");
+
+       if (IS_ERR(sti_ck))
+               return PTR_ERR(sti_ck);
+
+       clk_enable(sti_ck);
+
+       /* Reset STI module */
+       omap_sti_reset();
+
+       /* Enable STI */
+       sti_trace_enable(MPUCmdEn);
+
+       /* Change to custom serial protocol */
+       sti_writel(0x01, STI_SERIAL_CFG);
+
+       /* Set STI clock control register to normal mode */
+       sti_writel(0x00, STI_CLK_CTRL);
+
+       i = sti_readl(STI_REVISION);
+       snprintf(buf, sizeof(buf), "OMAP STI support loaded (HW v%u.%u)\n",
+               (i >> 4) & 0x0f, i & 0x0f);
+       printk(KERN_INFO "%s", buf);
+
+       sti_channel_write_trace(strlen(buf), 0xc3, buf, 239);
+
+       return 0;
+}
+
+static void sti_exit(void)
+{
+       u32 tmp;
+
+       /*
+        * This should have already been done by reset, but we switch off
+        * STI entirely just for added sanity..
+        */
+       tmp = sti_readl(STI_ER);
+       tmp &= ~STIEn;
+       sti_writel(tmp, STI_ER);
+
+       clk_disable(sti_ck);
+       clk_put(sti_ck);
+}
+
+static void __sti_trace_enable(int event)
+{
+       u32 tmp;
+
+       tmp = sti_readl(STI_ER);
+       tmp |= sti_kern_mask | event;
+       sti_writel(tmp, STI_ER);
+}
+
+int sti_trace_enable(int event)
+{
+       spin_lock_irq(&sti_lock);
+       sti_kern_mask |= event;
+       __sti_trace_enable(event);
+       spin_unlock_irq(&sti_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL(sti_trace_enable);
+
+static void __sti_trace_disable(int event)
+{
+       u32 tmp;
+
+       tmp = sti_readl(STI_DR);
+
+       if (cpu_is_omap16xx()) {
+               tmp |= event;
+               tmp &= ~sti_kern_mask;
+       } else if (cpu_is_omap24xx()) {
+               tmp &= ~event;
+               tmp |= sti_kern_mask;
+       } else
+               BUG();
+
+       sti_writel(tmp, STI_DR);
+}
+
+void sti_trace_disable(int event)
+{
+       spin_lock_irq(&sti_lock);
+       sti_kern_mask &= ~event;
+       __sti_trace_disable(event);
+       spin_unlock_irq(&sti_lock);
+}
+EXPORT_SYMBOL(sti_trace_disable);
+
+static ssize_t
+sti_trace_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "0x%08lx\n", sti_readl(STI_ER));
+}
+
+static ssize_t
+sti_trace_store(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       int evt = simple_strtoul(buf, NULL, 0);
+       int mask = ~evt;
+
+       spin_lock_irq(&sti_lock);
+       __sti_trace_disable(mask);
+       __sti_trace_enable(evt);
+       spin_unlock_irq(&sti_lock);
+
+       return count;
+}
+static DEVICE_ATTR(trace, S_IRUGO | S_IWUSR, sti_trace_show, sti_trace_store);
+
+static ssize_t
+sti_imask_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "0x%04lx\n", sti_irq_mask);
+}
+
+static ssize_t
+sti_imask_store(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       spin_lock_irq(&sti_lock);
+       sti_irq_mask = simple_strtoul(buf, NULL, 0);
+       spin_unlock_irq(&sti_lock);
+
+       return count;
+}
+static DEVICE_ATTR(imask, S_IRUGO | S_IWUSR, sti_imask_show, sti_imask_store);
+
+static int __devinit sti_probe(struct platform_device *pdev)
+{
+       struct resource *res, *cres;
+       int ret;
+
+       if (pdev->num_resources != 3) {
+               dev_err(&pdev->dev, "invalid number of resources: %d\n",
+                       pdev->num_resources);
+               return -ENODEV;
+       }
+
+       /* STI base */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (unlikely(!res)) {
+               dev_err(&pdev->dev, "invalid mem resource\n");
+               return -ENODEV;
+       }
+
+       /* Channel base */
+       cres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (unlikely(!cres)) {
+               dev_err(&pdev->dev, "invalid channel mem resource\n");
+               return -ENODEV;
+       }
+
+       ret = device_create_file(&pdev->dev, &dev_attr_trace);
+       if (unlikely(ret != 0))
+               return ret;
+
+       ret = device_create_file(&pdev->dev, &dev_attr_imask);
+       if (unlikely(ret != 0))
+               goto err;
+
+       sti_base = res->start;
+
+       /*
+        * OMAP 16xx keeps channels in a relatively sane location,
+        * whereas 24xx maps them much further out, and so they must be
+        * remapped.
+        */
+       if (cpu_is_omap16xx())
+               sti_channel_base = cres->start;
+       else if (cpu_is_omap24xx()) {
+               unsigned int size = cres->end - cres->start;
+
+               sti_channel_base = (unsigned long)ioremap(cres->start, size);
+               if (unlikely(!sti_channel_base)) {
+                       ret = -ENODEV;
+                       goto err_badremap;
+               }
+       }
+
+       ret = request_irq(platform_get_irq(pdev, 0), sti_interrupt,
+                         IRQF_DISABLED, "sti", NULL);
+       if (unlikely(ret != 0))
+               goto err_badirq;
+
+       return sti_init();
+
+err_badirq:
+       iounmap((void *)sti_channel_base);
+err_badremap:
+       device_remove_file(&pdev->dev, &dev_attr_imask);
+err:
+       device_remove_file(&pdev->dev, &dev_attr_trace);
+
+       return ret;
+}
+
+static int __devexit sti_remove(struct platform_device *pdev)
+{
+       unsigned int irq = platform_get_irq(pdev, 0);
+
+       if (cpu_is_omap24xx())
+               iounmap((void *)sti_channel_base);
+
+       device_remove_file(&pdev->dev, &dev_attr_trace);
+       device_remove_file(&pdev->dev, &dev_attr_imask);
+       free_irq(irq, NULL);
+       sti_exit();
+
+       return 0;
+}
+
+static struct platform_driver sti_driver = {
+       .probe          = sti_probe,
+       .remove         = __devexit_p(sti_remove),
+       .driver         = {
+               .name   = "sti",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init sti_module_init(void)
+{
+       return platform_driver_register(&sti_driver);
+}
+
+static void __exit sti_module_exit(void)
+{
+       platform_driver_unregister(&sti_driver);
+}
+subsys_initcall(sti_module_init);
+module_exit(sti_module_exit);
+
+MODULE_AUTHOR("Paul Mundt, Juha Yrjölä, Roman Tereshonkov");
+MODULE_LICENSE("GPL");
index a98de903e68d31d00e91686c01fe10cbe6d4d010..38b7b91e075c6cfd7ec2b38c64ad6dbb32f6f7fa 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/spinlock.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/clocksource.h>
 
 #include <asm/system.h>
 #include <asm/hardware.h>
@@ -170,15 +171,6 @@ omap_32k_ticks_to_nsecs(unsigned long ticks_32k)
 
 static unsigned long omap_32k_last_tick = 0;
 
-/*
- * Returns elapsed usecs since last 32k timer interrupt
- */
-static unsigned long omap_32k_timer_gettimeoffset(void)
-{
-       unsigned long now = omap_32k_sync_timer_read();
-       return omap_32k_ticks_to_usecs(now - omap_32k_last_tick);
-}
-
 /*
  * Returns current time from boot in nsecs. It's OK for this to wrap
  * around for now, as it's just a relative time stamp.
@@ -229,22 +221,6 @@ static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id)
 }
 
 #ifdef CONFIG_NO_IDLE_HZ
-static irqreturn_t omap_32k_timer_handler(int irq, void *dev_id)
-{
-       unsigned long now;
-
-       now = omap_32k_sync_timer_read();
-
-       /* Don't bother reprogramming timer if last tick was before next
-        * jiffie. We will get another interrupt when previously programmed
-        * timer expires. This cuts down interrupt load quite a bit.
-        */
-       if (now - omap_32k_last_tick < OMAP_32K_TICKS_PER_HZ)
-               return IRQ_HANDLED;
-
-       return _omap_32k_timer_interrupt(irq, dev_id);
-}
-
 /*
  * Programs the next timer interrupt needed. Called when dynamic tick is
  * enabled, and to reprogram the ticks to skip from pm_idle. Note that
@@ -280,6 +256,22 @@ static int omap_32k_timer_disable_dyn_tick(void)
        return 0;
 }
 
+static irqreturn_t omap_32k_timer_handler(int irq, void *dev_id)
+{
+       unsigned long now;
+
+       now = omap_32k_sync_timer_read();
+
+       /* Don't bother reprogramming timer if last tick was before next
+        * jiffie. We will get another interrupt when previously programmed
+        * timer expires. This cuts down interrupt load quite a bit.
+        */
+       if (now - omap_32k_last_tick < OMAP_32K_TICKS_PER_HZ)
+               return IRQ_HANDLED;
+
+       return _omap_32k_timer_interrupt(irq, dev_id);
+}
+
 static struct dyn_tick_timer omap_dyn_tick_timer = {
        .enable         = omap_32k_timer_enable_dyn_tick,
        .disable        = omap_32k_timer_disable_dyn_tick,
@@ -302,7 +294,6 @@ static __init void omap_init_32k_timer(void)
 
        if (cpu_class_is_omap1())
                setup_irq(INT_OS_TIMER, &omap_32k_timer_irq);
-       omap_timer.offset  = omap_32k_timer_gettimeoffset;
        omap_32k_last_tick = omap_32k_sync_timer_read();
 
 #ifdef CONFIG_ARCH_OMAP2
@@ -337,5 +328,4 @@ static void __init omap_timer_init(void)
 
 struct sys_timer omap_timer = {
        .init           = omap_timer_init,
-       .offset         = NULL,         /* Initialized later */
 };
index e7da9fa724ec5f50aa70040df67c10c2d7cbf2fe..bc33d90b3764a30f2c7e97938a76eff4ef4aece5 100644 (file)
@@ -82,4 +82,6 @@ source "drivers/dma/Kconfig"
 
 source "drivers/kvm/Kconfig"
 
+source "drivers/ssi/Kconfig"
+
 endmenu
index ad98cffa7b36a03828337d3ef270bd6f0bbc21c3..1dc8aba48ea99e47bcc17047d81a6eccda23ef81 100644 (file)
@@ -25,9 +25,14 @@ obj-$(CONFIG_CONNECTOR)              += connector/
 obj-$(CONFIG_FB_I810)           += video/i810/
 obj-$(CONFIG_FB_INTEL)          += video/intelfb/
 
+# we also need input/serio early so serio bus is initialized by the time
+# serial drivers start registering their serio ports
+obj-$(CONFIG_SERIO)            += input/serio/
 obj-y                          += serial/
 obj-$(CONFIG_PARPORT)          += parport/
-obj-y                          += base/ block/ misc/ mfd/ net/ media/ cbus/
+obj-y                          += base/ block/ misc/ mfd/ net/ media/
+obj-$(CONFIG_I2C)              += i2c/
+obj-y                          += media/ ssi/ cbus/
 obj-$(CONFIG_NUBUS)            += nubus/
 obj-$(CONFIG_ATM)              += atm/
 obj-$(CONFIG_PPC_PMAC)         += macintosh/
@@ -50,14 +55,13 @@ obj-$(CONFIG_ATA_OVER_ETH)  += block/aoe/
 obj-$(CONFIG_PARIDE)           += block/paride/
 obj-$(CONFIG_TC)               += tc/
 obj-$(CONFIG_USB)              += usb/
+obj-$(CONFIG_USB_MUSB_HDRC)    += usb/musb/
 obj-$(CONFIG_PCI)              += usb/
 obj-$(CONFIG_USB_GADGET)       += usb/gadget/
-obj-$(CONFIG_SERIO)            += input/serio/
 obj-$(CONFIG_GAMEPORT)         += input/gameport/
 obj-$(CONFIG_INPUT)            += input/
 obj-$(CONFIG_I2O)              += message/
 obj-$(CONFIG_RTC_LIB)          += rtc/
-obj-$(CONFIG_I2C)              += i2c/
 obj-$(CONFIG_W1)               += w1/
 obj-$(CONFIG_HWMON)            += hwmon/
 obj-$(CONFIG_PHONE)            += telephony/
index b9fbe6e7f9ae6e6fd9da5e78990efd5e87229bc4..9abcd6206ac321c9306854f6ced36008ffceb911 100644 (file)
@@ -147,6 +147,17 @@ config BT_HCIBTUART
          Say Y here to compile support for HCI UART devices into the
          kernel or say M to compile it as module (btuart_cs).
 
+config BT_HCIBRF6150
+       tristate "HCI TI BRF6150 driver with H4 extensions"
+       depends on BT && ARCH_OMAP
+       help
+         Bluetooth HCI driver for TI BRF6150 with H4 extensions.
+         This driver provides support for BRF6150 Bluetooth chip 
+         with vendor-specific H4 extensions.
+
+         Say Y here to compile support for TI BRF6150 devices into the
+         kernel or say M to compile it as module (brf6150).
+
 config BT_HCIVHCI
        tristate "HCI VHCI (Virtual HCI device) driver"
        help
index 08c10e178e02400fd3aae0027943a94b6c91daea..18aa038db1367d655d98b810c3bc8ba22f8862cb 100644 (file)
@@ -12,6 +12,7 @@ obj-$(CONFIG_BT_HCIDTL1)      += dtl1_cs.o
 obj-$(CONFIG_BT_HCIBT3C)       += bt3c_cs.o
 obj-$(CONFIG_BT_HCIBLUECARD)   += bluecard_cs.o
 obj-$(CONFIG_BT_HCIBTUART)     += btuart_cs.o
+obj-$(CONFIG_BT_HCIBRF6150)    += brf6150.o
 
 hci_uart-y                             := hci_ldisc.o
 hci_uart-$(CONFIG_BT_HCIUART_H4)       += hci_h4.o
diff --git a/drivers/bluetooth/brf6150.c b/drivers/bluetooth/brf6150.c
new file mode 100644 (file)
index 0000000..4bb38d9
--- /dev/null
@@ -0,0 +1,1041 @@
+/*
+ *  linux/drivers/bluetooth/brf6150/brf6150.c
+ *
+ *  Copyright (C) 2005 Nokia Corporation
+ *  Written by Ville Tervo <ville.tervo@nokia.com>
+ *
+ *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/serial_reg.h>
+#include <linux/skbuff.h>
+#include <linux/firmware.h>
+#include <linux/irq.h>
+#include <linux/timer.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/board.h>
+#include <asm/arch/irqs.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+
+#include "brf6150.h"
+
+#if 0
+#define NBT_DBG(fmt, arg...)  printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG(...)
+#endif
+
+#if 0
+#define NBT_DBG_FW(fmt, arg...)  printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG_FW(...)
+#endif
+
+#if 0
+#define NBT_DBG_POWER(fmt, arg...)  printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG_POWER(...)
+#endif
+
+#if 0
+#define NBT_DBG_TRANSFER(fmt, arg...)  printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG_TRANSFER(...)
+#endif
+
+#if 0
+#define NBT_DBG_TRANSFER_NF(fmt, arg...)  printk(fmt "" , ## arg)
+#else
+#define NBT_DBG_TRANSFER_NF(...)
+#endif
+
+#define PM_TIMEOUT (2000)
+
+static void brf6150_device_release(struct device *dev);
+static struct brf6150_info *exit_info;
+
+static struct platform_device brf6150_device = {
+       .name           = BT_DEVICE,
+       .id             = -1,
+       .num_resources  = 0,
+       .dev = {
+               .release = brf6150_device_release,
+       }
+};
+
+static struct device_driver brf6150_driver = {
+       .name           = BT_DRIVER,
+       .bus            = &platform_bus_type,
+};
+
+static inline void brf6150_outb(struct brf6150_info *info, unsigned int offset, u8 val)
+{
+       outb(val, info->uart_base + (offset << 2));
+}
+
+static inline u8 brf6150_inb(struct brf6150_info *info, unsigned int offset)
+{
+       return inb(info->uart_base + (offset << 2));
+}
+
+static void brf6150_set_rts(struct brf6150_info *info, int active)
+{
+       u8 b;
+
+       b = brf6150_inb(info, UART_MCR);
+       if (active)
+               b |= UART_MCR_RTS;
+       else
+               b &= ~UART_MCR_RTS;
+       brf6150_outb(info, UART_MCR, b);
+}
+
+static void brf6150_wait_for_cts(struct brf6150_info *info, int active,
+                                int timeout_ms)
+{
+       int okay;
+       unsigned long timeout;
+
+       okay = 0;
+       timeout = jiffies + msecs_to_jiffies(timeout_ms);
+       for (;;) {
+               int state;
+
+               state = brf6150_inb(info, UART_MSR) & UART_MSR_CTS;
+               if (active) {
+                       if (state)
+                               break;
+               } else {
+                       if (!state)
+                               break;
+               }
+               if (jiffies > timeout)
+                       break;
+       }
+}
+
+static inline void brf6150_set_auto_ctsrts(struct brf6150_info *info, int on)
+{
+       u8 lcr, b;
+
+       lcr = brf6150_inb(info, UART_LCR);
+       brf6150_outb(info, UART_LCR, 0xbf);
+       b = brf6150_inb(info, UART_EFR);
+       if (on)
+               b |= UART_EFR_CTS | UART_EFR_RTS;
+       else
+               b &= ~(UART_EFR_CTS | UART_EFR_RTS);
+       brf6150_outb(info, UART_EFR, b);
+       brf6150_outb(info, UART_LCR, lcr);
+}
+
+static inline void brf6150_enable_pm_rx(struct brf6150_info *info)
+{
+       if (info->pm_enabled) {
+               info->rx_pm_enabled = 1;
+       }
+}
+
+static inline void brf6150_disable_pm_rx(struct brf6150_info *info)
+{
+       if (info->pm_enabled) {
+               info->rx_pm_enabled = 0;
+       }
+}
+
+static void brf6150_enable_pm_tx(struct brf6150_info *info)
+{
+       if (info->pm_enabled) {
+               mod_timer(&info->pm_timer, jiffies + msecs_to_jiffies(PM_TIMEOUT));
+               info->tx_pm_enabled = 1;
+       }
+}
+
+static void brf6150_disable_pm_tx(struct brf6150_info *info)
+{
+       if (info->pm_enabled) {
+               info->tx_pm_enabled = 0;
+               omap_set_gpio_dataout(info->btinfo->bt_wakeup_gpio, 1);
+       }
+       if (omap_get_gpio_datain(info->btinfo->host_wakeup_gpio))
+               tasklet_schedule(&info->tx_task);
+}
+
+static void brf6150_pm_timer(unsigned long data)
+{
+       struct brf6150_info *info;
+
+       info = (struct brf6150_info *)data;
+       if (info->tx_pm_enabled && info->rx_pm_enabled && !test_bit(HCI_INQUIRY, &info->hdev->flags))
+               omap_set_gpio_dataout(info->btinfo->bt_wakeup_gpio, 0);
+       else
+               mod_timer(&info->pm_timer, jiffies + msecs_to_jiffies(PM_TIMEOUT));
+}
+
+static int brf6150_change_speed(struct brf6150_info *info, unsigned long speed)
+{
+       unsigned int divisor;
+       u8 lcr, mdr1;
+
+       NBT_DBG("Setting speed %lu\n", speed);
+
+       if (speed >= 460800) {
+               divisor = UART_CLOCK / 13 / speed;
+               mdr1 = 3;
+       } else {
+               divisor = UART_CLOCK / 16 / speed;
+               mdr1 = 0;
+       }
+
+       brf6150_outb(info, UART_OMAP_MDR1, 7); /* Make sure UART mode is disabled */
+       lcr = brf6150_inb(info, UART_LCR);
+       brf6150_outb(info, UART_LCR, UART_LCR_DLAB);     /* Set DLAB */
+       brf6150_outb(info, UART_DLL, divisor & 0xff);    /* Set speed */
+       brf6150_outb(info, UART_DLM, divisor >> 8);
+       brf6150_outb(info, UART_LCR, lcr);
+       brf6150_outb(info, UART_OMAP_MDR1, mdr1); /* Make sure UART mode is enabled */
+
+       return 0;
+}
+
+/* Firmware handling */
+static int brf6150_open_firmware(struct brf6150_info *info)
+{
+       int err;
+
+       info->fw_pos = 0;
+       err = request_firmware(&info->fw_entry, "brf6150fw.bin", &brf6150_device.dev);
+
+       return err;
+}
+
+static struct sk_buff *brf6150_read_fw_cmd(struct brf6150_info *info, int how)
+{
+       struct sk_buff *skb;
+       unsigned int cmd_len;
+
+       if (info->fw_pos >= info->fw_entry->size) {
+               return NULL;
+       }
+
+       cmd_len = info->fw_entry->data[info->fw_pos++];
+       if (!cmd_len)
+               return NULL;
+
+       if (info->fw_pos + cmd_len > info->fw_entry->size) {
+               printk(KERN_WARNING "Corrupted firmware image\n");
+               return NULL;
+       }
+
+       skb = bt_skb_alloc(cmd_len, how);
+       if (!skb) {
+               printk(KERN_WARNING "Cannot reserve memory for buffer\n");
+               return NULL;
+       }
+       memcpy(skb_put(skb, cmd_len), &info->fw_entry->data[info->fw_pos], cmd_len);
+
+       info->fw_pos += cmd_len;
+
+       return skb;
+}
+
+static int brf6150_close_firmware(struct brf6150_info *info)
+{
+       release_firmware(info->fw_entry);
+       return 0;
+}
+
+static int brf6150_send_alive_packet(struct brf6150_info *info)
+{
+       struct sk_buff *skb;
+
+       NBT_DBG("Sending alive packet\n");
+       skb = brf6150_read_fw_cmd(info, GFP_ATOMIC);
+       if (!skb) {
+               printk(KERN_WARNING "Cannot read alive command");
+               return -1;
+       }
+
+       clk_enable(info->uart_ck);
+       skb_queue_tail(&info->txq, skb);
+       tasklet_schedule(&info->tx_task);
+
+       NBT_DBG("Alive packet sent\n");
+       return 0;
+}
+
+static void brf6150_alive_packet(struct brf6150_info *info, struct sk_buff *skb)
+{
+       NBT_DBG("Received alive packet\n");
+       if (skb->data[1] == 0xCC) {
+               complete(&info->init_completion);
+       }
+
+       kfree_skb(skb);
+}
+
+static int brf6150_send_negotiation(struct brf6150_info *info)
+{
+       struct sk_buff *skb;
+       NBT_DBG("Sending negotiation..\n");
+
+       brf6150_change_speed(info, INIT_SPEED);
+
+       skb = brf6150_read_fw_cmd(info, GFP_KERNEL);
+
+       if (!skb) {
+               printk(KERN_WARNING "Cannot read negoatiation message");
+               return -1;
+       }
+
+       clk_enable(info->uart_ck);
+       skb_queue_tail(&info->txq, skb);
+       tasklet_schedule(&info->tx_task);
+
+
+       NBT_DBG("Negotiation sent\n");
+       return 0;
+}
+
+static void brf6150_negotiation_packet(struct brf6150_info *info,
+                                      struct sk_buff *skb)
+{
+       if (skb->data[1] == 0x20) {
+               /* Change to operational settings */
+               brf6150_set_rts(info, 0);
+               brf6150_wait_for_cts(info, 0, 100);
+               brf6150_change_speed(info, MAX_BAUD_RATE);
+               brf6150_set_rts(info, 1);
+               brf6150_wait_for_cts(info, 1, 100);
+               brf6150_set_auto_ctsrts(info, 1);
+               brf6150_send_alive_packet(info);
+       } else {
+               printk(KERN_WARNING "Could not negotiate brf6150 settings\n");
+       }
+       kfree_skb(skb);
+}
+
+static int brf6150_get_hdr_len(u8 pkt_type)
+{
+       long retval;
+
+       switch (pkt_type) {
+       case H4_EVT_PKT:
+               retval = HCI_EVENT_HDR_SIZE;
+               break;
+       case H4_ACL_PKT:
+               retval = HCI_ACL_HDR_SIZE;
+               break;
+       case H4_SCO_PKT:
+               retval = HCI_SCO_HDR_SIZE;
+               break;
+       case H4_NEG_PKT:
+               retval = 9;
+               break;
+       case H4_ALIVE_PKT:
+               retval = 3;
+               break;
+       default:
+               printk(KERN_ERR "brf6150: Unknown H4 packet");
+               retval = -1;
+               break;
+       }
+
+       return retval;
+}
+
+static unsigned int brf6150_get_data_len(struct brf6150_info *info,
+                                        struct sk_buff *skb)
+{
+       long retval = -1;
+       struct hci_event_hdr *evt_hdr;
+       struct hci_acl_hdr *acl_hdr;
+       struct hci_sco_hdr *sco_hdr;
+
+       switch (bt_cb(skb)->pkt_type) {
+       case H4_EVT_PKT:
+               evt_hdr = (struct hci_event_hdr *)skb->data;
+               retval = evt_hdr->plen;
+               break;
+       case H4_ACL_PKT:
+               acl_hdr = (struct hci_acl_hdr *)skb->data;
+               retval = le16_to_cpu(acl_hdr->dlen);
+               break;
+       case H4_SCO_PKT:
+               sco_hdr = (struct hci_sco_hdr *)skb->data;
+               retval = sco_hdr->dlen;
+               break;
+       case H4_NEG_PKT:
+               retval = 0;
+               break;
+       case H4_ALIVE_PKT:
+               retval = 0;
+               break;
+       }
+
+       return retval;
+}
+
+static void brf6150_parse_fw_event(struct brf6150_info *info)
+{
+       struct hci_fw_event *ev;
+
+       if (bt_cb(info->rx_skb)->pkt_type != H4_EVT_PKT) {
+               printk(KERN_WARNING "Got non event fw packet.\n");
+               info->fw_error = 1;
+               return;
+       }
+
+       ev = (struct hci_fw_event *)info->rx_skb->data;
+       if (ev->hev.evt != HCI_EV_CMD_COMPLETE) {
+               printk(KERN_WARNING "Got non cmd complete fw event\n");
+               info->fw_error = 1;
+               return;
+       }
+
+       if (ev->status != 0) {
+               printk(KERN_WARNING "Got error status from fw command\n");
+               info->fw_error = 1;
+               return;
+       }
+
+       complete(&info->fw_completion);
+}
+
+static inline void brf6150_recv_frame(struct brf6150_info *info,
+                                     struct sk_buff *skb)
+{
+       if (unlikely(!test_bit(HCI_RUNNING, &info->hdev->flags))) {
+               NBT_DBG("fw_event\n");
+               brf6150_parse_fw_event(info);
+               kfree_skb(skb);
+       } else {
+               hci_recv_frame(skb);
+               if (!(brf6150_inb(info, UART_LSR) & UART_LSR_DR))
+                       brf6150_enable_pm_rx(info);
+               NBT_DBG("Frame sent to upper layer\n");
+       }
+
+}
+
+static inline void brf6150_rx(struct brf6150_info *info)
+{
+       u8 byte;
+
+       NBT_DBG_TRANSFER("rx_tasklet woke up\ndata ");
+
+       while (brf6150_inb(info, UART_LSR) & UART_LSR_DR) {
+               if (info->rx_skb == NULL) {
+                       info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+                       if (!info->rx_skb) {
+                               printk(KERN_WARNING "brf6150: Can't allocate memory for new packet\n");
+                               return;
+                       }
+                       info->rx_state = WAIT_FOR_PKT_TYPE;
+                       info->rx_skb->dev = (void *)info->hdev;
+                       brf6150_disable_pm_rx(info);
+                       clk_enable(info->uart_ck);
+               }
+
+               byte = brf6150_inb(info, UART_RX);
+               if (info->garbage_bytes) {
+                       info->garbage_bytes--;
+                       info->hdev->stat.err_rx++;
+                       continue;
+               }
+               info->hdev->stat.byte_rx++;
+               NBT_DBG_TRANSFER_NF("0x%.2x  ", byte);
+               switch (info->rx_state) {
+               case WAIT_FOR_PKT_TYPE:
+                       bt_cb(info->rx_skb)->pkt_type = byte;
+                       info->rx_count = brf6150_get_hdr_len(byte);
+                       if (info->rx_count >= 0) {
+                               info->rx_state = WAIT_FOR_HEADER;
+                       } else {
+                               info->hdev->stat.err_rx++;
+                               kfree_skb(info->rx_skb);
+                               info->rx_skb = NULL;
+                               clk_disable(info->uart_ck);
+                       }
+                       break;
+               case WAIT_FOR_HEADER:
+                       info->rx_count--;
+                       *skb_put(info->rx_skb, 1) = byte;
+                       if (info->rx_count == 0) {
+                               info->rx_count = brf6150_get_data_len(info, info->rx_skb);
+                               if (info->rx_count > skb_tailroom(info->rx_skb)) {
+                                       printk(KERN_WARNING "brf6150: Frame is %ld bytes too long.\n",
+                                              info->rx_count - skb_tailroom(info->rx_skb));
+                                       info->rx_skb = NULL;
+                                       info->garbage_bytes = info->rx_count - skb_tailroom(info->rx_skb);
+                                       clk_disable(info->uart_ck);
+                                       break;
+                               }
+                               info->rx_state = WAIT_FOR_DATA;
+                               if (bt_cb(info->rx_skb)->pkt_type == H4_NEG_PKT) {
+                                       brf6150_negotiation_packet(info, info->rx_skb);
+                                       info->rx_skb = NULL;
+                                       clk_disable(info->uart_ck);
+                                       return;
+                               }
+                               if (bt_cb(info->rx_skb)->pkt_type == H4_ALIVE_PKT) {
+                                       brf6150_alive_packet(info, info->rx_skb);
+                                       info->rx_skb = NULL;
+                                       clk_disable(info->uart_ck);
+                                       return;
+                               }
+                       }
+                       break;
+               case WAIT_FOR_DATA:
+                       info->rx_count--;
+                       *skb_put(info->rx_skb, 1) = byte;
+                       if (info->rx_count == 0) {
+                               brf6150_recv_frame(info, info->rx_skb);
+                               info->rx_skb = NULL;
+                               clk_disable(info->uart_ck);
+                       }
+                       break;
+               default:
+                       WARN_ON(1);
+                       break;
+               }
+       }
+
+       NBT_DBG_TRANSFER_NF("\n");
+}
+
+static void brf6150_tx_tasklet(unsigned long data)
+{
+       unsigned int sent = 0;
+       unsigned long flags;
+       struct sk_buff *skb;
+       struct brf6150_info *info = (struct brf6150_info *)data;
+
+       NBT_DBG_TRANSFER("tx_tasklet woke up\n data ");
+
+       skb = skb_dequeue(&info->txq);
+       if (!skb) {
+               /* No data in buffer */
+               brf6150_enable_pm_tx(info);
+               return;
+       }
+
+       /* Copy data to tx fifo */
+       while (!(brf6150_inb(info, UART_OMAP_SSR) & UART_OMAP_SSR_TXFULL) &&
+              (sent < skb->len)) {
+               NBT_DBG_TRANSFER_NF("0x%.2x ", skb->data[sent]);
+               brf6150_outb(info, UART_TX, skb->data[sent]);
+               sent++;
+       }
+
+       info->hdev->stat.byte_tx += sent;
+       NBT_DBG_TRANSFER_NF("\n");
+       if (skb->len == sent) {
+               kfree_skb(skb);
+               clk_disable(info->uart_ck);
+       } else {
+               skb_pull(skb, sent);
+               skb_queue_head(&info->txq, skb);
+       }
+
+       spin_lock_irqsave(&info->lock, flags);
+       brf6150_outb(info, UART_IER, brf6150_inb(info, UART_IER) | UART_IER_THRI);
+       spin_unlock_irqrestore(&info->lock, flags);
+}
+
+static irqreturn_t brf6150_interrupt(int irq, void *data)
+{
+       struct brf6150_info *info = (struct brf6150_info *)data;
+       u8 iir, msr;
+       int ret;
+       unsigned long flags;
+
+       ret = IRQ_NONE;
+
+       clk_enable(info->uart_ck);
+       iir = brf6150_inb(info, UART_IIR);
+       if (iir & UART_IIR_NO_INT) {
+               printk("Interrupt but no reason irq 0x%.2x\n", iir);
+               clk_disable(info->uart_ck);
+               return IRQ_HANDLED;
+       }
+
+       NBT_DBG("In interrupt handler iir 0x%.2x\n", iir);
+
+       iir &= UART_IIR_ID;
+
+       if (iir == UART_IIR_MSI) {
+               msr = brf6150_inb(info, UART_MSR);
+               ret = IRQ_HANDLED;
+       }
+       if (iir == UART_IIR_RLSI) {
+               brf6150_inb(info, UART_RX);
+               brf6150_inb(info, UART_LSR);
+               ret = IRQ_HANDLED;
+       }
+
+       if (iir == UART_IIR_RDI) {
+               brf6150_rx(info);
+               ret = IRQ_HANDLED;
+       }
+
+       if (iir == UART_IIR_THRI) {
+               spin_lock_irqsave(&info->lock, flags);
+               brf6150_outb(info, UART_IER, brf6150_inb(info, UART_IER) & ~UART_IER_THRI);
+               spin_unlock_irqrestore(&info->lock, flags);
+               tasklet_schedule(&info->tx_task);
+               ret = IRQ_HANDLED;
+       }
+
+       clk_disable(info->uart_ck);
+       return ret;
+}
+
+static irqreturn_t brf6150_wakeup_interrupt(int irq, void *dev_inst)
+{
+       struct brf6150_info *info = dev_inst;
+       int should_wakeup;
+       unsigned long flags;
+
+       spin_lock_irqsave(&info->lock, flags);
+       should_wakeup = omap_get_gpio_datain(info->btinfo->host_wakeup_gpio);
+       NBT_DBG_POWER("gpio interrupt %d\n", should_wakeup);
+       if (should_wakeup) {
+               clk_enable(info->uart_ck);
+               brf6150_set_auto_ctsrts(info, 1);
+               brf6150_rx(info);
+               tasklet_schedule(&info->tx_task);
+       } else {
+               brf6150_set_auto_ctsrts(info, 0);
+               brf6150_set_rts(info, 0);
+               clk_disable(info->uart_ck);
+       }
+
+       spin_unlock_irqrestore(&info->lock, flags);
+       return IRQ_HANDLED;
+}
+
+static int brf6150_init_uart(struct brf6150_info *info)
+{
+       int count = 0;
+
+       /* Reset the  UART */
+       brf6150_outb(info, UART_OMAP_SYSC, UART_SYSC_OMAP_RESET);
+       while (!(brf6150_inb(info, UART_OMAP_SYSS) & UART_SYSS_RESETDONE)) {
+               if (count++ > 100) {
+                       printk(KERN_ERR "brf6150: UART reset timeout\n");
+                       return -1;
+               }
+               udelay(1);
+       }
+
+       /* Enable and setup FIFO */
+       brf6150_outb(info, UART_LCR, UART_LCR_WLEN8);
+       brf6150_outb(info, UART_OMAP_MDR1, 0x00); /* Make sure UART mode is enabled */
+       brf6150_outb(info, UART_OMAP_SCR, 0x00);
+       brf6150_outb(info, UART_EFR, brf6150_inb(info, UART_EFR) | UART_EFR_ECB);
+       brf6150_outb(info, UART_MCR, brf6150_inb(info, UART_MCR) | UART_MCR_TCRTLR);
+       brf6150_outb(info, UART_TI752_TLR, 0xff);
+       brf6150_outb(info, UART_TI752_TCR, 0x1f);
+       brf6150_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+       brf6150_outb(info, UART_IER, UART_IER_RDI);
+
+       return 0;
+}
+
+static int brf6150_reset(struct brf6150_info *info)
+{
+       omap_set_gpio_dataout(info->btinfo->bt_wakeup_gpio, 0);
+       omap_set_gpio_dataout(info->btinfo->reset_gpio, 0);
+       current->state = TASK_UNINTERRUPTIBLE;
+       schedule_timeout(msecs_to_jiffies(10));
+       omap_set_gpio_dataout(info->btinfo->bt_wakeup_gpio, 1);
+       current->state = TASK_UNINTERRUPTIBLE;
+       schedule_timeout(msecs_to_jiffies(100));
+       omap_set_gpio_dataout(info->btinfo->reset_gpio, 1);
+       current->state = TASK_UNINTERRUPTIBLE;
+       schedule_timeout(msecs_to_jiffies(100));
+
+       return 0;
+}
+
+static int brf6150_send_firmware(struct brf6150_info *info)
+{
+       struct sk_buff *skb;
+
+       init_completion(&info->fw_completion);
+       info->fw_error = 0;
+
+       while ((skb = brf6150_read_fw_cmd(info, GFP_KERNEL)) != NULL) {
+               clk_enable(info->uart_ck);
+               skb_queue_tail(&info->txq, skb);
+               tasklet_schedule(&info->tx_task);
+
+               if (!wait_for_completion_timeout(&info->fw_completion, HZ)) {
+                       return -1;
+               }
+
+               if (info->fw_error) {
+                       return -1;
+               }
+       }
+       NBT_DBG_FW("Firmware sent\n");
+
+       return 0;
+
+}
+
+/* hci callback functions */
+static int brf6150_hci_flush(struct hci_dev *hdev)
+{
+       struct brf6150_info *info;
+       info = hdev->driver_data;
+
+       skb_queue_purge(&info->txq);
+
+       return 0;
+}
+
+static int brf6150_hci_open(struct hci_dev *hdev)
+{
+       struct brf6150_info *info;
+       int err;
+
+       info = hdev->driver_data;
+
+       if (test_bit(HCI_RUNNING, &hdev->flags))
+               return 0;
+
+       if (brf6150_open_firmware(info) < 0) {
+               printk("Cannot open firmware\n");
+               return -1;
+       }
+
+       info->rx_state = WAIT_FOR_PKT_TYPE;
+       info->rx_count = 0;
+       info->garbage_bytes = 0;
+       info->rx_skb = NULL;
+       info->pm_enabled = 0;
+       set_irq_type(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), IRQT_NOEDGE);
+       init_completion(&info->fw_completion);
+
+       clk_enable(info->uart_ck);
+
+       brf6150_init_uart(info);
+       brf6150_set_auto_ctsrts(info, 0);
+       brf6150_set_rts(info, 0);
+       brf6150_reset(info);
+       brf6150_wait_for_cts(info, 1, 10);
+       brf6150_set_rts(info, 1);
+       if (brf6150_send_negotiation(info)) {
+               brf6150_close_firmware(info);
+               return -1;
+       }
+
+       if (!wait_for_completion_interruptible_timeout(&info->init_completion, HZ)) {
+               brf6150_close_firmware(info);
+               clk_disable(info->uart_ck);
+               clear_bit(HCI_RUNNING, &hdev->flags);
+               return -1;
+       }
+       brf6150_set_auto_ctsrts(info, 1);
+
+       err = brf6150_send_firmware(info);
+       brf6150_close_firmware(info);
+       if (err < 0)
+               printk(KERN_ERR "brf6150: Sending firmware failed. Bluetooth won't work properly\n");
+
+       set_irq_type(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), IRQT_BOTHEDGE);
+       info->pm_enabled = 1;
+       set_bit(HCI_RUNNING, &hdev->flags);
+       return 0;
+}
+
+static int brf6150_hci_close(struct hci_dev *hdev)
+{
+       struct brf6150_info *info = hdev->driver_data;
+       if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+               return 0;
+
+       brf6150_hci_flush(hdev);
+       clk_disable(info->uart_ck);
+       del_timer_sync(&info->pm_timer);
+       omap_set_gpio_dataout(info->btinfo->bt_wakeup_gpio, 0);
+       set_irq_type(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), IRQT_NOEDGE);
+
+       return 0;
+}
+
+static void brf6150_hci_destruct(struct hci_dev *hdev)
+{
+}
+
+static int brf6150_hci_send_frame(struct sk_buff *skb)
+{
+       struct brf6150_info *info;
+       struct hci_dev *hdev = (struct hci_dev *)skb->dev;
+
+       if (!hdev) {
+               printk(KERN_WARNING "brf6150: Frame for unknown device\n");
+               return -ENODEV;
+       }
+
+       if (!test_bit(HCI_RUNNING, &hdev->flags)) {
+               printk(KERN_WARNING "brf6150: Frame for non-running device\n");
+               return -EIO;
+       }
+
+       info = hdev->driver_data;
+
+       switch (bt_cb(skb)->pkt_type) {
+               case HCI_COMMAND_PKT:
+                       hdev->stat.cmd_tx++;
+                       break;
+               case HCI_ACLDATA_PKT:
+                       hdev->stat.acl_tx++;
+                       break;
+               case HCI_SCODATA_PKT:
+                       hdev->stat.sco_tx++;
+                       break;
+       };
+
+       /* Push frame type to skb */
+       clk_enable(info->uart_ck);
+       *skb_push(skb, 1) = bt_cb(skb)->pkt_type;
+       skb_queue_tail(&info->txq, skb);
+
+       brf6150_disable_pm_tx(info);
+
+       return 0;
+}
+
+static int brf6150_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
+{
+       return -ENOIOCTLCMD;
+}
+
+static void brf6150_device_release(struct device *dev)
+{
+}
+
+static int brf6150_register_hdev(struct brf6150_info *info)
+{
+       struct hci_dev *hdev;
+
+       /* Initialize and register HCI device */
+
+       hdev = hci_alloc_dev();
+       if (!hdev) {
+               printk(KERN_WARNING "brf6150: Can't allocate memory for device\n");
+               return -ENOMEM;
+       }
+       info->hdev = hdev;
+
+       hdev->type = HCI_UART;
+       hdev->driver_data = info;
+
+       hdev->open = brf6150_hci_open;
+       hdev->close = brf6150_hci_close;
+       hdev->destruct = brf6150_hci_destruct;
+       hdev->flush = brf6150_hci_flush;
+       hdev->send = brf6150_hci_send_frame;
+       hdev->destruct = brf6150_hci_destruct;
+       hdev->ioctl = brf6150_hci_ioctl;
+
+       hdev->owner = THIS_MODULE;
+
+       if (hci_register_dev(hdev) < 0) {
+               printk(KERN_WARNING "brf6150: Can't register HCI device %s.\n", hdev->name);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int __init brf6150_init(void)
+{
+       struct brf6150_info *info;
+       int irq, err;
+
+       info = kmalloc(sizeof(struct brf6150_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+       memset(info, 0, sizeof(struct brf6150_info));
+
+       brf6150_device.dev.driver_data = info;
+       init_completion(&info->init_completion);
+       init_completion(&info->fw_completion);
+       info->pm_enabled = 0;
+       info->rx_pm_enabled = 0;
+       info->tx_pm_enabled = 0;
+       info->garbage_bytes = 0;
+       tasklet_init(&info->tx_task, brf6150_tx_tasklet, (unsigned long)info);
+       spin_lock_init(&info->lock);
+       skb_queue_head_init(&info->txq);
+       init_timer(&info->pm_timer);
+       info->pm_timer.function = brf6150_pm_timer;
+       info->pm_timer.data = (unsigned long)info;
+       exit_info = NULL;
+
+       info->btinfo = omap_get_config(OMAP_TAG_NOKIA_BT, struct omap_bluetooth_config);
+       if (info->btinfo == NULL)
+               return -1;
+
+       NBT_DBG("RESET gpio: %d\n", info->btinfo->reset_gpio);
+       NBT_DBG("BTWU gpio: %d\n", info->btinfo->bt_wakeup_gpio);
+       NBT_DBG("HOSTWU gpio: %d\n", info->btinfo->host_wakeup_gpio);
+       NBT_DBG("Uart: %d\n", info->btinfo->bt_uart);
+       NBT_DBG("sysclk: %d\n", info->btinfo->bt_sysclk);
+
+       err = omap_request_gpio(info->btinfo->reset_gpio);
+       if (err < 0)
+       {
+               printk(KERN_WARNING "Cannot get GPIO line %d", 
+                      info->btinfo->reset_gpio);
+               kfree(info);
+               return err;
+       }
+
+       err = omap_request_gpio(info->btinfo->bt_wakeup_gpio);
+       if (err < 0)
+       {
+               printk(KERN_WARNING "Cannot get GPIO line 0x%d",
+                      info->btinfo->bt_wakeup_gpio);
+               omap_free_gpio(info->btinfo->reset_gpio);
+               kfree(info);
+               return err;
+       }
+
+       err = omap_request_gpio(info->btinfo->host_wakeup_gpio);
+       if (err < 0)
+       {
+               printk(KERN_WARNING "Cannot get GPIO line %d",
+                      info->btinfo->host_wakeup_gpio);
+               omap_free_gpio(info->btinfo->reset_gpio);
+               omap_free_gpio(info->btinfo->bt_wakeup_gpio);
+               kfree(info);
+               return err;
+       }
+
+       omap_set_gpio_direction(info->btinfo->reset_gpio, 0);
+       omap_set_gpio_direction(info->btinfo->bt_wakeup_gpio, 0);
+       omap_set_gpio_direction(info->btinfo->host_wakeup_gpio, 1);
+       set_irq_type(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), IRQT_NOEDGE);
+
+       switch (info->btinfo->bt_uart) {
+       case 1:
+               irq = INT_UART1;
+               info->uart_ck = clk_get(NULL, "uart1_ck");
+               info->uart_base = io_p2v((unsigned long)OMAP_UART1_BASE);
+               break;
+       case 2:
+               irq = INT_UART2;
+               info->uart_ck = clk_get(NULL, "uart2_ck");
+               info->uart_base = io_p2v((unsigned long)OMAP_UART2_BASE);
+               break;
+       case 3:
+               irq = INT_UART3;
+               info->uart_ck = clk_get(NULL, "uart3_ck");
+               info->uart_base = io_p2v((unsigned long)OMAP_UART3_BASE);
+               break;
+       default:
+               printk(KERN_ERR "No uart defined\n");
+               goto cleanup;
+       }
+
+       info->irq = irq;
+       err = request_irq(irq, brf6150_interrupt, 0, "brf6150", (void *)info);
+       if (err < 0) {
+               printk(KERN_ERR "brf6150: unable to get IRQ %d\n", irq);
+               goto cleanup;
+       }
+
+       err = request_irq(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio),
+                       brf6150_wakeup_interrupt, 0, "brf6150_wkup", (void *)info);
+       if (err < 0) {
+               printk(KERN_ERR "brf6150: unable to get wakeup IRQ %d\n",
+                               OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio));
+               free_irq(irq, (void *)info);
+               goto cleanup;
+       }
+
+       /* Register with LDM */
+       if (platform_device_register(&brf6150_device)) {
+               printk(KERN_ERR "failed to register brf6150 device\n");
+               err = -ENODEV;
+               goto cleanup_irq;
+       }
+       /* Register the driver with LDM */
+       if (driver_register(&brf6150_driver)) {
+               printk(KERN_WARNING "failed to register brf6150 driver\n");
+               platform_device_unregister(&brf6150_device);
+               err = -ENODEV;
+               goto cleanup_irq;
+       }
+
+       if (brf6150_register_hdev(info) < 0) {
+               printk(KERN_WARNING "failed to register brf6150 hci device\n");
+               platform_device_unregister(&brf6150_device);
+               driver_unregister(&brf6150_driver);
+               goto cleanup_irq;
+       }
+
+       exit_info = info;
+       return 0;
+
+cleanup_irq:
+       free_irq(irq, (void *)info);
+       free_irq(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), (void *)info);
+cleanup:
+       omap_free_gpio(info->btinfo->reset_gpio);
+       omap_free_gpio(info->btinfo->bt_wakeup_gpio);
+       omap_free_gpio(info->btinfo->host_wakeup_gpio);
+       kfree(info);
+
+       return err;
+}
+
+static void __exit brf6150_exit(void)
+{
+       brf6150_hci_close(exit_info->hdev);
+       hci_free_dev(exit_info->hdev);
+       omap_free_gpio(exit_info->btinfo->reset_gpio);
+       omap_free_gpio(exit_info->btinfo->bt_wakeup_gpio);
+       omap_free_gpio(exit_info->btinfo->host_wakeup_gpio);
+       free_irq(exit_info->irq, (void *)exit_info);
+       free_irq(OMAP_GPIO_IRQ(exit_info->btinfo->host_wakeup_gpio), (void *)exit_info);
+       kfree(exit_info);
+}
+
+module_init(brf6150_init);
+module_exit(brf6150_exit);
+
+MODULE_DESCRIPTION("brf6150 hci driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ville Tervo <ville.tervo@nokia.com>");
diff --git a/drivers/bluetooth/brf6150.h b/drivers/bluetooth/brf6150.h
new file mode 100644 (file)
index 0000000..334a72e
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ *  linux/drivers/bluetooth/brf6150/brf6150.h
+ *
+ *  Copyright (C) 2005 Nokia Corporation
+ *  Written by Ville Tervo <ville.tervo@nokia.com>
+ *
+ *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <asm/arch/board.h>
+
+#ifndef __DRIVERS_BLUETOOTH_BRF6150_H
+#define __DRIVERS_BLUETOOTH_BRF6150_H
+
+#define UART_SYSC_OMAP_RESET   0x02
+#define UART_SYSS_RESETDONE    0x01
+#define UART_OMAP_SCR_EMPTY_THR        0x08
+#define UART_OMAP_SCR_WAKEUP   0x10
+#define UART_OMAP_SSR_WAKEUP   0x02
+#define UART_OMAP_SSR_TXFULL   0x01
+
+struct brf6150_info {
+       struct hci_dev *hdev;
+       spinlock_t lock;
+
+       struct clk *uart_ck;
+       unsigned long uart_base;
+       unsigned int irq;
+
+       struct sk_buff_head txq;
+       struct sk_buff *rx_skb;
+       const struct omap_bluetooth_config *btinfo;
+       const struct firmware *fw_entry;
+       int fw_pos;
+       int fw_error;
+       struct completion fw_completion;
+       struct completion init_completion;
+       struct tasklet_struct tx_task;
+       long rx_count;
+       unsigned long garbage_bytes;
+       unsigned long rx_state;
+       int pm_enabled;
+       int rx_pm_enabled;
+       int tx_pm_enabled;
+       struct timer_list pm_timer;
+};
+
+#define BT_DEVICE "nokia_btuart"
+#define BT_DRIVER "nokia_btuart"
+
+#define MAX_BAUD_RATE          921600
+#define UART_CLOCK             48000000
+#define BT_INIT_DIVIDER                320
+#define BT_BAUDRATE_DIVIDER    384000000
+#define BT_SYSCLK_DIV          1000
+#define INIT_SPEED             120000
+
+#define H4_TYPE_SIZE           1
+
+/* H4+ packet types */
+#define H4_CMD_PKT             0x01
+#define H4_ACL_PKT             0x02
+#define H4_SCO_PKT             0x03
+#define H4_EVT_PKT             0x04
+#define H4_NEG_PKT             0x06
+#define H4_ALIVE_PKT           0x07
+
+/* TX states */
+#define WAIT_FOR_PKT_TYPE      1
+#define WAIT_FOR_HEADER                2
+#define WAIT_FOR_DATA          3
+
+struct hci_fw_event {
+       struct hci_event_hdr hev;
+       struct hci_ev_cmd_complete cmd;
+       __u8 status;
+} __attribute__ ((packed));
+
+#endif /* __DRIVERS_BLUETOOTH_BRF6150_H */
index f1a5c63e8c94838d54881f6290f2ae6a1f8b7591..008d193ccba3fc601533a6acd7dbe232abc7f29e 100644 (file)
@@ -25,14 +25,14 @@ config CBUS_TAHVO_USER
        depends on CBUS_TAHVO
        bool "Support for Tahvo user space functions"
        ---help---
-         If you want support for Tahvo's user space read/write etc. functions,
+         If you want support for Tahvo's user space read/write etc. functions, 
          you should say Y here.
 
 config CBUS_TAHVO_USB
        depends on CBUS_TAHVO && USB
        tristate "Support for Tahvo USB transceiver"
        ---help---
-         If you want Tahvo support for USB transceiver, say Y or M here.
+         If you want Tahvo support for USB transceiver, say Y or M here. 
 
 config CBUS_TAHVO_USB_HOST_BY_DEFAULT
        depends on CBUS_TAHVO_USB && USB_OTG
@@ -53,7 +53,7 @@ config CBUS_RETU_USER
        depends on CBUS_RETU
        bool "Support for Retu user space functions"
        ---help---
-         If you want support for Retu's user space read/write etc. functions,
+         If you want support for Retu's user space read/write etc. functions, 
          you should say Y here.
 
 config CBUS_RETU_POWERBUTTON
index ad37b6d051beb07898223accc780ca8da5884df1..7a7469f6f62a0df46d4ded5a5095a1c47ef3fc7c 100644 (file)
@@ -91,7 +91,7 @@ static int __init retubutton_init(void)
        pwrbtn_dev = input_allocate_device();
        if (!pwrbtn_dev)
                return -ENOMEM;
-
+       
        pwrbtn_dev->evbit[0] = BIT(EV_KEY);
        pwrbtn_dev->keybit[LONG(KEY_POWER)] = BIT(KEY_POWER);
        pwrbtn_dev->name = "retu-pwrbutton";
index 1c5a2a53d6e6afca29a5d00a117dc84927040024..934400f69882688802c4ad28993969fb6702be17 100644 (file)
@@ -105,7 +105,7 @@ static struct platform_device tahvo_usb_device;
  * OTG related functions
  *
  * These shoud be separated into omap-otg.c driver module, as they are used
- * by various transceivers. These functions are needed in the UDC-only case
+ * by various transceivers. These functions are needed in the UDC-only case 
  * as well. These functions are copied from GPL isp1301_omap.c
  * ---------------------------------------------------------------------------
  */
index 9e43e39dc35c09dc25efafa0c56555bfeabf4dea..ba2157b1e9a13a8cf8613602a8b83e9b2b4a8568 100644 (file)
@@ -696,6 +696,16 @@ config NWFLASH
 
 source "drivers/char/hw_random/Kconfig"
 
+config OMAP_RNG
+       tristate "OMAP Random Number Generator support"
+       depends on ARCH_OMAP16XX || ARCH_OMAP24XX
+       ---help---
+         This driver provides kernel-side support for the Random Number
+         Generator hardware found on OMAP16xx and OMAP24xx multimedia
+         processors.
+
+         If unsure, say N.
+
 config NVRAM
        tristate "/dev/nvram support"
        depends on ATARI || X86 || ARM || GENERIC_NVRAM
@@ -798,6 +808,11 @@ config GEN_RTC_X
 config EFI_RTC
        bool "EFI Real Time Clock Services"
        depends on IA64
+config OMAP_RTC
+       bool "TI OMAP Real Time Clock"
+       depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730
+       help
+         Support for TI OMAP RTC
 
 config DS1302
        tristate "DS1302 RTC support"
index fc110637ced6ad4b4f6ae8b70bc3365d69110540..611cdc12afb8672b7c2ec999a5677f1c1e217155 100644 (file)
@@ -69,6 +69,7 @@ obj-$(CONFIG_GEN_RTC)         += genrtc.o
 obj-$(CONFIG_EFI_RTC)          += efirtc.o
 obj-$(CONFIG_SGI_DS1286)       += ds1286.o
 obj-$(CONFIG_SGI_IP27_RTC)     += ip27-rtc.o
+obj-$(CONFIG_OMAP_RTC)         += omap-rtc.o
 obj-$(CONFIG_DS1302)           += ds1302.o
 ifeq ($(CONFIG_GENERIC_NVRAM),y)
   obj-$(CONFIG_NVRAM)  += generic_nvram.o
index e13dd1892bfdf95bb8c8e731528c12eab1a4fb4d..773d8a87510ba9799dd6a048b1a7e596672578a5 100644 (file)
@@ -179,7 +179,6 @@ static struct platform_driver omap_rng_driver = {
                .name           = "omap_rng",
                .owner          = THIS_MODULE,
        },
-       .probe          = omap_rng_probe,
        .remove         = __exit_p(omap_rng_remove),
        .suspend        = omap_rng_suspend,
        .resume         = omap_rng_resume
@@ -190,7 +189,7 @@ static int __init omap_rng_init(void)
        if (!cpu_is_omap16xx() && !cpu_is_omap24xx())
                return -ENODEV;
 
-       return platform_driver_register(&omap_rng_driver);
+       return platform_driver_probe(&omap_rng_driver, omap_rng_probe);
 }
 
 static void __exit omap_rng_exit(void)
diff --git a/drivers/char/omap-rng.c b/drivers/char/omap-rng.c
new file mode 100644 (file)
index 0000000..cc3290e
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * drivers/char/omap-rng.c
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * OMAP16xx and OMAP24xx Random Number Generator driver
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/random.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+
+#if defined (CONFIG_ARCH_OMAP16XX)
+#define RNG_BASE               0xfffe5000
+#endif
+#if defined (CONFIG_ARCH_OMAP24XX)
+#define RNG_BASE               0x480A0000
+#endif
+
+#define RNG_OUT_REG            0x00            /* Output register */
+#define RNG_STAT_REG           0x04            /* Status register
+                                                       [0] = STAT_BUSY */
+#define RNG_ALARM_REG          0x24            /* Alarm register
+                                                       [7:0] = ALARM_COUNTER */
+#define RNG_CONFIG_REG         0x28            /* Configuration register
+                                                       [11:6] = RESET_COUNT
+                                                       [5:3]  = RING2_DELAY 
+                                                       [2:0]  = RING1_DELAY */
+#define RNG_REV_REG            0x3c            /* Revision register
+                                                       [7:0] = REV_NB */
+#define RNG_MASK_REG           0x40            /* Mask and reset register
+                                                       [2] = IT_EN
+                                                       [1] = SOFTRESET
+                                                       [0] = AUTOIDLE */
+#define RNG_SYSSTATUS          0x44            /* System status
+                                                       [0] = RESETDONE */
+
+#define ENTROPY_WORD_COUNT     128
+
+static u32 rng_base = io_p2v(RNG_BASE);
+
+static struct clk *rng_ick = NULL;
+
+static u32 rng_read_reg(int reg)
+{
+       return __raw_readl(rng_base + reg);
+}
+
+static void rng_write_reg(int reg, u32 val)
+{
+       __raw_writel(val, rng_base + reg);
+}
+
+static void rng_feed_entropy(int count)
+{
+       u32 l;
+
+       while (count--) {
+               while (rng_read_reg(RNG_STAT_REG));
+               l = rng_read_reg(RNG_OUT_REG);
+               add_input_randomness(0, 0, l);
+       }
+}
+
+static int __init rng_init(void)
+{
+       if (!cpu_is_omap16xx() && !cpu_is_omap24xx())
+               return -ENODEV;
+
+       if (cpu_is_omap24xx()) {
+               rng_ick = clk_get(NULL, "rng_ick");
+               if (IS_ERR(rng_ick)) {
+                       printk(KERN_ERR "omap-rng.c: Could not get rng_ick\n");
+                       return PTR_ERR(rng_ick);
+               }
+               clk_enable(rng_ick);
+       }
+
+       printk("OMAP Random Number Generator ver. %02x\n",
+       rng_read_reg(RNG_REV_REG));
+       rng_write_reg(RNG_MASK_REG, 0x00000001);
+       rng_feed_entropy(ENTROPY_WORD_COUNT);
+       rng_write_reg(RNG_MASK_REG, 0x00000000);
+       printk("%d words of entropy generated\n", ENTROPY_WORD_COUNT);
+
+       return 0;
+}
+late_initcall(rng_init);
diff --git a/drivers/char/omap-rtc.c b/drivers/char/omap-rtc.c
new file mode 100644 (file)
index 0000000..f1b3fa3
--- /dev/null
@@ -0,0 +1,788 @@
+/*
+ *     TI OMAP Real Time Clock interface for Linux     
+ *
+ *     Copyright (C) 2003 MontaVista Software, Inc.
+ *      Author: George G. Davis <gdavis@mvista.com> or <source@mvista.com>
+ *
+ *     Initially based on linux-2.4.20/drivers/char/rtc.c
+ *     Copyright (C) 1996 Paul Gortmaker
+ *
+ *     This driver allows use of the real time clock (built into
+ *     nearly all computers) from user space. It exports the /dev/rtc
+ *     interface supporting various ioctl() and also the
+ *     /proc/driver/rtc pseudo-file for status information.
+ *
+ *     The ioctls can be used to set the interrupt behaviour from the
+ *     RTC via IRQs. Then the /dev/rtc interface can be used to make
+ *     use of RTC interrupts, be they time update or alarm based.
+ *
+ *     The /dev/rtc interface will block on reads until an interrupt
+ *     has been received. If a RTC interrupt has already happened,
+ *     it will output an unsigned long and then block. The output value
+ *     contains the interrupt status in the low byte and the number of
+ *     interrupts since the last read in the remaining high bytes. The 
+ *     /dev/rtc interface can also be used with the select(2) call.
+ *
+ *     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.
+ *
+ *     Based on other minimal char device drivers, like Alan's
+ *     watchdog, Ted's random, etc. etc.
+ *
+ * Change Log :
+ *      v1.0    <gdavis@mvista.com> Initial version based on rtc.c v1.10e
+ *              <ramakrishnan@india.ti.com> Added support for 2.6 kernel, 
+ *                  - changed the return value of the interrupt handler
+ */
+
+/*
+ *     Note that *all* calls to CMOS_READ and CMOS_WRITE are done with
+ *     interrupts disabled.
+ *     REVISIT: Elaborate on OMAP1510 TRM 15uS BUSY access rule.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/rtc.h>
+#include <asm/mach/time.h>
+
+#include "omap-rtc.h"
+
+extern spinlock_t rtc_lock;
+
+static int omap_rtc_alarm = NO_IRQ;
+static int omap_rtc_timer = NO_IRQ;
+
+
+/* OMAP RTC register access macros: */
+
+#define CMOS_READ(addr)                omap_readb(addr)
+#define CMOS_WRITE(val, addr)  omap_writeb(val, addr)
+
+static struct fasync_struct *rtc_async_queue;
+
+static DECLARE_WAIT_QUEUE_HEAD(rtc_wait);
+
+static void get_rtc_time (struct rtc_time *rtc_tm);
+static void get_rtc_alm_time (struct rtc_time *alm_tm);
+
+static void set_rtc_irq_bit(unsigned char bit);
+static void mask_rtc_irq_bit(unsigned char bit);
+
+static int rtc_read_proc(char *page, char **start, off_t off,
+                         int count, int *eof, void *data);
+
+/*
+ *     Bits in rtc_status. (7 bits of room for future expansion)
+ */
+
+#define RTC_IS_OPEN            0x01    /* means /dev/rtc is in use     */
+
+/*
+ * REVISIT: fix this comment:
+ * rtc_status is never changed by rtc_interrupt, and ioctl/open/close is
+ * protected by the big kernel lock.
+ */
+static unsigned long rtc_status = 0;   /* bitmapped status byte.       */
+static unsigned long rtc_irq_data = 0; /* our output to the world      */
+
+/*
+ *     If this driver ever becomes modularised, it will be really nice
+ *     to make the epoch retain its value across module reload...
+ */
+
+static unsigned long epoch = 1900;     /* year corresponding to 0x00   */
+
+static const unsigned char days_in_mo[] = 
+{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+/*
+ *     A very tiny interrupt handler. It runs with IRQF_DISABLED set.
+ */
+
+irqreturn_t rtc_interrupt(int irq, void *dev_id)
+{
+       /*
+        *      Either an alarm interrupt or update complete interrupt.
+        *      We store the status in the low byte and the number of
+        *      interrupts received since the last read in the remainder
+        *      of rtc_irq_data.
+        */
+
+       spin_lock (&rtc_lock);
+
+       rtc_irq_data += 0x100;
+       rtc_irq_data &= ~0xff;
+       rtc_irq_data |= CMOS_READ(OMAP_RTC_STATUS_REG);
+
+       if (rtc_irq_data & OMAP_RTC_STATUS_ALARM)
+               CMOS_WRITE(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG);
+
+       spin_unlock (&rtc_lock);
+
+       /* Now do the rest of the actions */
+       wake_up_interruptible(&rtc_wait);       
+
+       kill_fasync (&rtc_async_queue, SIGIO, POLL_IN);
+       return IRQ_HANDLED;
+}
+
+/*
+ *     Now all the various file operations that we export.
+ */
+
+static ssize_t rtc_read(struct file *file, char __user *buf,
+                       size_t count, loff_t *ppos)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       unsigned long data;
+       ssize_t retval;
+       
+       if (count < sizeof(unsigned long))
+               return -EINVAL;
+
+       add_wait_queue(&rtc_wait, &wait);
+       set_current_state(TASK_INTERRUPTIBLE);
+
+       for (;;) {
+               spin_lock_irq (&rtc_lock);
+               data = rtc_irq_data;
+               if (data != 0) {
+                       rtc_irq_data = 0;
+                       break;
+               }
+               spin_unlock_irq (&rtc_lock);
+
+               if (file->f_flags & O_NONBLOCK) {
+                       retval = -EAGAIN;
+                       goto out;
+               }
+               if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+                       goto out;
+               }
+               schedule();
+       }
+
+       spin_unlock_irq (&rtc_lock);
+       retval = put_user(data, (unsigned long __user *)buf);
+       if (!retval)
+               retval = sizeof(unsigned long); 
+ out:
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&rtc_wait, &wait);
+
+       return retval;
+}
+
+/* convert from userspace struct to hardware BCD-encoded version,
+ * or return error code
+ */
+static int utm2bcd(struct rtc_time __user *arg, struct rtc_time *tm)
+{
+       unsigned char leap_yr;
+
+       if (copy_from_user(tm, arg, sizeof(struct rtc_time)))
+               return -EFAULT;
+
+       tm->tm_year += 1900;
+       tm->tm_mon++;
+
+       if (tm->tm_year < 1970)
+               return -EINVAL;
+
+       leap_yr = (!(tm->tm_year % 4) && (tm->tm_year % 100))
+                       || !(tm->tm_year % 400);
+
+       if ((tm->tm_mon > 12) || (tm->tm_mday == 0))
+               return -EINVAL;
+
+       if (tm->tm_mday > (days_in_mo[tm->tm_mon] + ((tm->tm_mon == 2) && leap_yr)))
+               return -EINVAL;
+
+       if ((tm->tm_hour >= 24) || (tm->tm_min >= 60) || (tm->tm_sec >= 60))
+               return -EINVAL;
+
+       if ((tm->tm_year -= epoch) > 255)    /* They are unsigned */
+               return -EINVAL;
+
+       if (tm->tm_year > 169)
+               return -EINVAL;
+
+       if (tm->tm_year >= 100)
+               tm->tm_year -= 100;
+
+       BIN_TO_BCD(tm->tm_sec);
+       BIN_TO_BCD(tm->tm_min);
+       BIN_TO_BCD(tm->tm_hour);
+       BIN_TO_BCD(tm->tm_mday);
+       BIN_TO_BCD(tm->tm_mon);
+       BIN_TO_BCD(tm->tm_year);
+
+       return 0;
+}
+
+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+                    unsigned long arg)
+{
+       struct rtc_time wtime; 
+       int status = 0;
+       u8 save_control;
+
+       switch (cmd) {
+       case RTC_AIE_OFF:       /* Mask alarm int. enab. bit    */
+               mask_rtc_irq_bit(OMAP_RTC_INTERRUPTS_IT_ALARM);
+               break;
+       case RTC_AIE_ON:        /* Allow alarm interrupts.      */
+               set_rtc_irq_bit(OMAP_RTC_INTERRUPTS_IT_ALARM);
+               break;
+       case RTC_UIE_OFF:       /* Mask ints from RTC updates.  */
+               mask_rtc_irq_bit(OMAP_RTC_INTERRUPTS_IT_TIMER);
+               break;
+       case RTC_UIE_ON:        /* Allow ints for RTC updates.  */
+               set_rtc_irq_bit(OMAP_RTC_INTERRUPTS_IT_TIMER);
+               break;
+       case RTC_ALM_READ:      /* Read the present alarm time */
+               /*
+                * This returns a struct rtc_time. Reading >= 0xc0
+                * means "don't care" or "match all". Only the tm_hour,
+                * tm_min, and tm_sec values are filled in.
+                */
+               memset(&wtime, 0, sizeof(struct rtc_time));
+               get_rtc_alm_time(&wtime);
+               goto return_wtime;
+       case RTC_ALM_SET:       /* Store a time into the alarm */
+               status = utm2bcd((void __user *)arg, &wtime);
+               if (status != 0)
+                       return status;
+
+               spin_lock_irq(&rtc_lock);
+               CMOS_WRITE(wtime.tm_year, OMAP_RTC_ALARM_YEARS_REG);
+               CMOS_WRITE(wtime.tm_mon, OMAP_RTC_ALARM_MONTHS_REG);
+               CMOS_WRITE(wtime.tm_mday, OMAP_RTC_ALARM_DAYS_REG);
+               CMOS_WRITE(wtime.tm_hour, OMAP_RTC_ALARM_HOURS_REG);
+               CMOS_WRITE(wtime.tm_min, OMAP_RTC_ALARM_MINUTES_REG);
+               CMOS_WRITE(wtime.tm_sec, OMAP_RTC_ALARM_SECONDS_REG);
+               spin_unlock_irq(&rtc_lock);
+
+               break;
+       case RTC_RD_TIME:       /* Read the time/date from RTC  */
+               memset(&wtime, 0, sizeof(struct rtc_time));
+               get_rtc_time(&wtime);
+               goto return_wtime;
+       case RTC_SET_TIME:      /* Set the RTC */
+               if (!capable(CAP_SYS_TIME))
+                       return -EACCES;
+
+               status = utm2bcd((void __user *)arg, &wtime);
+               if (status != 0)
+                       return status;
+
+               spin_lock_irq(&rtc_lock);
+               save_control = CMOS_READ(OMAP_RTC_CTRL_REG);
+               CMOS_WRITE((save_control & ~OMAP_RTC_CTRL_STOP),
+                          OMAP_RTC_CTRL_REG);
+               CMOS_WRITE(wtime.tm_year, OMAP_RTC_YEARS_REG);
+               CMOS_WRITE(wtime.tm_mon, OMAP_RTC_MONTHS_REG);
+               CMOS_WRITE(wtime.tm_mday, OMAP_RTC_DAYS_REG);
+               CMOS_WRITE(wtime.tm_hour, OMAP_RTC_HOURS_REG);
+               CMOS_WRITE(wtime.tm_min, OMAP_RTC_MINUTES_REG);
+               CMOS_WRITE(wtime.tm_sec, OMAP_RTC_SECONDS_REG);
+               CMOS_WRITE((save_control | OMAP_RTC_CTRL_STOP),
+                          OMAP_RTC_CTRL_REG);
+               spin_unlock_irq(&rtc_lock);
+
+               break;
+       case RTC_EPOCH_READ:    /* Read the epoch.      */
+               status = put_user (epoch, (unsigned long  __user *)arg);
+               break;
+       case RTC_EPOCH_SET:     /* Set the epoch.       */
+               if (!capable(CAP_SYS_TIME))
+                       return -EACCES;
+
+               /* 
+                * There were no RTC clocks before 1900.
+                */
+               if (arg < 1900)
+                       status = -EINVAL;
+               else
+                       epoch = arg;
+               break;
+       default:
+               status = -ENOTTY;
+       }
+       return status;
+
+return_wtime:
+       return copy_to_user((void  __user *)arg, &wtime, sizeof wtime)
+               ? -EFAULT
+               : 0;
+}
+
+/*
+ *     We enforce only one user at a time here with the open/close.
+ *     Also clear the previous interrupt data on an open, and clean
+ *     up things on a close.
+ */
+
+/* We use rtc_lock to protect against concurrent opens. So the BKL is not
+ * needed here. Or anywhere else in this driver. */
+static int rtc_open(struct inode *inode, struct file *file)
+{
+       spin_lock_irq (&rtc_lock);
+
+       if (rtc_status & RTC_IS_OPEN)
+               goto out_busy;
+
+       rtc_status |= RTC_IS_OPEN;
+
+       rtc_irq_data = 0;
+       spin_unlock_irq (&rtc_lock);
+       return 0;
+
+out_busy:
+       spin_unlock_irq (&rtc_lock);
+       return -EBUSY;
+}
+
+static int rtc_fasync(int fd, struct file *filp, int on)
+{
+       return fasync_helper (fd, filp, on, &rtc_async_queue);
+}
+
+static int rtc_release(struct inode *inode, struct file *file)
+{
+       unsigned char tmp;
+
+       /*
+        * Turn off all interrupts once the device is no longer
+        * in use, and clear the data.
+        */
+
+       spin_lock_irq(&rtc_lock);
+       tmp = CMOS_READ(OMAP_RTC_INTERRUPTS_REG);
+       tmp &=  ~OMAP_RTC_INTERRUPTS_IT_ALARM;
+       tmp &=  ~OMAP_RTC_INTERRUPTS_IT_TIMER;
+       CMOS_WRITE(tmp, OMAP_RTC_INTERRUPTS_REG);
+       spin_unlock_irq(&rtc_lock);
+
+       if (file->f_flags & FASYNC) {
+               rtc_fasync (-1, file, 0);
+       }
+
+       spin_lock_irq (&rtc_lock);
+       rtc_irq_data = 0;
+       spin_unlock_irq (&rtc_lock);
+
+       /* No need for locking -- nobody else can do anything until this rmw
+        * is committed, and we don't implement timer support in omap-rtc.
+        */
+       rtc_status &= ~RTC_IS_OPEN;
+       return 0;
+}
+
+/* Called without the kernel lock - fine */
+static unsigned int rtc_poll(struct file *file, poll_table *wait)
+{
+       unsigned long l;
+
+       poll_wait(file, &rtc_wait, wait);
+
+       spin_lock_irq (&rtc_lock);
+       l = rtc_irq_data;
+       spin_unlock_irq (&rtc_lock);
+
+       if (l != 0)
+               return POLLIN | POLLRDNORM;
+       return 0;
+}
+
+/*
+ *     The various file operations we support.
+ */
+
+static struct file_operations rtc_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .read           = rtc_read,
+       .poll           = rtc_poll,
+       .ioctl          = rtc_ioctl,
+       .open           = rtc_open,
+       .release        = rtc_release,
+       .fasync         = rtc_fasync,
+};
+
+static struct miscdevice rtc_dev = {
+       .minor          = RTC_MINOR,
+       .name           = "rtc",
+       .fops           = &rtc_fops,
+};
+
+static int __init omap_rtc_probe(struct platform_device *pdev)
+{
+       struct resource         *res, *mem;
+
+       /* find the IRQs */
+
+       omap_rtc_timer = platform_get_irq(pdev, 0);
+       if (omap_rtc_timer <= 0) {
+               dev_err(&pdev->dev, "no irq for rtc timer\n");
+               return -ENOENT;
+       }
+
+       omap_rtc_alarm = platform_get_irq(pdev, 1);
+       if (omap_rtc_alarm <= 0) {
+               dev_err(&pdev->dev, "no irq for alarm\n");
+               return -ENOENT;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res)
+               mem = request_mem_region(res->start,
+                               res->end - res->start + 1,
+                               pdev->name);
+       else
+               mem = NULL;
+       if (!mem) {
+               pr_debug("%s: RTC registers at %x are not free.\n",
+                       pdev->name, OMAP_RTC_BASE);
+               return -EBUSY;
+       }
+       platform_set_drvdata(pdev, mem);
+
+       if (CMOS_READ(OMAP_RTC_STATUS_REG) & OMAP_RTC_STATUS_POWER_UP) {
+               pr_info("%s: RTC power up reset detected.\n",
+                       pdev->name);
+               /* Clear OMAP_RTC_STATUS_POWER_UP */
+               CMOS_WRITE(OMAP_RTC_STATUS_POWER_UP, OMAP_RTC_STATUS_REG);
+       }
+
+       if (CMOS_READ(OMAP_RTC_STATUS_REG) & OMAP_RTC_STATUS_ALARM) {
+               pr_debug("%s: Clearing RTC ALARM interrupt.\n",
+                       pdev->name);
+               /* Clear OMAP_RTC_STATUS_ALARM */
+               CMOS_WRITE(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG);
+       }
+
+       if (request_irq(omap_rtc_timer, rtc_interrupt, IRQF_DISABLED,
+                       pdev->name, NULL)) {
+               pr_debug("%s: RTC timer interrupt IRQ%d is not free.\n",
+                       pdev->name, omap_rtc_timer);
+               goto fail;
+       }
+
+       if (request_irq(omap_rtc_alarm, rtc_interrupt, IRQF_DISABLED,
+                       pdev->name, NULL)) {
+               pr_debug("%s: RTC alarm interrupt IRQ%d is not free.\n",
+                       pdev->name, omap_rtc_alarm);
+               free_irq(omap_rtc_timer, NULL);
+               goto fail;
+       }
+
+       /* On boards with split power, RTC_ON_NOFF resets all but the RTC */
+       if (!(CMOS_READ(OMAP_RTC_CTRL_REG) & OMAP_RTC_CTRL_STOP)) {
+               pr_info("%s: Enabling RTC.\n", pdev->name);
+               CMOS_WRITE(OMAP_RTC_CTRL_STOP, OMAP_RTC_CTRL_REG);
+       } else
+               pr_info("%s: RTC already running.\n", pdev->name);
+
+       spin_lock_init(&rtc_lock);
+       misc_register(&rtc_dev);
+       create_proc_read_entry("driver/rtc", 0, NULL, rtc_read_proc, NULL);
+
+       return 0;
+
+fail:
+       release_resource(mem);
+       return -EIO;
+}
+
+static int omap_rtc_remove(struct platform_device *pdev)
+{
+       free_irq (omap_rtc_timer, NULL);
+       free_irq (omap_rtc_alarm, NULL);
+
+       remove_proc_entry ("driver/rtc", NULL);
+       misc_deregister(&rtc_dev);
+
+       release_resource(platform_get_drvdata(pdev));
+       return 0;
+}
+
+/*
+ *     Info exported via "/proc/driver/rtc".
+ */
+
+static int rtc_proc_output (char *buf)
+{
+#define YN(value) ((value) ? "yes" : "no")
+       char *p;
+       struct rtc_time tm;
+
+       p = buf;
+
+       get_rtc_time(&tm);
+
+       /*
+        * There is no way to tell if the luser has the RTC set for local
+        * time or for Universal Standard Time (GMT). Probably local though.
+        */
+       p += sprintf(p,
+                    "rtc_time\t: %02d:%02d:%02d\n"
+                    "rtc_date\t: %04d-%02d-%02d\n"
+                    "rtc_epoch\t: %04lu\n",
+                    tm.tm_hour, tm.tm_min, tm.tm_sec,
+                    tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch);
+
+       get_rtc_alm_time(&tm);
+
+       /*
+        * We implicitly assume 24hr mode here. Alarm values >= 0xc0 will
+        * match any value for that particular field. Values that are
+        * greater than a valid time, but less than 0xc0 shouldn't appear.
+        */
+       p += sprintf(p,
+                    "alarm_time\t: %02d:%02d:%02d\n"
+                    "alarm_date\t: %04d-%02d-%02d\n",
+                    tm.tm_hour, tm.tm_min, tm.tm_sec,
+                    tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
+
+       p += sprintf(p,
+                    "BCD\t\t: %s\n"
+                    "24hr\t\t: %s\n"
+                    "alarm_IRQ\t: %s\n"
+                    "update_IRQ\t: %s\n"
+                    "update_rate\t: %ud\n",
+                    YN(1),
+                    YN(1),
+                    YN(CMOS_READ(OMAP_RTC_INTERRUPTS_REG) &
+                       OMAP_RTC_INTERRUPTS_IT_ALARM),
+                    YN(CMOS_READ(OMAP_RTC_INTERRUPTS_REG) &
+                       OMAP_RTC_INTERRUPTS_IT_TIMER),
+                    CMOS_READ(OMAP_RTC_INTERRUPTS_REG) & 3 /* REVISIT */);
+
+       return  p - buf;
+#undef YN
+}
+
+static int rtc_read_proc(char *page, char **start, off_t off,
+                         int count, int *eof, void *data)
+{
+        int len = rtc_proc_output (page);
+
+       if (len <= off+count)
+               *eof = 1;
+        *start = page + off;
+        len -= off;
+       if (len > count)
+               len = count;
+       if (len < 0)
+               len = 0;
+        return len;
+}
+
+/*
+ * Returns true if a clock update is in progress
+ */
+static inline unsigned char rtc_is_updating(void)
+{
+       unsigned char uip;
+
+       spin_lock_irq(&rtc_lock);
+       uip = (CMOS_READ(OMAP_RTC_STATUS_REG) & OMAP_RTC_STATUS_BUSY);
+       spin_unlock_irq(&rtc_lock);
+       return uip;
+}
+
+static void bcd2tm(struct rtc_time *tm)
+{
+       BCD_TO_BIN(tm->tm_sec);
+       BCD_TO_BIN(tm->tm_min);
+       BCD_TO_BIN(tm->tm_hour);
+       BCD_TO_BIN(tm->tm_mday);
+       BCD_TO_BIN(tm->tm_mon);
+       BCD_TO_BIN(tm->tm_year);
+
+       /*
+        * Account for differences between how the RTC uses the values
+        * and how they are defined in a struct rtc_time;
+        */
+       if ((tm->tm_year += (epoch - 1900)) <= 69)
+               tm->tm_year += 100;
+
+       tm->tm_mon--;
+}
+
+
+static void get_rtc_time(struct rtc_time *rtc_tm)
+{
+       unsigned char ctrl;
+
+       /* REVISIT: Fix this comment!!!
+        * read RTC once any update in progress is done. The update
+        * can take just over 2ms. We wait 10 to 20ms. There is no need to
+        * to poll-wait (up to 1s - eeccch) for the falling edge of OMAP_RTC_STATUS_BUSY.
+        * If you need to know *exactly* when a second has started, enable
+        * periodic update complete interrupts, (via ioctl) and then 
+        * immediately read /dev/rtc which will block until you get the IRQ.
+        * Once the read clears, read the RTC time (again via ioctl). Easy.
+        */
+
+#if    0 /* REVISIT: This need to do as the TRM says. */
+       unsigned long uip_watchdog = jiffies;
+       if (rtc_is_updating() != 0)
+               while (jiffies - uip_watchdog < 2*HZ/100) {
+                       barrier();
+                       cpu_relax();
+               }
+#endif
+
+       /*
+        * Only the values that we read from the RTC are set. We leave
+        * tm_wday, tm_yday and tm_isdst untouched. Even though the
+        * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
+        * by the RTC when initially set to a non-zero value.
+        */
+       spin_lock_irq(&rtc_lock);
+       rtc_tm->tm_sec = CMOS_READ(OMAP_RTC_SECONDS_REG);
+       rtc_tm->tm_min = CMOS_READ(OMAP_RTC_MINUTES_REG);
+       rtc_tm->tm_hour = CMOS_READ(OMAP_RTC_HOURS_REG);
+       rtc_tm->tm_mday = CMOS_READ(OMAP_RTC_DAYS_REG);
+       rtc_tm->tm_mon = CMOS_READ(OMAP_RTC_MONTHS_REG);
+       rtc_tm->tm_year = CMOS_READ(OMAP_RTC_YEARS_REG);
+       ctrl = CMOS_READ(OMAP_RTC_CTRL_REG);
+       spin_unlock_irq(&rtc_lock);
+
+       bcd2tm(rtc_tm);
+}
+
+static void get_rtc_alm_time(struct rtc_time *alm_tm)
+{
+       unsigned char ctrl;
+
+       spin_lock_irq(&rtc_lock);
+       alm_tm->tm_sec = CMOS_READ(OMAP_RTC_ALARM_SECONDS_REG);
+       alm_tm->tm_min = CMOS_READ(OMAP_RTC_ALARM_MINUTES_REG);
+       alm_tm->tm_hour = CMOS_READ(OMAP_RTC_ALARM_HOURS_REG);
+       alm_tm->tm_mday = CMOS_READ(OMAP_RTC_ALARM_DAYS_REG);
+       alm_tm->tm_mon = CMOS_READ(OMAP_RTC_ALARM_MONTHS_REG);
+       alm_tm->tm_year = CMOS_READ(OMAP_RTC_ALARM_YEARS_REG);
+       ctrl = CMOS_READ(OMAP_RTC_CTRL_REG);
+       spin_unlock_irq(&rtc_lock);
+
+       bcd2tm(alm_tm);
+}
+
+/*
+ * Used to disable/enable UIE and AIE interrupts.
+ */
+
+static void mask_rtc_irq_bit(unsigned char bit)
+{
+       unsigned char val;
+
+       spin_lock_irq(&rtc_lock);
+       val = CMOS_READ(OMAP_RTC_INTERRUPTS_REG);
+       val &=  ~bit;
+       CMOS_WRITE(val, OMAP_RTC_INTERRUPTS_REG);
+       rtc_irq_data = 0;
+       spin_unlock_irq(&rtc_lock);
+}
+
+static void set_rtc_irq_bit(unsigned char bit)
+{
+       unsigned char val;
+
+       spin_lock_irq(&rtc_lock);
+       val = CMOS_READ(OMAP_RTC_INTERRUPTS_REG);
+       val |= bit;
+       CMOS_WRITE(val, OMAP_RTC_INTERRUPTS_REG);
+       rtc_irq_data = 0;
+       spin_unlock_irq(&rtc_lock);
+}
+
+#ifdef CONFIG_PM
+static struct timespec rtc_delta;
+
+static int omap_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct rtc_time rtc_tm;
+       struct timespec time;
+
+       time.tv_nsec = 0;
+       get_rtc_time(&rtc_tm);
+       rtc_tm_to_time(&rtc_tm, &time.tv_sec);
+
+       save_time_delta(&rtc_delta, &time);
+
+       return 0;
+}
+
+static int omap_rtc_resume(struct platform_device *pdev)
+{
+       struct rtc_time rtc_tm;
+       struct timespec time;
+
+       time.tv_nsec = 0;
+       get_rtc_time(&rtc_tm);
+       rtc_tm_to_time(&rtc_tm, &time.tv_sec);
+
+       restore_time_delta(&rtc_delta, &time);
+
+       return 0;
+}
+#else
+#define omap_rtc_suspend NULL
+#define omap_rtc_resume  NULL
+#endif
+
+static struct platform_driver omap_rtc_driver = {
+       .probe          = omap_rtc_probe,
+       .remove         = omap_rtc_remove,
+       .suspend        = omap_rtc_suspend,
+       .resume         = omap_rtc_resume,
+       .driver         = {
+               .name   = "omap_rtc",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static char __initdata banner[] = KERN_INFO "OMAP RTC Driver\n";
+
+static int __init rtc_init(void)
+{
+       printk(banner);
+       return platform_driver_register(&omap_rtc_driver);
+}
+
+static void __exit rtc_exit(void)
+{
+       platform_driver_unregister(&omap_rtc_driver);
+}
+
+module_init(rtc_init);
+module_exit(rtc_exit);
+
+MODULE_AUTHOR("George G. Davis (and others)");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(RTC_MINOR);
diff --git a/drivers/char/omap-rtc.h b/drivers/char/omap-rtc.h
new file mode 100644 (file)
index 0000000..d8acb56
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ *  TI OMAP Real Time Clock header file
+ *
+ *  Copyright (C) 2003 TI
+ *
+ *  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.
+ *
+ */
+
+#define OMAP_RTC_BASE                  0xfffb4800
+#define OMAP_RTC_SIZE                  128
+
+#define OMAP_RTC_VIRT_BASE             IO_ADDRESS(OMAP_RTC_BASE)
+
+/*
+ * Real-Time Clock
+ */
+
+#define OMAP_RTC_SECONDS_REG            (OMAP_RTC_BASE + 0x00)
+#define OMAP_RTC_MINUTES_REG            (OMAP_RTC_BASE + 0x04)
+#define OMAP_RTC_HOURS_REG              (OMAP_RTC_BASE + 0x08)
+#define OMAP_RTC_DAYS_REG               (OMAP_RTC_BASE + 0x0C)
+#define OMAP_RTC_MONTHS_REG             (OMAP_RTC_BASE + 0x10)
+#define OMAP_RTC_YEARS_REG              (OMAP_RTC_BASE + 0x14)
+#define OMAP_RTC_WEEKS_REG              (OMAP_RTC_BASE + 0x18)
+#define OMAP_RTC_ALARM_SECONDS_REG      (OMAP_RTC_BASE + 0x20)
+#define OMAP_RTC_ALARM_MINUTES_REG      (OMAP_RTC_BASE + 0x24)
+#define OMAP_RTC_ALARM_HOURS_REG        (OMAP_RTC_BASE + 0x28)
+#define OMAP_RTC_ALARM_DAYS_REG         (OMAP_RTC_BASE + 0x2c)
+#define OMAP_RTC_ALARM_MONTHS_REG       (OMAP_RTC_BASE + 0x30)
+#define OMAP_RTC_ALARM_YEARS_REG        (OMAP_RTC_BASE + 0x34)
+#define OMAP_RTC_CTRL_REG               (OMAP_RTC_BASE + 0x40)
+#define OMAP_RTC_STATUS_REG             (OMAP_RTC_BASE + 0x44)
+#define OMAP_RTC_INTERRUPTS_REG         (OMAP_RTC_BASE + 0x48)
+#define OMAP_RTC_COMP_LSB_REG           (OMAP_RTC_BASE + 0x4c)
+#define OMAP_RTC_COMP_MSB_REG           (OMAP_RTC_BASE + 0x50)
+
+/* RTC Control Register bit fields: */
+
+#define OMAP_RTC_CTRL_STOP              (1<<0)
+
+/* RTC Status Register bit fields: */
+
+#define OMAP_RTC_STATUS_POWER_UP        (1<<7)
+#define OMAP_RTC_STATUS_ALARM           (1<<6)
+#define OMAP_RTC_STATUS_1D_EVENT        (1<<5)
+#define OMAP_RTC_STATUS_1H_EVENT        (1<<4)
+#define OMAP_RTC_STATUS_1M_EVENT        (1<<3)
+#define OMAP_RTC_STATUS_1S_EVENT        (1<<2)
+#define OMAP_RTC_STATUS_RUN             (1<<1)
+#define OMAP_RTC_STATUS_BUSY            (1<<0)
+
+/* RTC Interrupt Register bit fields: */
+
+#define OMAP_RTC_INTERRUPTS_IT_ALARM    (1<<3)
+#define OMAP_RTC_INTERRUPTS_IT_TIMER    (1<<2)
index 2cd8ff8d10ac839b1e251c51225521dd89d76ef3..b15f99e83bd13368d1d417c90943a498f7d3844d 100644 (file)
@@ -29,6 +29,7 @@ obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
 obj-$(CONFIG_977_WATCHDOG) += wdt977.o
 obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
 obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
+obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
 obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
 obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
 obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
index 106fa01cdb6069717c61ee6a596e94d1ad38bf98..affcc00764d3d207cf2225240802a5255b2a7d9c 100644 (file)
@@ -101,7 +101,7 @@ static void __exit hwmon_exit(void)
        class_destroy(hwmon_class);
 }
 
-module_init(hwmon_init);
+subsys_initcall(hwmon_init);
 module_exit(hwmon_exit);
 
 EXPORT_SYMBOL_GPL(hwmon_device_register);
index 049f2f544e75e94a9d40aee991df4cf8d45510f4..d3e5f7f74648d09d13585ca361dfb25390f8468e 100644 (file)
@@ -203,6 +203,16 @@ config KEYBOARD_OMAP
          To compile this driver as a module, choose M here: the
          module will be called omap-keypad.
 
+config OMAP_PS2
+       tristate "TI OMAP Innovator 1510 PS/2 keyboard & mouse support"
+       depends on ARCH_OMAP15XX && MACH_OMAP_INNOVATOR
+       help
+         Say Y here if you want to use the OMAP Innovator 1510 PS/2
+         keyboard and mouse.
+
+         To compile this driver as a module, choose M here: the
+         module will be called innovator_ps2.
+
 config KEYBOARD_AAED2000
        tristate "AAED-2000 keyboard"
        depends on MACH_AAED2000
index 568797907347b9e0ace4898ab425e8a9ba16683d..8b5429d8366e6231eac4575ab3ec2f216620c9ec 100644 (file)
@@ -17,5 +17,6 @@ obj-$(CONFIG_KEYBOARD_SPITZ)          += spitzkbd.o
 obj-$(CONFIG_KEYBOARD_HIL)             += hil_kbd.o
 obj-$(CONFIG_KEYBOARD_HIL_OLD)         += hilkbd.o
 obj-$(CONFIG_KEYBOARD_OMAP)             += omap-keypad.o
+obj-$(CONFIG_OMAP_PS2)                 += innovator_ps2.o
 obj-$(CONFIG_KEYBOARD_AAED2000)         += aaed2000_kbd.o
 
diff --git a/drivers/input/keyboard/innovator_ps2.c b/drivers/input/keyboard/innovator_ps2.c
new file mode 100644 (file)
index 0000000..0f95f9f
--- /dev/null
@@ -0,0 +1,1280 @@
+/*
+ * drivers/char/innovator_ps2.c
+ *
+ * Basic PS/2 keyboard/mouse driver for the Juno® USAR HID controller
+ * present on the TI Innovator/OMAP1510 Break-out-board.
+ *
+ *
+ * Author: MontaVista Software, Inc.
+ *         <gdavis@mvista.com> or <source@mvista.com>
+ *
+ *
+ * 2003 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ *
+ * REFERENCES:
+ *
+ * 1.  Technical Reference Manual
+ *     Juno® 01
+ *     Multi-function ICs family
+ *     UR8HC007-001 HID & Power management controller
+ *     Document Number: DOC8-007-001-TR-075
+ *     Date: February 2002
+ *     Copyright Â©1998-2002 Semtech Corporation
+ *     http://www.semtech.com/pdf/doc8-007-001-tr.pdf
+ *
+ * 2.  Juno® 01 UR8HC007-001 Data Sheet
+ *     Extremely Low-power Input Device and Power Management IC
+ *     Copyright Â©1998-2002 Semtech Corporation
+ *     DOC8-007-001-DS-112
+ *     http://www.semtech.com/pdf/doc8-007-001-ds.pdf
+ *
+ *
+ * HISTORY:
+ *
+ * 20030626: George G. Davis <gdavis@mvista.com>
+ *      Initially based on the following RidgeRun DSPlinux Version 1.6 files:
+ *             linux-2.4.15-rmk1-dsplinux/arch/arm/dsplinux/hid/omap1510_hid.c
+ *             linux-2.4.15-rmk1-dsplinux/arch/arm/dsplinux/hid/omap1510_hid.h
+ *             linux-2.4.15-rmk1-dsplinux/arch/arm/dsplinux/hid/omap1510_ps2.c
+ *             linux-2.4.15-rmk1-dsplinux/arch/arm/dsplinux/hid/omap1510_spi.c
+ *     All original files above are
+ *             Copyright (C) 2001 RidgeRun, Inc.
+ *             Author: Alex McMains <aam@ridgerun.com>
+ *
+ * 20040812: Thiago Radicchi <trr@dcc.ufmg.br>
+ *      Cleanup of old code from 2.4 driver and some debug code.
+ *      Minor changes in interrupt handling code.
+ *
+ * NOTES:
+ *
+ * 1. This driver does not provide support for setting keyboard/mouse
+ *    configuration parameters. Both devices are managed directly by
+ *    the Juno UR8HC007-001 on behalf of the host. This minimises the
+ *    amount of host processing required to manage HID events and state
+ *    changes, e.g. both keyboard and mouse devices are hot pluggable
+ *    with no host intervention required. However, we cannot customise
+ *    keyboard/mouse settings in this case. So we live with the defaults
+ *    as setup by the Juno UR8HC007-001 whatever they may be.
+ * 2. Keyboard auto repeat does not work. See 1 above. : )
+ *
+ *
+ * TODO:
+ *
+ * 1. Complete DPM/LDM stubs and test.
+ * 2. Add SPI error handling support, i.e. resend, etc.,.
+ * 3. Determine why innovator_hid_interrupt() is called for every
+ *    invocation of Innovator FPGA IRQ demux. It appears that the
+ *    missed Innovator ethernet workaround may be to blame. However,
+ *    it does not adversely affect operation of this driver since we
+ *    check for assertion of ATN prior to servicing the interrupt. If
+ *    ATN is negated, we bug out right away.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/stddef.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/arch/fpga.h>
+
+#undef INNOVATOR_KEYB_DEBUG
+#ifdef INNOVATOR_KEYB_DEBUG
+#define        dbg(format, arg...) printk(KERN_DEBUG "%s:%d: " format , \
+                                  __FUNCTION__ , __LINE__ , ## arg)
+#define        entry() printk(KERN_DEBUG "%s:%d: Entry\n" , __FUNCTION__ , __LINE__)
+#define        exit()  printk(KERN_DEBUG "%s:%d: Exit\n" , __FUNCTION__ , __LINE__)
+#define dump_packet(p, n)                                      \
+       {                                                       \
+               int i;                                          \
+               printk(KERN_DEBUG "%s:%d: %08x:" ,              \
+                      __FUNCTION__ , __LINE__ , (int) p);      \
+               for (i = 0; i < n; i += 1) {                    \
+                       printk(" %02x", (int) p[i]);            \
+               }                                               \
+               printk("\n");                                   \
+       }
+#else
+#define        dbg(format, arg...) do {} while (0)
+#define        entry() do {} while (0)
+#define        exit()  do {} while (0)
+#define dump_packet(p, n) do {} while (0)
+#endif
+
+
+#define        PFX     "innovator_ps2"
+#define err(format, arg...)    printk(KERN_ERR PFX ": " format , ## arg)
+#define info(format, arg...)   printk(KERN_INFO PFX ": " format , ## arg)
+#define warn(format, arg...)   printk(KERN_WARNING PFX ": " format , ## arg)
+
+
+/****************************************************************************/
+
+/*
+ * Synchronous communications timing parameters (Reference [1] pg 7-7)
+ */
+
+#define tMSA   5000    /* -/5ms        _SS to _ATN (master transfer) */
+#define tMAC   100     /* 100us/5ms    _ATN to first clock pulse (master
+                                       transfer) */
+#define tMIB   150     /* 150us/5ms    Beginning of byte transfer to beginning
+                                       of next byte transfer */
+#define tSIB   150     /* 150us/5ms    Beginning of byte transfer to beginning
+                                       of next byte transfer */
+#define tMSP   100     /* -/100us      Last clock pulse of packet to _SS
+                                       de-assertion */
+#define tMNSA  100     /* -/100us      _SS de-assertion to _ATN de-assertion */
+#define tMNEXT 120     /* 120uS/-      _ATN release to _SS re-assertion
+                                       (master transfer) */
+#define        tSAS    5000    /* -/5ms        _ATN to _SS (slave transfer) */
+#define tSSC   100     /* 100us/5ms    _SS to first clock pulse (slave
+                                       transfer) */
+#define tSNA   100     /* -/100us      Last clock pulse of packet to _ATN
+                                       de-assertion */
+#define tSNAS  100     /* -/100us      _ATN release to _SS de-assertion */
+#define tSNEXT 120     /* 120us/-      _SS release to _ATN re-assertion
+                                       (slave transfer) */
+#define tSCK   4       /* 4us/-        Clock period */
+#define tSLOW  2       /* 2us/-        Clock LOW period */
+#define tHOLD  200     /* 200ns/-      Master data hold time */
+#define tSETUP 100     /* 100ns/-      Master data setup Time */
+#define tSSETUP        500     /* -/500ns      Slave data setup time from clock
+                                       falling edge */
+
+
+/*
+ * Protocol Headers (Reference [1], pg. 5-1):
+ */
+
+
+/* Protocols used in commands issued by the host: */
+#define SIMPLE                 0x80    /* Simple commands
+                                        * Common for both host and controller
+                                        * protocol headers.
+                                        */
+#define WRITE_REGISTER_BIT     0x81    /* Write register bit */
+#define READ_REGISTER_BIT      0x82    /* Read register bit */
+#define WRITE_REGISTER         0x83    /* Write register */
+#define READ_REGISTER          0x84    /* Read register */
+#define WRITE_BLOCK            0x85    /* Write block */
+#define READ_BLOCK             0x86    /* Read block */
+
+
+/* Protocols used in responses, reports and alerts issued by the controller: */
+#define REPORT_REGISTER_BIT    0x81    /* Report register bit & event alerts */
+#define REPORT_REGISTER                0x83    /* Report register */
+#define REPORT_BLOCK           0x85    /* Report block */
+#define POINTING_REPORT                0x87    /* Pointing device data report */
+#define KEYBOARD_REPORT                0x88    /* Keyboard device data report */
+
+
+/* Simple Commands (Reference [1], pg 5-3): */
+#define INITIALIZE             0x00    /* Forces the recipient to enter the
+                                        * known default power-on state.
+                                        */
+#define INITIALIZATION_COMPLETE        0x01    /* Issued as a hand-shake response only
+                                        * to the "Initialize" command.
+                                        */
+#define RESEND_REQUEST         0x05    /* Issued upon error in the reception
+                                        * of a package. The recipient resends
+                                        * the last transmitted packet.
+                                        */
+
+/* Register offsets (Reference [1], pg 6-1 thru 6-9): */
+
+#define REG_PM_COMM            0
+#define REG_PM_STATUS          1
+#define REG_PAGENO             255
+
+/* Power management bits ((Reference [1], pg 6-10): */
+
+#define SUS_STATE              0x2     /* in REG_PM_COMM */
+
+/* Miscellaneous constants: */
+
+#define X_MSB_SHIFT    (8-4)
+#define X_MSB_MASK     (3<<4)
+#define Y_MSB_SHIFT    (8-6)
+#define Y_MSB_MASK     (3<<6)
+
+
+#define JUNO_BLOCK_SIZE     32
+#define JUNO_BUFFER_SIZE    256
+
+
+/*
+ * Errors:
+ */
+
+#define E_BAD_HEADER   1
+#define E_BAD_LRC      2
+#define E_ZERO_BYTES   3
+#define E_BAD_VALUE    4
+#define E_BAD_MODE     5
+#define E_REPORT_MODE  6
+#define E_BAD_ACK      7
+#define E_BAD_DEVICE_ID        8
+#define E_PKT_SZ       9
+
+
+/*
+ * Host/Controller Command/Response Formats:
+ */
+
+typedef struct _simple_t {
+       u8 header;
+       u8 cmd_code;
+       u8 LRC;
+} __attribute__ ((packed)) simple_t;
+
+typedef struct _write_bit_t {
+       u8 header;
+       u8 offset;
+       u8 value_bit;
+       u8 LRC;
+} __attribute__ ((packed)) write_bit_t;
+
+typedef struct _read_bit_t {
+       u8 header;
+       u8 offset;
+       u8 bit;
+       u8 LRC;
+} __attribute__ ((packed)) read_bit_t;
+
+typedef struct _write_reg_t {
+       u8 header;
+       u8 offset;
+       u8 value;
+       u8 LRC;
+} __attribute__ ((packed)) write_reg_t;
+
+typedef struct _read_reg_t {
+       u8 header;
+       u8 offset;
+       u8 LRC;
+} __attribute__ ((packed)) read_reg_t;
+
+typedef struct _write_block_t {
+       u8 header;
+       u8 offset;
+       u8 length;
+       u8 block[JUNO_BLOCK_SIZE + 1]; /* Hack: LRC is last element of block[] */
+} __attribute__ ((packed)) write_block_t;
+
+typedef struct _read_block_t {
+       u8 header;
+       u8 offset;
+       u8 length;
+       u8 LRC;
+} __attribute__ ((packed)) read_block_t;
+
+typedef struct _report_bit_t {
+       u8 header;
+       u8 offset;
+       u8 value_bit;
+       u8 LRC;
+} __attribute__ ((packed)) report_bit_t;
+
+typedef struct _report_reg_t {
+       u8 header;
+       u8 offset;
+       u8 value;
+       u8 LRC;
+} __attribute__ ((packed)) report_reg_t;
+
+typedef struct _report_block_t {
+       u8 header;
+       u8 offset;
+       u8 length;
+       u8 block[32];
+       u8 LRC;
+} __attribute__ ((packed)) report_block_t;
+
+typedef struct _mse_report_t {
+       u8 header;
+       u8 buttons;
+       u8 Xdisplacement;
+       u8 Ydisplacement;
+       u8 Zdisplacement;
+       u8 LRC;
+} __attribute__ ((packed)) mse_report_t;
+
+typedef struct _kdb_report_t {
+       u8 header;
+       u8 keynum;              /* up > 0x80, down < 0x7E, all keys up 0x00 */
+       u8 LRC;
+} __attribute__ ((packed)) kdb_report_t;
+
+
+static u8 buffer[JUNO_BUFFER_SIZE];
+
+static void do_hid_tasklet(unsigned long);
+DECLARE_TASKLET(hid_tasklet, do_hid_tasklet, 0);
+static struct innovator_hid_dev *hid;
+
+struct innovator_hid_dev {
+       struct input_dev *mouse, *keyboard;
+       int open;
+       int irq_enabled;
+};
+
+/****************************************************************************/
+
+/*
+ * Low-level TI Innovator/OMAP1510 FPGA HID SPI interface helper functions:
+ */
+
+static u8
+innovator_fpga_hid_rd(void)
+{
+       u8 val = inb(INNOVATOR_FPGA_HID_SPI);
+       return val;
+}
+
+static void
+innovator_fpga_hid_wr(u8 val)
+{
+       outb(val, INNOVATOR_FPGA_HID_SPI);
+}
+
+static void
+innovator_fpga_hid_frob(u8 mask, u8 val)
+{
+       unsigned long flags;
+       local_irq_save(flags);
+       innovator_fpga_hid_wr((innovator_fpga_hid_rd() & ~mask) | val);
+       local_irq_restore(flags);
+}
+
+static void
+innovator_fpga_hid_set_bits(u8 x)
+{
+       innovator_fpga_hid_frob(x, x);
+}
+
+static void
+SS(int value)
+{
+       innovator_fpga_hid_frob(OMAP1510_FPGA_HID_nSS, value ? OMAP1510_FPGA_HID_nSS : 0);
+}
+
+static void
+SCLK(int value)
+{
+       innovator_fpga_hid_frob(OMAP1510_FPGA_HID_SCLK, value ? OMAP1510_FPGA_HID_SCLK : 0);
+}
+
+static void
+MOSI(int value)
+{
+       innovator_fpga_hid_frob(OMAP1510_FPGA_HID_MOSI, value ? OMAP1510_FPGA_HID_MOSI : 0);
+}
+
+static u8
+MISO(void)
+{
+       return ((innovator_fpga_hid_rd() & OMAP1510_FPGA_HID_MISO) ? 1 : 0);
+}
+
+static u8 
+ATN(void)
+{
+       return ((innovator_fpga_hid_rd() & OMAP1510_FPGA_HID_ATN) ? 1 : 0);
+}
+
+static int
+wait_for_ATN(int assert, int timeout)
+{
+       do {
+               if (ATN() == assert)
+                       return 0;
+               udelay(1);
+       } while (timeout -= 1);
+       return -1;
+}
+
+static u8
+innovator_fpga_hid_xfer_byte(u8 xbyte)
+{
+       int i;
+       u8 rbyte;
+
+       for (rbyte = 0, i = 7; i >= 0; i -= 1) {
+               SCLK(0);
+               MOSI((xbyte >> i) & 1);
+               udelay(tSLOW);
+               SCLK(1);
+               rbyte = (rbyte << 1) | MISO();
+               udelay(tSLOW);
+       }
+
+       return rbyte;
+}
+
+static void
+innovator_fpga_hid_reset(void)
+{
+       innovator_fpga_hid_wr(OMAP1510_FPGA_HID_SCLK | OMAP1510_FPGA_HID_MOSI);
+       mdelay(1);
+       innovator_fpga_hid_set_bits(OMAP1510_FPGA_HID_RESETn);
+}
+
+
+/*****************************************************************************
+
+  Refer to Reference [1], Chapter 7 / Low-level communications, Serial
+  Peripheral Interface (SPI) implementation Host (master) packet
+  transmission timing, pg. 7-3, for timing and implementation details
+  for spi_xmt().
+
+ *****************************************************************************/
+
+int
+spi_xmt(u8 * p, u8 n)
+{
+       unsigned long flags;
+
+       dump_packet(p, n);
+       local_irq_save(flags);
+       disable_irq(OMAP1510_INT_FPGA_ATN);
+
+       if (ATN()) {
+               /* Oops, we have a collision. */
+               enable_irq(OMAP1510_INT_FPGA_ATN);
+               local_irq_restore(flags);
+               dbg("Protocol error: ATN is asserted\n");
+               return -EAGAIN;
+       }
+
+       SS(1);
+
+       if (wait_for_ATN(1, tMSA) < 0) {
+               SS(0);
+               enable_irq(OMAP1510_INT_FPGA_ATN);
+               local_irq_restore(flags);
+               dbg("timeout waiting for ATN assertion\n");
+               return -EREMOTEIO;
+       }
+
+       udelay(tMAC);
+
+       while (n--) {
+               innovator_fpga_hid_xfer_byte(*p++);
+               if (n) {
+                       udelay(tMIB - 8 * tSCK);
+               }
+       }
+
+       MOSI(1);        /* Set MOSI to idle high. */
+
+       /* NOTE: The data sheet does not specify a minimum delay
+        * here. But innovator_fpga_hid_xfer_byte() gives us a half-clock
+        * delay (tSLOW) after the last bit is sent. So I'm happy with
+        * that.
+        */
+
+       SS(0);
+
+       if (wait_for_ATN(0, tMNSA) < 0) {
+               enable_irq(OMAP1510_INT_FPGA_ATN);
+               local_irq_restore(flags);
+               dbg("timeout waiting for ATN negation\n");
+               return -EREMOTEIO;
+       }
+
+       udelay(tMNEXT);
+       enable_irq(OMAP1510_INT_FPGA_ATN);
+       local_irq_restore(flags);
+       return 0;
+}
+
+
+/*****************************************************************************
+
+  Refer to Reference [1],  Chapter 7 / Low-level communications, Serial
+  Peripheral Interface (SPI) implementation, Slave packet transmission
+  timing, pg. 7-5, for timing and implementation details for spi_rcv().
+
+ *****************************************************************************/
+
+int
+spi_rcv(u8 * p, int len)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       if (len > 256) {
+               /* Limit packet size to something reasonable */
+               return -1;
+       }
+
+       local_irq_save(flags);
+
+       if (wait_for_ATN(1, tMSA) < 0) {
+               local_irq_restore(flags);
+               dbg("Protocol error: ATN is not asserted\n");
+               return -EREMOTEIO;
+       }
+
+       SS(1);
+
+       udelay(tSSC);
+
+       while (ATN()) {
+               if (ret >= len) {
+                       err("over run error\n");
+                       ret = -1;
+                       break;
+               }
+               p[ret++] = innovator_fpga_hid_xfer_byte(0xff);
+               udelay(tSNA);   /* Wait long enough to detect negation of ATN
+                                * after last clock pulse of packet.
+                                *
+                                * NOTE: Normally, we need a minimum delay of
+                                *       tSIB between the start of one byte
+                                *       and the start of the next. However,
+                                *       we also need to wait long enough
+                                *       for the USAR to negate ATN before
+                                *       starting the next byte. So we use
+                                *       max(tSIB - 8 * tSCK, tSNA) here to
+                                *       satisfy both constraints.
+                                */
+       }
+
+       SS(0);  /* NOTE: The data sheet does not specify a minimum delay
+                * here. But innovator_fpga_hid_xfer_byte() gives us a
+                * half-clock delay (tSLOW) after the last bit is sent. So
+                * I'm happy with that (rather than no delay at all : ).
+                */
+
+
+       udelay(tSNEXT); /* This isn't quite right. Assertion of ATN after
+                        * negation of SS is an USAR timing constraint.
+                        * What we need here is a spec for the minimum
+                        * delay from SS negation to SS assertion. But
+                        * for now, just use this brain dead delay.
+                        */
+
+       local_irq_restore(flags);
+
+       if (ret > 0) {
+               dump_packet(p, ret);
+       }
+
+       return ret;
+}
+
+
+/*****************************************************************************
+  Calculate Host/Controller Command/Response Longitudinal Redundancy Check (LRC)
+
+  The algorithm implemented in calculate_LRC() below is taken directly from
+  the reference [1], Chapter 7 / Low-level communications, LRC (Longitudinal
+  Redundancy Check), pg 5-10.
+
+ *****************************************************************************/
+
+static u8
+calculate_LRC(u8 * p, int n)
+{
+       u8 LRC;
+       int i;
+
+       /*
+        * Init the LRC using the first two message bytes.
+        */
+       LRC = p[0] ^ p[1];
+
+       /*
+        * Update the LRC using the remainder of the p.
+        */
+       for (i = 2; i < n; i++)
+               LRC ^= p[i];
+
+       /*
+        * If the MSB is set then clear the MSB and change the next
+        * most significant bit
+        */
+       if (LRC & 0x80)
+               LRC ^= 0xC0;
+
+       return LRC;
+}
+
+
+/*
+ * Controller response helper functions:
+ */
+
+static inline int
+report_mouse(mse_report_t * p, int n)
+{
+       if (p->header != POINTING_REPORT)
+               return -E_BAD_HEADER;
+
+       if (n != sizeof(mse_report_t))
+               return -E_PKT_SZ;
+
+       return (p->LRC != calculate_LRC((u8 *) p, sizeof(mse_report_t) - 1)) ?
+               -E_BAD_LRC : POINTING_REPORT;
+}
+
+static inline int
+report_keyboard(kdb_report_t * p, int n)
+{
+       if (p->header != KEYBOARD_REPORT)
+               return -E_BAD_HEADER;
+
+       if (n != sizeof(kdb_report_t))
+               return -E_PKT_SZ;
+
+       return (p->LRC != calculate_LRC((u8 *) p, sizeof(kdb_report_t) - 1)) ?
+               -E_BAD_LRC : KEYBOARD_REPORT;
+}
+
+
+/*
+ * Miscellaneous helper functions:
+ */
+
+static inline int
+report_type(u8 * type)
+{
+       /* check the header to find out what kind of report it is */
+       if ((*type) == KEYBOARD_REPORT)
+               return KEYBOARD_REPORT;
+       else if ((*type) == POINTING_REPORT)
+               return POINTING_REPORT;
+       else
+               return -E_BAD_HEADER;
+}
+
+static inline int
+report_async(void * p, int n)
+{
+       int ret;
+
+       if ((ret = spi_rcv((u8 *) p, n)) < 0)
+               return ret;
+
+       if (report_type((u8 *) p) == POINTING_REPORT)
+               ret = report_mouse((mse_report_t *) p, ret);
+       else if (report_type((u8 *) p) == KEYBOARD_REPORT)
+               ret = report_keyboard((kdb_report_t *) p, ret);
+
+       return ret;
+}
+
+/*
+ * Host command helper functions:
+ */
+
+#if    0
+/* REVISIT/TODO: Wrapper for command/response with resend handing. */
+static int
+spi_xfer(u8 * optr, u8 osz, u8 * iptr, u8 isz)
+{
+       static u8 buf[256];
+       int ret;
+       int xretries = 3;
+
+       do {
+               if (optr != NULL && osz) {
+                       do {
+                               ret = spi_xmt((u8 *) optr, osz);
+                       } while (ret < 0);
+               }
+
+               ret = spi_rcv((u8 *) buf, 256);
+
+               if (ret == -EREMOTEIO) {
+                       if (iptr == NULL) {
+                               break;
+                       }
+               }
+       } while (xretries--);
+
+       return ret;
+}
+#endif
+
+/* REVISIT: Enable these when/if additional Juno features are required. */
+static inline int
+simple(u8 cmd)
+{
+       static simple_t p;
+       int ret;
+
+       p.header = SIMPLE;
+       p.cmd_code = cmd;
+       p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1);
+
+       if ((ret = spi_xmt((u8 *) & p, sizeof(p))) < 0)
+               return ret;
+
+       if ((ret = spi_rcv((u8 *) & p, sizeof(p))) < 0)
+               return ret;
+
+       if (ret == 0)
+               return -E_ZERO_BYTES;
+
+       if (ret != sizeof(p))
+               return -E_PKT_SZ;
+
+       if (p.header != SIMPLE)
+               return -E_BAD_HEADER;
+
+       if (p.LRC != calculate_LRC((u8 *) & p, sizeof(p) - 1))
+               return -E_BAD_LRC;
+
+       /* REVISIT: Need to check or return response code here? */
+}
+
+static inline int
+write_bit(u8 offset, u8 bit, u8 value)
+{
+       static write_bit_t p;
+
+       p.header = WRITE_REGISTER_BIT;
+       p.offset = offset;
+       p.value_bit = (bit << 1) | (value & 1);
+       p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1);
+
+       return spi_xmt((u8 *) & p, sizeof(p));
+}
+
+static inline int
+read_bit(u8 offset, u8 bit, u8 * data)
+{
+       static read_bit_t p;
+       static report_bit_t q;
+       int ret;
+
+       p.header = READ_REGISTER_BIT;
+       p.offset = offset;
+       p.bit = bit;
+       p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1);
+
+       if ((ret = spi_xmt((u8 *) & p, sizeof(p))) < 0)
+               return ret;
+
+       if ((ret = spi_rcv((u8 *) & q, sizeof(q))) < 0)
+               return ret;
+
+       if (ret == 0)
+               return -E_ZERO_BYTES;
+
+       if (ret != sizeof(q))
+               return -E_PKT_SZ;
+
+       if (q.header != REPORT_REGISTER_BIT)
+               return -E_BAD_HEADER;
+
+       if (q.LRC != calculate_LRC((u8 *) & q, sizeof(q) - 1))
+               return -E_BAD_LRC;
+
+       *data = q.value_bit;
+
+       return 0;
+}
+
+static inline int
+write_reg(u8 offset, u8 value)
+{
+       static write_reg_t p;
+
+       p.header = WRITE_REGISTER;
+       p.offset = offset;
+       p.value = value;
+       p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1);
+
+       return spi_xmt((u8 *) & p, sizeof(p));
+}
+
+static inline int
+read_reg(u8 offset, u8 * data)
+{
+       static read_reg_t p;
+       static report_reg_t q;
+       int ret;
+
+       p.header = READ_REGISTER;
+       p.offset = offset;
+       p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1);
+
+       if ((ret = spi_xmt((u8 *) & p, sizeof(p))) < 0)
+               return ret;
+
+       if ((ret = spi_rcv((u8 *) & q, sizeof(q))) < 0)
+               return ret;
+
+       if (ret == 0)
+               return -E_ZERO_BYTES;
+
+       if (ret != sizeof(q))
+               return -E_PKT_SZ;
+
+       if (q.header != REPORT_REGISTER)
+               return -E_BAD_HEADER;
+
+       if (q.LRC != calculate_LRC((u8 *) & q, sizeof(q) - 1))
+               return -E_BAD_LRC;
+
+       *data = q.value;
+
+       return 0;
+}
+
+static inline int
+write_block(u8 offset, u8 length, u8 * block)
+{
+       static write_block_t p;
+
+       p.header = WRITE_BLOCK;
+       p.offset = offset;
+       p.length = length;
+       memcpy(&p.block, block, length);
+       p.block[length] = calculate_LRC((u8 *) & p, 3 + length);
+
+       return spi_xmt((u8 *) & p, 4 + length);
+}
+
+static inline int
+read_block(u8 offset, u8 length, u8 * buf)
+{
+       static read_block_t p;
+       static report_block_t q;
+       int ret;
+
+       p.header = READ_BLOCK;
+       p.offset = offset;
+       p.length = length;
+       p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1);
+
+       if ((ret = spi_xmt((u8 *) & p, sizeof(p))) < 0)
+               return ret;
+
+       if ((ret = spi_rcv((u8 *) & q, sizeof(q))) < 0)
+               return ret;
+
+       if (ret == 0)
+               return -E_ZERO_BYTES;
+
+       if (ret != sizeof(4 + q.length))
+               return -E_PKT_SZ;
+
+       if (q.header != REPORT_BLOCK)
+               return -E_BAD_HEADER;
+
+       if (q.block[q.length] != calculate_LRC((u8 *) & q, 3 + q.length))
+               return -E_BAD_LRC;
+
+       if (length != q.length)
+               return -E_PKT_SZ;
+
+       memcpy(buf, &q.block, length);
+
+       return 0;
+}
+
+#ifdef INNOVATOR_KEYB_DEBUG
+static void
+ctrl_dump_regs(void)
+{
+       int i;
+       int n;
+
+       for (i = 0; i < 256; i += 8) {
+               read_block(i, 16, buffer);
+               mdelay(1);
+       }
+}
+#endif
+
+/*****************************************************************************/
+
+static void
+process_pointing_report(struct innovator_hid_dev *hid, u8 * buffer)
+{
+       static int prev_x, prev_y, prev_btn;
+       int x, y, btn;
+       hid->keyboard = input_allocate_device();
+       hid->mouse = input_allocate_device();
+
+       if (buffer[1] & (1 << 3)) {
+               /* relative pointing device report */
+               x = buffer[2];
+               y = buffer[3];
+
+               /* check the sign and convert from 2's complement if negative */
+               if (buffer[1] & (1<<4))
+                       x = ~(-x) - 255;
+
+               /* input driver wants -y */
+               if (buffer[1] & (1<<5))
+                       y = -(~(-y) - 255);
+               else
+                       y = -y;
+
+               input_report_key(hid->mouse,
+                                BTN_LEFT, buffer[1] & (1<<0));
+               input_report_key(hid->mouse,
+                                BTN_RIGHT, buffer[1] & (1<<1));
+               input_report_key(hid->mouse,
+                                BTN_MIDDLE, buffer[1] & (1<<2));
+               input_report_rel(hid->mouse, REL_X, x);
+               input_report_rel(hid->mouse, REL_Y, y);
+       } else {
+               /* REVISIT: Does this work? */
+               /* absolute pointing device report */
+               x = buffer[2] + ((buffer[1] & X_MSB_MASK) << X_MSB_SHIFT);
+               y = buffer[3] + ((buffer[1] & Y_MSB_MASK) << Y_MSB_SHIFT);
+               btn = buffer[1] & (1<<0);
+
+               if ((prev_x == x) && (prev_y == y)
+                   && (prev_btn == btn))
+                       return;
+
+               input_report_key(hid->mouse, BTN_LEFT, btn);
+               input_report_abs(hid->mouse, ABS_X, x);
+               input_report_abs(hid->mouse, ABS_Y, y);
+               prev_x = x;
+               prev_y = y;
+               prev_btn = btn;
+       }
+       input_sync(hid->mouse);
+       dbg("HID X: %d Y: %d Functions: %x\n", x, y, buffer[1]);
+}
+
+/*
+ * Reference [1], Appendix A, Semtech standard PS/2 key number definitions,
+ * pgs. A-1 through A-3. The following table lists standard PS/2 key numbers
+ * used by the Juno® 01 keyboard manager.
+ *
+ * NOTES:
+ * 1. The following table indices are E0 codes which require special handling:
+ *     53..62, 77..78, 94, 96, 100, 102..104, 108..110
+ * 2. The following table indices are E1 codes which require special handling:
+ *     101
+ */
+
+static unsigned char usar2scancode[128] = {
+       0x00, 0x29, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+       0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+       0x18, 0x19, 0x1a, 0x1b, 0x2b, 0x1e, 0x1f, 0x20,
+       0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+       0x1c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32,
+       0x33, 0x34, 0x35, 0x39, 0x01, 0x52, 0x53, 0x4b,
+       0x47, 0x4f, 0x48, 0x50, 0x49, 0x51, 0x4d, 0x37,
+       0x4e, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47,
+       0x48, 0x49, 0x52, 0x53, 0x4a, 0x1c, 0x35, 0x3b,
+       0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43,
+       0x44, 0x57, 0x58, 0x2a, 0x36, 0x38, 0x38, 0x1d,
+       0x1d, 0x3a, 0x45, 0x46, 0x2a, 0x1d, 0x5b, 0x5c,
+       0x5d, 0xff, 0x00, 0x00, 0x5e, 0x5f, 0x63, 0x70,
+       0x7b, 0x79, 0x7d, 0x73, 0x5b, 0x5c, 0x5d, 0x63,
+       0x65, 0x66, 0x68, 0x69, 0x6b, 0x56, 0x54, 0x00
+};
+
+/*
+ * The following are bit masks used to encode E0 scan codes which
+ * require special handling. However, scan codes 100 and 101 are
+ * excludable here since they each require unique multi-byte scan
+ * code translations and are therefore dealt with individually via
+ * handle_print_scr() and handle_pause() respectively below.
+ */
+
+static unsigned long int e0_codes1 = 0x030003ff; /* scan codes 53..84 */
+static unsigned long int e0_codes2 = 0x038e0a00; /* scan codes 85..116 */
+
+static void
+handle_print_scr(int up)
+{
+       if (up) {
+               input_report_key(hid->keyboard, 0xe0, 1);
+               input_report_key(hid->keyboard, 0xb7, 1);
+               input_report_key(hid->keyboard, 0xe0, 1);
+               input_report_key(hid->keyboard, 0xaa, 1);
+       } else {
+               input_report_key(hid->keyboard, 0xe0, 0);
+               input_report_key(hid->keyboard, 0x2a, 0);
+               input_report_key(hid->keyboard, 0xe0, 0);
+               input_report_key(hid->keyboard, 0x37, 0);
+       }
+}
+
+static void
+handle_pause(void)
+{
+       input_report_key(hid->keyboard, 0xe1, 0);
+       input_report_key(hid->keyboard, 0x1d, 0);
+       input_report_key(hid->keyboard, 0x45, 0);
+       input_report_key(hid->keyboard, 0xe1, 0);
+       input_report_key(hid->keyboard, 0x9d, 0);
+       input_report_key(hid->keyboard, 0xc5, 0);
+}
+
+static void
+process_keyboard_report(struct innovator_hid_dev *hid, u8 * buffer)
+{
+       unsigned char ch = buffer[1] & 0x7f;
+       int up = buffer[1] & 0x80 ? 1 : 0;
+       int is_e0 = 0;
+       hid->keyboard = input_allocate_device();
+       hid->mouse = input_allocate_device();
+
+       if ((ch == 106) || (ch == 107))
+               return;         /* no code */
+
+       if (ch == 100) {
+               handle_print_scr(up);
+               return;
+       }
+
+       if (ch == 101) {
+               handle_pause();
+               return;
+       }
+
+       if ((ch >= 53) && (ch <= 84)) {
+               /* first block of e0 codes */
+               is_e0 = e0_codes1 & (1 << (ch - 53));
+       } else if ((ch >= 85) && (ch <= 116)) {
+               /* second block of e0 codes */
+               is_e0 = e0_codes2 & (1 << (ch - 85));
+       }
+
+       if (is_e0) {
+               input_report_key(hid->keyboard, 0xe0, !up);
+       }
+       input_report_key(hid->keyboard, usar2scancode[ch], !up);
+       input_sync(hid->keyboard);
+}
+
+static irqreturn_t
+innovator_hid_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       if (ATN()) {
+               disable_irq(OMAP1510_INT_FPGA_ATN);
+               tasklet_schedule(&hid_tasklet);
+       }
+       return IRQ_HANDLED;
+}
+
+static void
+do_hid_tasklet(unsigned long unused)
+{
+       int ret;
+       if ((ret = report_async(buffer, 256)) == -1) {
+               dbg("Error: Bad Juno return value: %d\n", ret);
+       } else if (ret == KEYBOARD_REPORT) {
+               process_keyboard_report(hid, buffer);
+       } else if (ret == POINTING_REPORT) {
+               process_pointing_report(hid, buffer);
+       } else {
+               dbg("ERROR: bad report\n");
+       }
+       enable_irq(OMAP1510_INT_FPGA_ATN);
+}
+
+static int
+innovator_hid_open(struct input_dev *dev)
+{
+       if (hid->open++)
+               return 0;
+
+       if (request_irq(OMAP1510_INT_FPGA_ATN, (void *) innovator_hid_interrupt,
+                       IRQF_DISABLED, PFX, hid) < 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+static void
+innovator_hid_close(struct input_dev *dev)
+{
+       if (!--hid->open)
+               return;
+
+       if (hid == NULL)
+               return;
+
+       kfree(hid);
+}
+
+static int innovator_ps2_remove(struct device *dev)
+{
+       return 0;
+}
+
+static void innovator_ps2_device_release(struct device *dev)
+{
+       /* Nothing */
+}
+
+static int innovator_ps2_suspend(struct device *dev, pm_message_t state)
+{
+       u8 pmcomm = 0;
+
+       /*
+        * Set SUS_STATE in REG_PM_COMM (Page 0 R0).  This will cause
+        * PM_MOD bits of REG_PM_STATUS to show suspended state,
+        * but the SUS_STAT bit of REG_PM_STATUS will continue to
+        * reflect the state of the _HSUS pin.
+        */
+
+       if (write_reg(REG_PAGENO, 0) < 0)
+               printk("ps2 suspend: write_reg REG_PAGENO error\n");
+
+       if (read_reg(REG_PM_COMM, &pmcomm) < 0)
+               printk("ps2 suspend: read_reg REG_PM_COMM error\n");
+               
+       if (write_reg(REG_PM_COMM, pmcomm | SUS_STATE) < 0)
+               printk("ps2 suspend: write_reg REG_PM_COMM error\n");
+
+       return 0;
+}
+
+static int innovator_ps2_resume(struct device *dev)
+{
+       u8 pmcomm = 0;
+
+       /*
+        * Clear SUS_STATE from REG_PM_COMM (Page 0 R0).
+        */
+
+       if (write_reg(REG_PAGENO, 0) < 0)
+               printk("ps2 resume: write_reg REG_PAGENO error\n");
+
+       if (read_reg(REG_PM_COMM, &pmcomm) < 0)
+               printk("ps2 resume: read_reg REG_PM_COMM error\n");
+
+       if (write_reg(REG_PM_COMM, pmcomm & ~SUS_STATE) < 0)
+               printk("ps2 resume: write_reg REG_PM_COMM error\n");
+
+       return 0;
+}
+
+static struct device_driver innovator_ps2_driver = {
+       .name           = "innovator_ps2",
+       .bus            = &platform_bus_type,
+       .remove         = innovator_ps2_remove,
+       .suspend        = innovator_ps2_suspend,
+       .resume         = innovator_ps2_resume,
+};
+
+static struct platform_device innovator_ps2_device = {
+       .name           = "ps2",
+       .id             = -1,
+       .dev = {
+               .driver         = &innovator_ps2_driver,
+               .release        = innovator_ps2_device_release,
+       },
+};
+
+static int __init
+innovator_kbd_init(void)
+{
+       int i;
+       info("Innovator PS/2 keyboard/mouse driver v1.0\n");
+
+       innovator_fpga_hid_reset();
+
+       if ((hid = kmalloc(sizeof(struct innovator_hid_dev),
+            GFP_KERNEL)) == NULL) {
+               warn("unable to allocate space for HID device\n");
+               return -ENOMEM;
+       }
+
+       /* setup the mouse */
+       memset(hid, 0, sizeof(struct innovator_hid_dev));
+       hid->mouse = input_allocate_device();
+       hid->mouse->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+       hid->mouse->keybit[LONG(BTN_MOUSE)] =
+           BIT(BTN_LEFT) | BIT(BTN_RIGHT) |
+           BIT(BTN_MIDDLE) | BIT(BTN_TOUCH);
+       hid->mouse->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+       hid->mouse->private = hid;
+       hid->mouse->open = innovator_hid_open;
+       hid->mouse->close = innovator_hid_close;
+       hid->mouse->name = "innovator_mouse";
+       hid->mouse->id.bustype = 0;
+       hid->mouse->id.vendor = 0;
+       hid->mouse->id.product = 0;
+       hid->mouse->id.version = 0;
+       hid->keyboard = input_allocate_device();
+       hid->keyboard->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+       hid->keyboard->keycodesize = sizeof(unsigned char);
+       hid->keyboard->keycodemax = ARRAY_SIZE(usar2scancode);
+       for(i = 0; i < 128; i++)
+               set_bit(usar2scancode[i], hid->keyboard->keybit);
+       hid->keyboard->private = hid;
+       hid->keyboard->open = innovator_hid_open;
+       hid->keyboard->close = innovator_hid_close;
+       hid->keyboard->name = "innovator_keyboard";
+       hid->keyboard->id.bustype = 0;
+       hid->keyboard->id.vendor = 0;
+       hid->keyboard->id.product = 0;
+       hid->keyboard->id.version = 0;
+       input_register_device(hid->mouse);
+       input_register_device(hid->keyboard);
+       innovator_hid_open(hid->mouse);
+       innovator_hid_open(hid->keyboard);
+
+       if (driver_register(&innovator_ps2_driver) != 0)
+               printk(KERN_ERR "Driver register failed for innovator_ps2\n");
+
+       if (platform_device_register(&innovator_ps2_device) != 0) {
+               printk(KERN_ERR "Device register failed for ps2\n");
+               driver_unregister(&innovator_ps2_driver);
+       }
+
+#ifdef INNOVATOR_KEYB_DEBUG
+       ctrl_dump_regs();
+#endif
+       return 0;
+}
+
+static void __exit
+innovator_kbd_exit(void)
+{
+       input_unregister_device(hid->mouse);
+       input_unregister_device(hid->keyboard);
+       free_irq(OMAP1510_INT_FPGA_ATN, hid);
+       if (hid != NULL)
+               kfree(hid);
+       driver_unregister(&innovator_ps2_driver);
+       platform_device_unregister(&innovator_ps2_device);
+       return;
+}
+
+module_init(innovator_kbd_init);
+module_exit(innovator_kbd_exit);
+
+MODULE_AUTHOR("George G. Davis <gdavis@mvista.com>");
+MODULE_DESCRIPTION("Innovator PS/2 Driver");
+MODULE_LICENSE("GPL");
index 5680a6d95b2b335c36c8bd6eed067ee87d2d085e..794bf4a25b7437135774d5bb9e97c54c4d4a47ef 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/mutex.h>
+#include <linux/spinlock.h>
 #include <linux/errno.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/keypad.h>
@@ -61,6 +62,8 @@ struct omap_kp {
        unsigned int cols;
        unsigned long delay;
        unsigned int debounce;
+       int suspended;
+       spinlock_t suspend_lock;
 };
 
 DECLARE_TASKLET_DISABLED(kp_tasklet, omap_kp_tasklet, 0);
@@ -100,6 +103,14 @@ static u8 get_row_gpio_val(struct omap_kp *omap_kp)
 static irqreturn_t omap_kp_interrupt(int irq, void *dev_id)
 {
        struct omap_kp *omap_kp = dev_id;
+       unsigned long flags;
+
+       spin_lock_irqsave(&omap_kp->suspend_lock, flags);
+       if (omap_kp->suspended) {
+               spin_unlock_irqrestore(&omap_kp->suspend_lock, flags);
+               return IRQ_HANDLED;
+       }
+       spin_unlock_irqrestore(&omap_kp->suspend_lock, flags);
 
        /* disable keyboard interrupt and schedule for handling */
        if (cpu_is_omap24xx()) {
@@ -271,15 +282,29 @@ static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, omap_kp_enable_show, omap_kp_enabl
 #ifdef CONFIG_PM
 static int omap_kp_suspend(struct platform_device *dev, pm_message_t state)
 {
-       /* Nothing yet */
+       struct omap_kp *omap_kp = platform_get_drvdata(dev);
+       unsigned long flags;
+       spin_lock_irqsave(&omap_kp->suspend_lock, flags);
+
+       /*
+        * Re-enable the interrupt in case it has been masked by the
+        * handler and a key is still pressed.  We need the interrupt
+        * to wake us up from suspended.
+        */
+       if (cpu_class_is_omap1())
+               omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+
+       omap_kp->suspended = 1;
 
+       spin_unlock_irqrestore(&omap_kp->suspend_lock, flags);
        return 0;
 }
 
 static int omap_kp_resume(struct platform_device *dev)
 {
-       /* Nothing yet */
+       struct omap_kp *omap_kp = platform_get_drvdata(dev);
 
+       omap_kp->suspended = 0;
        return 0;
 }
 #else
@@ -292,7 +317,7 @@ static int __init omap_kp_probe(struct platform_device *pdev)
        struct omap_kp *omap_kp;
        struct input_dev *input_dev;
        struct omap_kp_platform_data *pdata =  pdev->dev.platform_data;
-       int i, col_idx, row_idx, irq_idx, ret;
+       int i, col_idx = 0, row_idx = 0, irq_idx, ret;
 
        if (!pdata->rows || !pdata->cols || !pdata->keymap) {
                printk(KERN_ERR "No rows, cols or keymap from pdata\n");
@@ -309,7 +334,9 @@ static int __init omap_kp_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, omap_kp);
 
+       spin_lock_init(&omap_kp->suspend_lock);
        omap_kp->input = input_dev;
+       omap_kp->suspended = 0;
 
        /* Disable the interrupt for the MPUIO keyboard */
        if (!cpu_is_omap24xx())
index 6b46c9bf1d2045c7bf79a1c2c977bdf92a6db27e..8b3a3715e0b216ff16cf597b2d651738e9c70b10 100644 (file)
@@ -14,10 +14,13 @@ if INPUT_TOUCHSCREEN
 config TOUCHSCREEN_ADS7846
        tristate "ADS 7846 based touchscreens"
        depends on SPI_MASTER
+       select HWMON
        help
          Say Y here if you have a touchscreen interface using the
          ADS7846 controller, and your board-specific initialization
-         code includes that in its table of SPI devices.
+         code includes that in its table of SPI devices.  You will
+         also get hwmon interfaces for the temperature and voltage
+         sensors this chip provides.
 
          If unsure, say N (but it's safe to say "Y").
 
@@ -159,4 +162,32 @@ config TOUCHSCREEN_UCB1400
          To compile this driver as a module, choose M here: the
          module will be called ucb1400_ts.
 
+config TOUCHSCREEN_TSC2102
+       tristate "TSC 2102 based touchscreens"
+       depends on SPI_MASTER
+       select TSC2102
+       help
+         Say Y here if you have a touchscreen interface using the
+         TI TSC 2102 controller, and your board-specific initialization
+         code includes that in its table of SPI devices.  Also make
+         sure the proper SPI controller is selected.
+
+         If unsure, say N (but it's safe to say "Y").
+
+         To compile this driver as a module, choose M here: the
+         module will be called tsc2102_ts.
+
+config TOUCHSCREEN_OMAP
+       tristate "OMAP touchscreen input driver"
+       depends on INPUT && INPUT_TOUCHSCREEN && (MACH_OMAP_H2 || MACH_OMAP_H3)
+       help
+         Say Y here if you have an OMAP based board with touchscreen
+         attached to it, e.g. OMAP H2 or H3
+
+         If unsure, or you're using drivers in the newer SPI
+         framework (as with Innovator or OSK/Mistral), say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called omap_ts.
+
 endif
index 30e6e2217a15d86d72f153ca2fa3af9086f7ca70..061bc14aeda41dcce8c9f9311adb17055ab1dba3 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Makefile for the mouse drivers.
+# Makefile for the touchscreen input drivers.
 #
 
 # Each configuration option enables a list of files.
@@ -16,3 +16,5 @@ obj-$(CONFIG_TOUCHSCREEN_PENMOUNT)    += penmount.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)   += touchright.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN)     += touchwin.o
 obj-$(CONFIG_TOUCHSCREEN_UCB1400)      += ucb1400_ts.o
+obj-$(CONFIG_TOUCHSCREEN_TSC2102)      += tsc2102_ts.o
+obj-$(CONFIG_TOUCHSCREEN_OMAP) += omap/
index c6164b6f476a3ecb5fde27af07ddd05c38557d01..0c496d5d19597cd7702641c4867d39a994dd5320 100644 (file)
@@ -17,8 +17,9 @@
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
  */
-#include <linux/device.h>
+#include <linux/hwmon.h>
 #include <linux/init.h>
+#include <linux/err.h>
 #include <linux/delay.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
@@ -54,7 +55,8 @@
  * files.
  */
 
-#define        TS_POLL_PERIOD  msecs_to_jiffies(10)
+#define TS_POLL_DELAY  (1 * 1000000)   /* ns delay before the first sample */
+#define        TS_POLL_PERIOD  (5 * 1000000)   /* ns delay between samples */
 
 /* this driver doesn't aim at the peak continuous sample rate */
 #define        SAMPLE_BITS     (8 /*cmd*/ + 16 /*sample*/ + 2 /* before, after */)
@@ -76,7 +78,7 @@ struct ads7846 {
        char                    phys[32];
 
        struct spi_device       *spi;
-       struct attribute_group  *attr_group;
+       struct class_device     *hwmon;
        u16                     model;
        u16                     vref_delay_usecs;
        u16                     x_plate_ohms;
@@ -99,13 +101,16 @@ struct ads7846 {
        u16                     debounce_rep;
 
        spinlock_t              lock;
-       struct timer_list       timer;          /* P: lock */
+       struct hrtimer          timer;
        unsigned                pendown:1;      /* P: lock */
        unsigned                pending:1;      /* P: lock */
 // FIXME remove "irq_disabled"
        unsigned                irq_disabled:1; /* P: lock */
        unsigned                disabled:1;
 
+       int                     (*filter)(void *data, int data_idx, int *val);
+       void                    *filter_data;
+       void                    (*filter_cleanup)(void *data);
        int                     (*get_pendown_state)(void);
 };
 
@@ -142,15 +147,16 @@ struct ads7846 {
 #define        MAX_12BIT       ((1<<12)-1)
 
 /* leave ADC powered up (disables penirq) between differential samples */
-#define        READ_12BIT_DFR(x) (ADS_START | ADS_A2A1A0_d_ ## x \
-       | ADS_12_BIT | ADS_DFR)
+#define        READ_12BIT_DFR(x, adc, vref) (ADS_START | ADS_A2A1A0_d_ ## x \
+       | ADS_12_BIT | ADS_DFR | \
+       (adc ? ADS_PD10_ADC_ON : 0) | (vref ? ADS_PD10_REF_ON : 0))
 
-#define        READ_Y  (READ_12BIT_DFR(y)  | ADS_PD10_ADC_ON)
-#define        READ_Z1 (READ_12BIT_DFR(z1) | ADS_PD10_ADC_ON)
-#define        READ_Z2 (READ_12BIT_DFR(z2) | ADS_PD10_ADC_ON)
+#define        READ_Y(vref)    (READ_12BIT_DFR(y,  1, vref))
+#define        READ_Z1(vref)   (READ_12BIT_DFR(z1, 1, vref))
+#define        READ_Z2(vref)   (READ_12BIT_DFR(z2, 1, vref))
 
-#define        READ_X  (READ_12BIT_DFR(x)  | ADS_PD10_ADC_ON)
-#define        PWRDOWN (READ_12BIT_DFR(y)  | ADS_PD10_PDOWN)   /* LAST */
+#define        READ_X(vref)    (READ_12BIT_DFR(x,  1, vref))
+#define        PWRDOWN         (READ_12BIT_DFR(y,  0, 0))      /* LAST */
 
 /* single-ended samples need to first power up reference voltage;
  * we leave both ADC and VREF powered
@@ -158,14 +164,19 @@ struct ads7846 {
 #define        READ_12BIT_SER(x) (ADS_START | ADS_A2A1A0_ ## x \
        | ADS_12_BIT | ADS_SER)
 
-#define        REF_ON  (READ_12BIT_DFR(x) | ADS_PD10_ALL_ON)
-#define        REF_OFF (READ_12BIT_DFR(y) | ADS_PD10_PDOWN)
+#define        REF_ON  (READ_12BIT_DFR(x, 1, 1))
+#define        REF_OFF (READ_12BIT_DFR(y, 0, 0))
 
 /*--------------------------------------------------------------------------*/
 
 /*
  * Non-touchscreen sensors only use single-ended conversions.
+ * The range is GND..vREF. The ads7843 and ads7835 must use external vREF;
+ * ads7846 lets that pin be unconnected, to use internal vREF.
+ *
+ * FIXME make external vREF_mV be a module option, and use that as needed...
  */
+static const unsigned vREF_mV = 2500;
 
 struct ser_req {
        u8                      ref_on;
@@ -193,50 +204,55 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
        struct ser_req          *req = kzalloc(sizeof *req, GFP_KERNEL);
        int                     status;
        int                     sample;
-       int                     i;
+       int                     use_internal;
 
        if (!req)
                return -ENOMEM;
 
        spi_message_init(&req->msg);
 
-       /* activate reference, so it has time to settle; */
-       req->ref_on = REF_ON;
-       req->xfer[0].tx_buf = &req->ref_on;
-       req->xfer[0].len = 1;
-       req->xfer[1].rx_buf = &req->scratch;
-       req->xfer[1].len = 2;
-
-       /*
-        * for external VREF, 0 usec (and assume it's always on);
-        * for 1uF, use 800 usec;
-        * no cap, 100 usec.
-        */
-       req->xfer[1].delay_usecs = ts->vref_delay_usecs;
+       /* FIXME boards with ads7846 might use external vref instead ... */
+       use_internal = (ts->model == 7846);
+
+       /* maybe turn on internal vREF, and let it settle */
+       if (use_internal) {
+               req->ref_on = REF_ON;
+               req->xfer[0].tx_buf = &req->ref_on;
+               req->xfer[0].len = 1;
+               spi_message_add_tail(&req->xfer[0], &req->msg);
+
+               req->xfer[1].rx_buf = &req->scratch;
+               req->xfer[1].len = 2;
+
+               /* for 1uF, settle for 800 usec; no cap, 100 usec.  */
+               req->xfer[1].delay_usecs = ts->vref_delay_usecs;
+               spi_message_add_tail(&req->xfer[1], &req->msg);
+       }
 
        /* take sample */
        req->command = (u8) command;
        req->xfer[2].tx_buf = &req->command;
        req->xfer[2].len = 1;
+       spi_message_add_tail(&req->xfer[2], &req->msg);
+
        req->xfer[3].rx_buf = &req->sample;
        req->xfer[3].len = 2;
+       spi_message_add_tail(&req->xfer[3], &req->msg);
 
        /* REVISIT:  take a few more samples, and compare ... */
 
-       /* turn off reference */
-       req->ref_off = REF_OFF;
-       req->xfer[4].tx_buf = &req->ref_off;
-       req->xfer[4].len = 1;
-       req->xfer[5].rx_buf = &req->scratch;
-       req->xfer[5].len = 2;
-
-       CS_CHANGE(req->xfer[5]);
-
-       /* group all the transfers together, so we can't interfere with
-        * reading touchscreen state; disable penirq while sampling
-        */
-       for (i = 0; i < 6; i++)
-               spi_message_add_tail(&req->xfer[i], &req->msg);
+       /* maybe off internal vREF */
+       if (use_internal) {
+               req->ref_off = REF_OFF;
+               req->xfer[4].tx_buf = &req->ref_off;
+               req->xfer[4].len = 1;
+               spi_message_add_tail(&req->xfer[4], &req->msg);
+
+               req->xfer[5].rx_buf = &req->scratch;
+               req->xfer[5].len = 2;
+               CS_CHANGE(req->xfer[5]);
+               spi_message_add_tail(&req->xfer[5], &req->msg);
+       }
 
        ts->irq_disabled = 1;
        disable_irq(spi->irq);
@@ -256,21 +272,60 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
        return status ? status : sample;
 }
 
-#define SHOW(name) static ssize_t \
+#define SHOW(name,var,adjust) static ssize_t \
 name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \
 { \
+       struct ads7846 *ts = dev_get_drvdata(dev); \
        ssize_t v = ads7846_read12_ser(dev, \
-                       READ_12BIT_SER(name) | ADS_PD10_ALL_ON); \
+                       READ_12BIT_SER(var) | ADS_PD10_ALL_ON); \
        if (v < 0) \
                return v; \
-       return sprintf(buf, "%u\n", (unsigned) v); \
+       return sprintf(buf, "%u\n", adjust(ts, v)); \
 } \
 static DEVICE_ATTR(name, S_IRUGO, name ## _show, NULL);
 
-SHOW(temp0)
-SHOW(temp1)
-SHOW(vaux)
-SHOW(vbatt)
+
+/* Sysfs conventions report temperatures in millidegrees Celcius.
+ * We could use the low-accuracy two-sample scheme, but can't do the high
+ * accuracy scheme without calibration data.  For now we won't try either;
+ * userspace sees raw sensor values, and must scale appropriately.
+ */
+static inline unsigned null_adjust(struct ads7846 *ts, ssize_t v)
+{
+       return v;
+}
+
+SHOW(temp0, temp0, null_adjust)                // temp1_input
+SHOW(temp1, temp1, null_adjust)                // temp2_input
+
+
+/* sysfs conventions report voltages in millivolts.  We can convert voltages
+ * if we know vREF.  userspace may need to scale vAUX to match the board's
+ * external resistors; we assume that vBATT only uses the internal ones.
+ */
+static inline unsigned vaux_adjust(struct ads7846 *ts, ssize_t v)
+{
+       unsigned retval = v;
+
+       /* external resistors may scale vAUX into 0..vREF */
+       retval *= vREF_mV;
+       retval = retval >> 12;
+       return retval;
+}
+
+static inline unsigned vbatt_adjust(struct ads7846 *ts, ssize_t v)
+{
+       unsigned retval = vaux_adjust(ts, v);
+
+       /* ads7846 has a resistor ladder to scale this signal down */
+       if (ts->model == 7846)
+               retval *= 4;
+       return retval;
+}
+
+SHOW(in0_input, vaux, vaux_adjust)
+SHOW(in1_input, vbatt, vbatt_adjust)
+
 
 static int is_pen_down(struct device *dev)
 {
@@ -318,49 +373,40 @@ static ssize_t ads7846_disable_store(struct device *dev,
 
 static DEVICE_ATTR(disable, 0664, ads7846_disable_show, ads7846_disable_store);
 
-static struct attribute *ads7846_attributes[] = {
-       &dev_attr_temp0.attr,
-       &dev_attr_temp1.attr,
-       &dev_attr_vbatt.attr,
-       &dev_attr_vaux.attr,
-       &dev_attr_pen_down.attr,
-       &dev_attr_disable.attr,
-       NULL,
-};
+/*--------------------------------------------------------------------------*/
 
-static struct attribute_group ads7846_attr_group = {
-       .attrs = ads7846_attributes,
-};
+static void ads7846_report_pen_state(struct ads7846 *ts, int down)
+{
+       struct input_dev        *input_dev = ts->input;
 
-/*
- * ads7843/7845 don't have temperature sensors, and
- * use the other sensors a bit differently too
- */
+       input_report_key(input_dev, BTN_TOUCH, down);
+       if (!down)
+               input_report_abs(input_dev, ABS_PRESSURE, 0);
+#ifdef VERBOSE
+       pr_debug("%s: %s\n", ts->spi->dev.bus_id, down ? "DOWN" : "UP");
+#endif
+}
 
-static struct attribute *ads7843_attributes[] = {
-       &dev_attr_vbatt.attr,
-       &dev_attr_vaux.attr,
-       &dev_attr_pen_down.attr,
-       &dev_attr_disable.attr,
-       NULL,
-};
+static void ads7846_report_pen_position(struct ads7846 *ts, int x, int y,
+                                       int pressure)
+{
+       struct input_dev        *input_dev = ts->input;
 
-static struct attribute_group ads7843_attr_group = {
-       .attrs = ads7843_attributes,
-};
+       input_report_abs(input_dev, ABS_X, x);
+       input_report_abs(input_dev, ABS_Y, y);
+       input_report_abs(input_dev, ABS_PRESSURE, pressure);
 
-static struct attribute *ads7845_attributes[] = {
-       &dev_attr_vaux.attr,
-       &dev_attr_pen_down.attr,
-       &dev_attr_disable.attr,
-       NULL,
-};
+#ifdef VERBOSE
+       pr_debug("%s: %d/%d/%d\n", ts->spi->dev.bus_id, x, y, pressure);
+#endif
+}
 
-static struct attribute_group ads7845_attr_group = {
-       .attrs = ads7845_attributes,
-};
+static void ads7846_sync_events(struct ads7846 *ts)
+{
+       struct input_dev        *input_dev = ts->input;
 
-/*--------------------------------------------------------------------------*/
+       input_sync(input_dev);
+}
 
 /*
  * PENIRQ only kicks the timer.  The timer only reissues the SPI transfer,
@@ -373,25 +419,22 @@ static struct attribute_group ads7845_attr_group = {
 static void ads7846_rx(void *ads)
 {
        struct ads7846          *ts = ads;
-       struct input_dev        *input_dev = ts->input;
        unsigned                Rt;
-       unsigned                sync = 0;
        u16                     x, y, z1, z2;
-       unsigned long           flags;
 
        /* adjust:  on-wire is a must-ignore bit, a BE12 value, then padding;
         * built from two 8 bit values written msb-first.
         */
-       x = (be16_to_cpu(ts->tc.x) >> 3) & 0x0fff;
-       y = (be16_to_cpu(ts->tc.y) >> 3) & 0x0fff;
-       z1 = (be16_to_cpu(ts->tc.z1) >> 3) & 0x0fff;
-       z2 = (be16_to_cpu(ts->tc.z2) >> 3) & 0x0fff;
+       x = ts->tc.x;
+       y = ts->tc.y;
+       z1 = ts->tc.z1;
+       z2 = ts->tc.z2;
 
        /* range filtering */
        if (x == MAX_12BIT)
                x = 0;
 
-       if (likely(x && z1 && !device_suspended(&ts->spi->dev))) {
+       if (likely(x && z1)) {
                /* compute touch pressure resistance using equation #2 */
                Rt = z2;
                Rt -= z1;
@@ -406,97 +449,108 @@ static void ads7846_rx(void *ads)
        * the maximum. Don't report it to user space, repeat at least
        * once more the measurement */
        if (ts->tc.ignore || Rt > ts->pressure_max) {
-               mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
+#ifdef VERBOSE
+               pr_debug("%s: ignored %d pressure %d\n",
+                       ts->spi->dev.bus_id, ts->tc.ignore, Rt);
+#endif
+               hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
+                             HRTIMER_REL);
                return;
        }
 
-       /* NOTE:  "pendown" is inferred from pressure; we don't rely on
-        * being able to check nPENIRQ status, or "friendly" trigger modes
-        * (both-edges is much better than just-falling or low-level).
-        *
-        * REVISIT:  some boards may require reading nPENIRQ; it's
-        * needed on 7843.  and 7845 reads pressure differently...
-        *
-        * REVISIT:  the touchscreen might not be connected; this code
-        * won't notice that, even if nPENIRQ never fires ...
+       /* NOTE: We can't rely on the pressure to determine the pen down
+        * state. The pressure value can fluctuate for quite a while
+        * after lifting the pen and in some cases may not even settle at
+        * the expected value. The only safe way to check for the pen up
+        * condition is in the timer by reading the pen IRQ state.
         */
-       if (!ts->pendown && Rt != 0) {
-               input_report_key(input_dev, BTN_TOUCH, 1);
-               sync = 1;
-       } else if (ts->pendown && Rt == 0) {
-               input_report_key(input_dev, BTN_TOUCH, 0);
-               sync = 1;
-       }
-
        if (Rt) {
-               input_report_abs(input_dev, ABS_X, x);
-               input_report_abs(input_dev, ABS_Y, y);
-               sync = 1;
-       }
-
-       if (sync) {
-               input_report_abs(input_dev, ABS_PRESSURE, Rt);
-               input_sync(input_dev);
+               if (!ts->pendown) {
+                       ads7846_report_pen_state(ts, 1);
+                       ts->pendown = 1;
+               }
+               ads7846_report_pen_position(ts, x, y, Rt);
+               ads7846_sync_events(ts);
        }
 
-#ifdef VERBOSE
-       if (Rt || ts->pendown)
-               pr_debug("%s: %d/%d/%d%s\n", ts->spi->dev.bus_id,
-                       x, y, Rt, Rt ? "" : " UP");
-#endif
-
-       spin_lock_irqsave(&ts->lock, flags);
-
-       ts->pendown = (Rt != 0);
-       mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
-
-       spin_unlock_irqrestore(&ts->lock, flags);
+       hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), HRTIMER_REL);
 }
 
-static void ads7846_debounce(void *ads)
+static int ads7846_debounce(void *ads, int data_idx, int *val)
 {
        struct ads7846          *ts = ads;
-       struct spi_message      *m;
-       struct spi_transfer     *t;
-       int                     val;
-       int                     status;
 
-       m = &ts->msg[ts->msg_idx];
-       t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
-       val = (be16_to_cpu(*(__be16 *)t->rx_buf) >> 3) & 0x0fff;
-       if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol)) {
+       if (!ts->read_cnt || (abs(ts->last_read - *val) > ts->debounce_tol)) {
+               /* Start over collecting consistent readings. */
+               ts->read_rep = 0;
                /* Repeat it, if this was the first read or the read
                 * wasn't consistent enough. */
                if (ts->read_cnt < ts->debounce_max) {
-                       ts->last_read = val;
+                       ts->last_read = *val;
                        ts->read_cnt++;
+                       return ADS7846_FILTER_REPEAT;
                } else {
                        /* Maximum number of debouncing reached and still
                         * not enough number of consistent readings. Abort
                         * the whole sample, repeat it in the next sampling
                         * period.
                         */
-                       ts->tc.ignore = 1;
                        ts->read_cnt = 0;
-                       /* Last message will contain ads7846_rx() as the
-                        * completion function.
-                        */
-                       m = ts->last_msg;
+                       return ADS7846_FILTER_IGNORE;
                }
-               /* Start over collecting consistent readings. */
-               ts->read_rep = 0;
        } else {
                if (++ts->read_rep > ts->debounce_rep) {
                        /* Got a good reading for this coordinate,
                         * go for the next one. */
-                       ts->tc.ignore = 0;
-                       ts->msg_idx++;
                        ts->read_cnt = 0;
                        ts->read_rep = 0;
-                       m++;
-               } else
+                       return ADS7846_FILTER_OK;
+               } else {
                        /* Read more values that are consistent. */
                        ts->read_cnt++;
+                       return ADS7846_FILTER_REPEAT;
+               }
+       }
+}
+
+static int ads7846_no_filter(void *ads, int data_idx, int *val)
+{
+       return ADS7846_FILTER_OK;
+}
+
+static void ads7846_rx_val(void *ads)
+{
+       struct ads7846 *ts = ads;
+       struct spi_message *m;
+       struct spi_transfer *t;
+       u16 *rx_val;
+       int val;
+       int action;
+       int status;
+
+       m = &ts->msg[ts->msg_idx];
+       t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
+       rx_val = (u16 *)t->rx_buf;
+       val = be16_to_cpu(*rx_val) >> 3;
+
+       action = ts->filter(ts->filter_data, ts->msg_idx, &val);
+       switch (action) {
+       case ADS7846_FILTER_REPEAT:
+               break;
+       case ADS7846_FILTER_IGNORE:
+               ts->tc.ignore = 1;
+               /* Last message will contain ads7846_rx() as the
+                * completion function.
+                */
+               m = ts->last_msg;
+               break;
+       case ADS7846_FILTER_OK:
+               *rx_val = val;
+               ts->tc.ignore = 0;
+               m = &ts->msg[++ts->msg_idx];
+               break;
+       default:
+               BUG();
        }
        status = spi_async(ts->spi, m);
        if (status)
@@ -504,21 +558,27 @@ static void ads7846_debounce(void *ads)
                                status);
 }
 
-static void ads7846_timer(unsigned long handle)
+static int ads7846_timer(struct hrtimer *handle)
 {
-       struct ads7846  *ts = (void *)handle;
+       struct ads7846  *ts = container_of(handle, struct ads7846, timer);
        int             status = 0;
 
        spin_lock_irq(&ts->lock);
 
-       if (unlikely(ts->msg_idx && !ts->pendown)) {
-               /* measurement cycle ended */
+       if (unlikely(!ts->get_pendown_state() ||
+                    device_suspended(&ts->spi->dev))) {
+               if (ts->pendown) {
+                       ads7846_report_pen_state(ts, 0);
+                       ads7846_sync_events(ts);
+                       ts->pendown = 0;
+               }
+
+               /* measurment cycle ended */
                if (!device_suspended(&ts->spi->dev)) {
                        ts->irq_disabled = 0;
                        enable_irq(ts->spi->irq);
                }
                ts->pending = 0;
-               ts->msg_idx = 0;
        } else {
                /* pen is still down, continue with the measurement */
                ts->msg_idx = 0;
@@ -528,6 +588,7 @@ static void ads7846_timer(unsigned long handle)
        }
 
        spin_unlock_irq(&ts->lock);
+       return HRTIMER_NORESTART;
 }
 
 static irqreturn_t ads7846_irq(int irq, void *handle)
@@ -538,15 +599,17 @@ static irqreturn_t ads7846_irq(int irq, void *handle)
        spin_lock_irqsave(&ts->lock, flags);
        if (likely(ts->get_pendown_state())) {
                if (!ts->irq_disabled) {
-                       /* The ARM do_simple_IRQ() dispatcher doesn't act
-                        * like the other dispatchers:  it will report IRQs
-                        * even after they've been disabled.  We work around
-                        * that here.  (The "generic irq" framework may help...)
+                       /* REVISIT irq logic for many ARM chips has cloned a
+                        * bug wherein disabling an irq in its handler won't
+                        * work;(it's disabled lazily, and too late to work.
+                        * until all their irq logic is fixed, we must shadow
+                        * that state here.
                         */
                        ts->irq_disabled = 1;
                        disable_irq(ts->spi->irq);
                        ts->pending = 1;
-                       mod_timer(&ts->timer, jiffies);
+                       hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY),
+                                       HRTIMER_REL);
                }
        }
        spin_unlock_irqrestore(&ts->lock, flags);
@@ -629,9 +692,11 @@ static int __devinit ads7846_probe(struct spi_device *spi)
 {
        struct ads7846                  *ts;
        struct input_dev                *input_dev;
+       struct class_device             *hwmon = ERR_PTR(-ENOMEM);
        struct ads7846_platform_data    *pdata = spi->dev.platform_data;
        struct spi_message              *m;
        struct spi_transfer             *x;
+       int                             vref;
        int                             err;
 
        if (!spi->irq) {
@@ -651,36 +716,38 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                return -EINVAL;
        }
 
-       /* REVISIT when the irq can be triggered active-low, or if for some
-        * reason the touchscreen isn't hooked up, we don't need to access
-        * the pendown state.
-        */
        if (pdata->get_pendown_state == NULL) {
                dev_dbg(&spi->dev, "no get_pendown_state function?\n");
                return -EINVAL;
        }
 
-       /* We'd set TX wordsize 8 bits and RX wordsize to 13 bits ... except
-        * that even if the hardware can do that, the SPI controller driver
-        * may not.  So we stick to very-portable 8 bit words, both RX and TX.
+       /* We'd set the wordsize to 12 bits ... except that some controllers
+        * will then treat the 8 bit command words as 12 bits (and drop the
+        * four MSBs of the 12 bit result).  Result: inputs must be shifted
+        * to discard the four garbage LSBs.  (Also, not all controllers can
+        * support 12 bit words.)
         */
-       spi->bits_per_word = 8;
 
        ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);
        input_dev = input_allocate_device();
-       if (!ts || !input_dev) {
+       hwmon = hwmon_device_register(&spi->dev);
+       if (!ts || !input_dev || IS_ERR(hwmon)) {
                err = -ENOMEM;
                goto err_free_mem;
        }
 
        dev_set_drvdata(&spi->dev, ts);
        spi->dev.power.power_state = PMSG_ON;
+       spi->mode = SPI_MODE_1;
+       err = spi_setup(spi);
+       if (err < 0)
+               goto err_free_mem;
 
        ts->spi = spi;
        ts->input = input_dev;
+       ts->hwmon = hwmon;
 
-       init_timer(&ts->timer);
-       ts->timer.data = (unsigned long) ts;
+       hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_REL);
        ts->timer.function = ads7846_timer;
 
        spin_lock_init(&ts->lock);
@@ -689,14 +756,25 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
        ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
        ts->pressure_max = pdata->pressure_max ? : ~0;
-       if (pdata->debounce_max) {
+
+       if (pdata->filter != NULL) {
+               if (pdata->filter_init != NULL) {
+                       err = pdata->filter_init(pdata, &ts->filter_data);
+                       if (err < 0)
+                               goto err_free_mem;
+               }
+               ts->filter = pdata->filter;
+               ts->filter_cleanup = pdata->filter_cleanup;
+       } else if (pdata->debounce_max) {
                ts->debounce_max = pdata->debounce_max;
+               if (ts->debounce_max < 2)
+                       ts->debounce_max = 2;
                ts->debounce_tol = pdata->debounce_tol;
                ts->debounce_rep = pdata->debounce_rep;
-               if (ts->debounce_rep > ts->debounce_max + 1)
-                       ts->debounce_rep = ts->debounce_max - 1;
+               ts->filter = ads7846_debounce;
+               ts->filter_data = ts;
        } else
-               ts->debounce_tol = ~0;
+               ts->filter = ads7846_no_filter;
        ts->get_pendown_state = pdata->get_pendown_state;
 
        snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id);
@@ -718,6 +796,8 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        input_set_abs_params(input_dev, ABS_PRESSURE,
                        pdata->pressure_min, pdata->pressure_max, 0, 0);
 
+       vref = pdata->keep_vref_on;
+
        /* set up the transfers to read touchscreen state; this assumes we
         * use formula #2 for pressure, not #3.
         */
@@ -727,7 +807,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        spi_message_init(m);
 
        /* y- still on; turn on only y+ (and ADC) */
-       ts->read_y = READ_Y;
+       ts->read_y = READ_Y(vref);
        x->tx_buf = &ts->read_y;
        x->len = 1;
        spi_message_add_tail(x, m);
@@ -737,7 +817,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        x->len = 2;
        spi_message_add_tail(x, m);
 
-       m->complete = ads7846_debounce;
+       m->complete = ads7846_rx_val;
        m->context = ts;
 
        m++;
@@ -745,7 +825,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
 
        /* turn y- off, x+ on, then leave in lowpower */
        x++;
-       ts->read_x = READ_X;
+       ts->read_x = READ_X(vref);
        x->tx_buf = &ts->read_x;
        x->len = 1;
        spi_message_add_tail(x, m);
@@ -755,7 +835,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        x->len = 2;
        spi_message_add_tail(x, m);
 
-       m->complete = ads7846_debounce;
+       m->complete = ads7846_rx_val;
        m->context = ts;
 
        /* turn y+ off, x- on; we'll use formula #2 */
@@ -764,7 +844,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                spi_message_init(m);
 
                x++;
-               ts->read_z1 = READ_Z1;
+               ts->read_z1 = READ_Z1(vref);
                x->tx_buf = &ts->read_z1;
                x->len = 1;
                spi_message_add_tail(x, m);
@@ -774,14 +854,14 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                x->len = 2;
                spi_message_add_tail(x, m);
 
-               m->complete = ads7846_debounce;
+               m->complete = ads7846_rx_val;
                m->context = ts;
 
                m++;
                spi_message_init(m);
 
                x++;
-               ts->read_z2 = READ_Z2;
+               ts->read_z2 = READ_Z2(vref);
                x->tx_buf = &ts->read_z2;
                x->len = 1;
                spi_message_add_tail(x, m);
@@ -791,7 +871,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                x->len = 2;
                spi_message_add_tail(x, m);
 
-               m->complete = ads7846_debounce;
+               m->complete = ads7846_rx_val;
                m->context = ts;
        }
 
@@ -816,47 +896,81 @@ static int __devinit ads7846_probe(struct spi_device *spi)
 
        ts->last_msg = m;
 
-       if (request_irq(spi->irq, ads7846_irq, IRQF_TRIGGER_FALLING,
-                       spi->dev.driver->name, ts)) {
+       if (request_irq(spi->irq, ads7846_irq,
+                       IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_FALLING,
+                       spi->dev.bus_id, ts)) {
                dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
                err = -EBUSY;
-               goto err_free_mem;
+               goto err_cleanup_filter;
        }
 
-       dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq);
+       dev_info(&spi->dev, "touchscreen + hwmon, irq %d\n", spi->irq);
 
-       /* take a first sample, leaving nPENIRQ active; avoid
+       /* take a first sample, leaving nPENIRQ active and vREF off; avoid
         * the touchscreen, in case it's not connected.
         */
        (void) ads7846_read12_ser(&spi->dev,
                          READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
 
-       switch (ts->model) {
-       case 7846:
-               ts->attr_group = &ads7846_attr_group;
-               break;
-       case 7845:
-               ts->attr_group = &ads7845_attr_group;
-               break;
-       default:
-               ts->attr_group = &ads7843_attr_group;
-               break;
+       /* ads7843/7845 don't have temperature sensors, and
+        * use the other ADC lines a bit differently too
+        */
+       if (ts->model == 7846) {
+               err = device_create_file(&spi->dev, &dev_attr_temp0);
+               if (err)
+                       goto err_remove_attr7;
+               err = device_create_file(&spi->dev, &dev_attr_temp1);
+               if (err)
+                       goto err_remove_attr6;
+       }
+       /* in1 == vBAT (7846), or a non-scaled ADC input */
+       if (ts->model != 7845) {
+               err = device_create_file(&spi->dev, &dev_attr_in1_input);
+               if (err)
+                       goto err_remove_attr5;
        }
-       err = sysfs_create_group(&spi->dev.kobj, ts->attr_group);
+       /* in0 == a non-scaled ADC input */
+       err = device_create_file(&spi->dev, &dev_attr_in0_input);
+       if (err)
+               goto err_remove_attr4;
+
+       /* non-hwmon device attributes */
+       err = device_create_file(&spi->dev, &dev_attr_pen_down);
+       if (err)
+               goto err_remove_attr3;
+       err = device_create_file(&spi->dev, &dev_attr_disable);
        if (err)
-               goto err_free_irq;
+               goto err_remove_attr2;
 
        err = input_register_device(input_dev);
        if (err)
-               goto err_remove_attr_group;
+               goto err_remove_attr1;
 
        return 0;
 
- err_remove_attr_group:
-       sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
- err_free_irq:
+ err_remove_attr1:
+       device_remove_file(&spi->dev, &dev_attr_disable);
+ err_remove_attr2:
+       device_remove_file(&spi->dev, &dev_attr_pen_down);
+ err_remove_attr3:
+       device_remove_file(&spi->dev, &dev_attr_in0_input);
+ err_remove_attr4:
+       if (ts->model != 7845)
+               device_remove_file(&spi->dev, &dev_attr_in1_input);
+ err_remove_attr5:
+       if (ts->model == 7846) {
+               device_remove_file(&spi->dev, &dev_attr_temp1);
+ err_remove_attr6:
+               device_remove_file(&spi->dev, &dev_attr_temp0);
+       }
+ err_remove_attr7:
        free_irq(spi->irq, ts);
+ err_cleanup_filter:
+       if (ts->filter_cleanup)
+               ts->filter_cleanup(ts->filter_data);
  err_free_mem:
+       if (!IS_ERR(hwmon))
+               hwmon_device_unregister(hwmon);
        input_free_device(input_dev);
        kfree(ts);
        return err;
@@ -866,16 +980,28 @@ static int __devexit ads7846_remove(struct spi_device *spi)
 {
        struct ads7846          *ts = dev_get_drvdata(&spi->dev);
 
+       hwmon_device_unregister(ts->hwmon);
        input_unregister_device(ts->input);
 
        ads7846_suspend(spi, PMSG_SUSPEND);
 
-       sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
+       device_remove_file(&spi->dev, &dev_attr_disable);
+       device_remove_file(&spi->dev, &dev_attr_pen_down);
+       if (ts->model == 7846) {
+               device_remove_file(&spi->dev, &dev_attr_temp1);
+               device_remove_file(&spi->dev, &dev_attr_temp0);
+       }
+       if (ts->model != 7845)
+               device_remove_file(&spi->dev, &dev_attr_in1_input);
+       device_remove_file(&spi->dev, &dev_attr_in0_input);
 
        free_irq(ts->spi->irq, ts);
        /* suspend left the IRQ disabled */
        enable_irq(ts->spi->irq);
 
+       if (ts->filter_cleanup != NULL)
+               ts->filter_cleanup(ts->filter_data);
+
        kfree(ts);
 
        dev_dbg(&spi->dev, "unregistered touchscreen\n");
@@ -923,7 +1049,7 @@ static int __init ads7846_init(void)
 
        return spi_register_driver(&ads7846_driver);
 }
-module_init(ads7846_init);
+device_initcall(ads7846_init);
 
 static void __exit ads7846_exit(void)
 {
diff --git a/drivers/input/touchscreen/omap/Makefile b/drivers/input/touchscreen/omap/Makefile
new file mode 100644 (file)
index 0000000..af6344e
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Makefile for the OMAP touchscreen input driver
+#
+
+obj-$(CONFIG_TOUCHSCREEN_OMAP) += omapts.o
+
+objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_H2) += ts_hx.o
+objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_H3) += ts_hx.o
+
+omapts-objs := omap_ts.o $(objs-yy)
diff --git a/drivers/input/touchscreen/omap/omap_ts.c b/drivers/input/touchscreen/omap/omap_ts.c
new file mode 100644 (file)
index 0000000..14dfc6a
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * input/touchscreen/omap/omap_ts.c
+ *
+ * touchscreen input device driver for various TI OMAP boards
+ * Copyright (c) 2002 MontaVista Software Inc.
+ * Copyright (c) 2004 Texas Instruments, Inc.
+ * Cleanup and modularization 2004 by Dirk Behme <dirk.behme@de.bosch.com>
+ *
+ * Assembled using driver code copyright the companies above.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * History:
+ * 12/12/2004    Srinath Modified and intergrated code for H2 and H3
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/suspend.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+
+//#define DEBUG
+
+#include "omap_ts.h"
+
+#define OMAP_TS_NAME   "omap_ts"
+
+static struct ts_device *__initdata ts_devs[] = {
+#if defined(CONFIG_MACH_OMAP_H2) || defined(CONFIG_MACH_OMAP_H3)
+       &hx_ts,
+#endif
+};
+
+static struct omap_ts_t ts_omap;
+
+static int omap_ts_read(void)
+{
+       u16 data[4] = { 0, 0, 0, 0 };
+
+       ts_omap.dev->read(data);
+
+       input_report_abs(ts_omap.inputdevice, ABS_X, data[0]);
+       input_report_abs(ts_omap.inputdevice, ABS_Y, data[1]);
+       input_report_abs(ts_omap.inputdevice, ABS_PRESSURE, data[2]);
+       input_sync(ts_omap.inputdevice);
+
+       DEBUG_TS("omap_ts_read: read x=%d,y=%d,p=%d\n", data[0], data[1],
+                data[2]);
+
+       return 0;
+}
+
+static void omap_ts_timer(unsigned long data)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ts_omap.lock, flags);
+
+       if (!ts_omap.dev->penup()) {
+               if (!ts_omap.touched) {
+                       DEBUG_TS("omap_ts_timer: pen down\n");
+                       input_report_key(ts_omap.inputdevice, BTN_TOUCH, 1);
+               }
+               ts_omap.touched = 1;
+               omap_ts_read();
+               ts_omap.ts_timer.expires = jiffies + HZ / 100;
+               add_timer(&(ts_omap.ts_timer));
+       } else {
+               if (ts_omap.touched) {
+                       DEBUG_TS("omap_ts_timer: pen up\n");
+                       ts_omap.touched = 0;
+                       input_report_abs(ts_omap.inputdevice, ABS_X, 0);
+                       input_report_abs(ts_omap.inputdevice, ABS_Y, 0);
+                       input_report_abs(ts_omap.inputdevice, ABS_PRESSURE,
+                                        0);
+                       input_sync(ts_omap.inputdevice);
+                       input_report_key(ts_omap.inputdevice, BTN_TOUCH, 0);
+               }
+               if (!ts_omap.irq_enabled) {
+                       ts_omap.irq_enabled = 1;
+                       enable_irq(ts_omap.irq);
+               }
+       }
+
+       spin_unlock_irqrestore(&ts_omap.lock, flags);
+}
+
+static irqreturn_t omap_ts_handler(int irq, void *dev_id)
+{
+       spin_lock(&ts_omap.lock);
+
+       if (ts_omap.irq_enabled) {
+               ts_omap.irq_enabled = 0;
+               disable_irq(irq);
+       }
+       // restart acquire
+       mod_timer(&ts_omap.ts_timer, jiffies + HZ / 100);
+
+       spin_unlock(&ts_omap.lock);
+
+       return IRQ_HANDLED;
+}
+
+static int __init omap_ts_probe(struct platform_device *pdev)
+{
+       int i;
+       int status = -ENODEV;
+
+       memset(&ts_omap, 0, sizeof(ts_omap));
+
+       ts_omap.inputdevice = input_allocate_device();
+       if (!ts_omap.inputdevice) {
+               return -ENOMEM;
+       }
+
+       spin_lock_init(&ts_omap.lock);
+
+       for (i = 0; i < ARRAY_SIZE(ts_devs); i++) {
+               if (!ts_devs[i] || !ts_devs[i]->probe)
+                       continue;
+               status = ts_devs[i]->probe(&ts_omap);
+               if (status == 0) {
+                       ts_omap.dev = ts_devs[i];
+                       break;
+               }
+       }
+
+       if (status != 0) {
+               input_free_device(ts_omap.inputdevice);
+               return status;
+       }
+
+       // Init acquisition timer function
+       init_timer(&ts_omap.ts_timer);
+       ts_omap.ts_timer.function = omap_ts_timer;
+
+       /* request irq */
+       if (ts_omap.irq != -1) {
+               if (request_irq(ts_omap.irq, omap_ts_handler,
+                               IRQF_SAMPLE_RANDOM | ts_omap.irq_type,
+                               OMAP_TS_NAME, &ts_omap)) {
+                       printk(KERN_ERR
+         "omap_ts.c: Could not allocate touchscreen IRQ!\n");
+                       ts_omap.irq = -1;
+                       ts_omap.dev->remove();
+                       input_free_device(ts_omap.inputdevice);
+                       return -EINVAL;
+               }
+               ts_omap.irq_enabled = 1;
+       } else {
+               printk(KERN_ERR "omap_ts.c: No touchscreen IRQ assigned!\n");
+               ts_omap.dev->remove();
+               input_free_device(ts_omap.inputdevice);
+               return -EINVAL;
+       }
+
+       ts_omap.inputdevice->name = OMAP_TS_NAME;
+       ts_omap.inputdevice->dev = &pdev->dev;
+       ts_omap.inputdevice->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+       ts_omap.inputdevice->keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
+       ts_omap.inputdevice->absbit[0] =
+           BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+       input_register_device(ts_omap.inputdevice);
+
+       ts_omap.dev->enable();
+
+       printk("OMAP touchscreen driver initialized\n");
+
+       return 0;
+}
+
+static int omap_ts_remove(struct platform_device *pdev)
+{
+       ts_omap.dev->disable();
+       input_unregister_device(ts_omap.inputdevice);
+       if (ts_omap.irq != -1)
+               free_irq(ts_omap.irq, &ts_omap);
+
+       ts_omap.dev->remove();
+
+       return 0;
+}
+
+static int omap_ts_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       ts_omap.dev->disable();
+       return 0;
+}
+
+static int omap_ts_resume(struct platform_device *pdev)
+{
+       ts_omap.dev->enable();
+       return 0;
+}
+
+static void omap_ts_device_release(struct device *dev)
+{
+       /* Nothing */
+}
+static struct platform_driver omap_ts_driver = {
+       .probe          = omap_ts_probe,
+       .remove         = omap_ts_remove,
+       .suspend        = omap_ts_suspend,
+       .resume         = omap_ts_resume,
+       .driver = {
+               .name   = OMAP_TS_NAME,
+       },
+};
+
+static struct platform_device omap_ts_device = {
+       .name           = OMAP_TS_NAME,
+       .id             = -1,
+       .dev = {
+               .release        = omap_ts_device_release,
+       },
+};
+
+static int __init omap_ts_init(void)
+{
+       int ret;
+
+       if (machine_is_omap_osk() || machine_is_omap_innovator())
+               return -ENODEV;
+
+       ret = platform_device_register(&omap_ts_device);
+       if (ret != 0)
+               return -ENODEV;
+
+       ret = platform_driver_register(&omap_ts_driver);
+       if (ret != 0) {
+               platform_device_unregister(&omap_ts_device);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void __exit omap_ts_exit(void)
+{
+       platform_driver_unregister(&omap_ts_driver);
+       platform_device_unregister(&omap_ts_device);
+}
+
+module_init(omap_ts_init);
+module_exit(omap_ts_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/omap/omap_ts.h b/drivers/input/touchscreen/omap/omap_ts.h
new file mode 100644 (file)
index 0000000..bef8e17
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * omap_ts.h - header file for OMAP touchscreen support
+ * 
+ * Copyright (c) 2002 MontaVista Software Inc.
+ * Copyright (c) 2004 Texas Instruments, Inc.
+ *
+ * Assembled using driver code copyright the companies above.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __OMAP_TS_H
+#define __OMAP_TS_H
+
+#ifdef DEBUG
+#define DEBUG_TS(fmt...)   printk(fmt)
+#else
+#define DEBUG_TS(fmt...)   do { } while (0)
+#endif
+
+struct omap_ts_t;
+
+struct ts_device {
+        int  (*probe)   (struct omap_ts_t *);
+        void (*read)    (u16 *);
+        void (*enable)  (void);
+        void (*disable) (void);
+        void (*remove)  (void);
+        int  (*penup)  (void);
+};
+
+struct omap_ts_t{
+       struct input_dev * inputdevice;
+       struct timer_list ts_timer;      // Timer for triggering acquisitions
+       int touched;
+       int irq;
+       int irq_type;
+       int irq_enabled;
+       struct ts_device *dev;
+       spinlock_t lock;
+};
+
+extern struct ts_device hx_ts;
+
+#endif /* __OMAP_TS_H */
diff --git a/drivers/input/touchscreen/omap/ts_hx.c b/drivers/input/touchscreen/omap/ts_hx.c
new file mode 100644 (file)
index 0000000..9f82f5a
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * input/touchscreen/omap/ts_hx.c
+ * touchscreen support for OMAP H3 and H2  boards
+ *
+ * Copyright (c) 2002 MontaVista Software Inc.
+ * Copyright (c) 2004 Texas Instruments, Inc.
+ *
+ * Assembled using driver code copyright the companies above.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * History:
+ * 9/12/2004   Srinath Modified and integrated  H2 and H3 code
+ *
+ */
+
+#include <linux/input.h>
+#include <linux/device.h>
+#include <asm/mach-types.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/hardware.h>
+#include <asm/hardware/tsc2101.h>
+
+#include "../drivers/ssi/omap-tsc2101.h"
+#include "omap_ts.h"
+
+#define        H2_GPIO_NUM             4
+#define        H3_GPIO_NUM             48
+
+#define OMAP_TSC2101_XRES                     500
+#define TOUCHSCREEN_DATA_REGISTERS_PAGE         0x0
+#define TOUCHSCREEN_CONTROL_REGISTERS_PAGE      0x1
+#define OMAP_TSC2101_READ_MAX             0x4
+#define TSC2101_GETSTATUS(ret)           (((ret) >> 11) & 0x1)
+#define TSC2101_MASKVAL                         0xFFF
+#define TSC2101_PRESSUREVAL(x)           ((x) << 12)
+
+static int hx_ts_penup(void);
+static int hx_ts_probe(struct omap_ts_t *ts);
+static void hx_ts_read(u16 * data);
+static void hx_ts_enable(void);
+static void hx_ts_disable(void);
+#ifdef MODULE
+static void hx_ts_remove(void);
+#endif
+
+struct ts_device hx_ts = {
+       .probe          = hx_ts_probe,
+       .read           = hx_ts_read,
+       .enable         = hx_ts_enable,
+       .disable        = hx_ts_disable,
+       .remove         = __exit_p(hx_ts_remove),
+       .penup          = hx_ts_penup,
+};
+
+static int hx_ts_penup(void)
+{
+       int ret = 0;
+       /* Read the status register */
+       ret = omap_tsc2101_read(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
+                               TSC2101_TS_STATUS);
+       /* Check for availability of data in status register */
+       ret = TSC2101_GETSTATUS(ret);
+       return !ret;
+
+}
+
+static int __init hx_ts_probe(struct omap_ts_t *ts)
+{
+       unsigned        gpio;
+
+       if (machine_is_omap_h2()) {
+               gpio = H2_GPIO_NUM;
+               omap_cfg_reg(P20_1610_GPIO4);
+       } else if (machine_is_omap_h3()) {
+               gpio = H3_GPIO_NUM;
+               omap_cfg_reg(W19_1610_GPIO48);
+       } else
+               return -ENODEV;
+
+       ts->irq = OMAP_GPIO_IRQ(gpio);
+       if (omap_request_gpio(gpio) != 0) {
+               printk(KERN_ERR "hX_ts_init.c: Could not reserve GPIO!\n");
+               return -EINVAL;
+       };
+
+       omap_set_gpio_direction(gpio, 1);
+       ts->irq_type = IRQF_TRIGGER_FALLING;
+       return 0;
+}
+
+static void hx_ts_read(u16 * values)
+{
+       s32 t, p = 0;
+       int i;
+
+       /* Read X, Y, Z1 and Z2 */
+       omap_tsc2101_reads(TOUCHSCREEN_DATA_REGISTERS_PAGE, TSC2101_TS_X,
+                          values, OMAP_TSC2101_READ_MAX);
+
+       for (i = 0; i < OMAP_TSC2101_READ_MAX; i++)
+               values[i] &= TSC2101_MASKVAL;
+
+       /* Calculate Pressure */
+       if (values[TSC2101_TS_Z1] != 0) {
+               t = ((OMAP_TSC2101_XRES * values[TSC2101_TS_X]) *
+                    (values[TSC2101_TS_Z2] - values[TSC2101_TS_Z1]));
+               p = t / (u32) (TSC2101_PRESSUREVAL(values[TSC2101_TS_Z1]));
+               if (p < 0)
+                       p = 0;
+       }
+
+       values[TSC2101_TS_Z1] = p;
+}
+
+static void hx_ts_enable(void)
+{
+       int ret = omap_tsc2101_enable();
+       if (ret) {
+               printk(KERN_ERR "FAILED TO INITIALIZE TSC CODEC\n");
+               return;
+       }
+
+       /* PINTDAV is data available only */
+       omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
+                          TSC2101_TS_STATUS, TSC2101_DATA_AVAILABLE);
+       /* disable buffer mode */
+       omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
+                          TSC2101_TS_BUFFER_CTRL, TSC2101_BUFFERMODE_DISABLE);
+       /* use internal reference, 100 usec power-up delay,
+        *        * power down between conversions, 1.25V internal reference */
+       omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
+                          TSC2101_TS_REF_CTRL, TSC2101_REF_POWERUP);
+       /* enable touch detection, 84usec precharge time, 32 usec sense time */
+       omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
+                          TSC2101_TS_CONFIG_CTRL, TSC2101_ENABLE_TOUCHDETECT);
+       /* 3 msec conversion delays  */
+       omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
+                          TSC2101_TS_PROG_DELAY, TSC2101_PRG_DELAY);
+       /*
+        * TSC2101-controlled conversions
+        * 12-bit samples
+        * continuous X,Y,Z1,Z2 scan mode
+        * average (mean) 4 samples per coordinate
+        * 1 MHz internal conversion clock
+        * 500 usec panel voltage stabilization delay
+        */
+       omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
+                          TSC2101_TS_ADC_CTRL, TSC2101_ADC_CONTROL);
+
+       return;
+
+}
+
+static void hx_ts_disable(void)
+{
+       /* stop conversions and power down */
+       omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
+                          TSC2101_TS_ADC_CTRL, TSC2101_ADC_POWERDOWN);
+       omap_tsc2101_disable();
+}
+
+#ifdef MODULE
+static void __exit hx_ts_remove(void)
+{
+       if (machine_is_omap_h2())
+               omap_free_gpio(H2_GPIO_NUM);
+       else if (machine_is_omap_h3())
+               omap_free_gpio(H3_GPIO_NUM);
+}
+#endif
diff --git a/drivers/input/touchscreen/tsc2102_ts.c b/drivers/input/touchscreen/tsc2102_ts.c
new file mode 100644 (file)
index 0000000..8188263
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * input/touchscreen/tsc2102_ts.c
+ *
+ * Touchscreen input device driver for the TSC 2102 chip.
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This package 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 package 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 package; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <linux/spi/tsc2102.h>
+
+struct input_dev *dev;
+
+static void tsc2102_touch(int touching)
+{
+       if (!touching) {
+               input_report_abs(dev, ABS_X, 0);
+               input_report_abs(dev, ABS_Y, 0);
+               input_report_abs(dev, ABS_PRESSURE, 0);
+               input_sync(dev);
+       }
+
+       input_report_key(dev, BTN_TOUCH, touching);
+}
+
+static void tsc2102_coords(int x, int y, int z1, int z2)
+{
+       int p;
+
+       /* Calculate the touch resistance a la equation #1 */
+       if (z1 != 0)
+               p = x * (z2 - z1) / (z1 << 4);
+       else
+               p = 1;
+
+       input_report_abs(dev, ABS_X, x);
+       input_report_abs(dev, ABS_Y, y);
+       input_report_abs(dev, ABS_PRESSURE, p);
+       input_sync(dev);
+}
+
+static int tsc2102_ts_probe(struct platform_device *pdev)
+{
+       int status;
+
+       dev = input_allocate_device();
+       if (!dev)
+               return -ENOMEM;
+
+       status = tsc2102_touch_cb(tsc2102_touch);
+       if (status) {
+               input_free_device(dev);
+               return status;
+       }
+
+       status = tsc2102_coords_cb(tsc2102_coords);
+       if (status) {
+               tsc2102_touch_cb(0);
+               input_free_device(dev);
+               return status;
+       }
+
+       dev->name = "TSC2102 Touchscreen";
+       dev->dev = &pdev->dev;
+       dev->cdev.dev = &pdev->dev;
+       dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+       dev->keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
+       dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+       dev->phys = "tsc2102/input0";
+       dev->id.bustype = BUS_HOST;
+       dev->id.vendor = 0x0001;
+       dev->id.product = 0x2102;
+       dev->id.version = 0x0001;
+
+       status = input_register_device(dev);
+       if (status) {
+               tsc2102_coords_cb(0);
+               tsc2102_touch_cb(0);
+               input_free_device(dev);
+               return status;
+       }
+
+       printk(KERN_INFO "TSC2102 touchscreen driver initialized\n");
+       return 0;
+}
+
+static int tsc2102_ts_remove(struct platform_device *pdev)
+{
+       tsc2102_touch_cb(0);
+       tsc2102_coords_cb(0);
+       input_unregister_device(dev);
+       input_free_device(dev);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int
+tsc2102_ts_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       return 0;
+}
+
+static int tsc2102_ts_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+#else
+#define tsc2102_ts_suspend     NULL
+#define tsc2102_ts_resume      NULL
+#endif
+
+static struct platform_driver tsc2102_ts_driver = {
+       .probe          = tsc2102_ts_probe,
+       .remove         = tsc2102_ts_remove,
+       .suspend        = tsc2102_ts_suspend,
+       .resume         = tsc2102_ts_resume,
+       .driver         = {
+               .name   = "tsc2102-ts",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init tsc2102_ts_init(void)
+{
+       int ret;
+
+       ret = platform_driver_register(&tsc2102_ts_driver);
+       if (ret)
+               return -ENODEV;
+
+       return 0;
+}
+
+static void __exit tsc2102_ts_exit(void)
+{
+       platform_driver_unregister(&tsc2102_ts_driver);
+}
+
+module_init(tsc2102_ts_init);
+module_exit(tsc2102_ts_exit);
+
+MODULE_AUTHOR("Andrzej Zaborowski");
+MODULE_DESCRIPTION("Touchscreen input driver for TI TSC2102.");
+MODULE_LICENSE("GPL");
index 7399ba791116d882ecceae66fa7e9535cfea1404..7c2c352430f5500dda284735dcf656bc937baef5 100644 (file)
@@ -82,6 +82,27 @@ config LEDS_WRAP
        help
          This option enables support for the PCEngines WRAP programmable LEDs.
 
+config LEDS_OMAP_DEBUG
+       boolean "LED Support for OMAP debug board LEDs"
+       depends on LEDS_CLASS=y && ARCH_OMAP
+       help
+         Enables support for the LEDs on the debug board used with OMAP
+         reference boards like H2/H3/H4 and Perseus2.  Up to six of these
+         may be claimed by the original ARM debug LED API.
+
+config LEDS_OMAP
+       tristate "LED Support for OMAP GPIO LEDs"
+       depends on LEDS_CLASS && ARCH_OMAP
+       help
+         This option enables support for the LEDs on OMAP processors.
+
+config LEDS_OMAP_PWM
+       tristate "LED Support for OMAP PWM-controlled LEDs"
+       depends on LEDS_CLASS && ARCH_OMAP && OMAP_DM_TIMER
+       help
+         This options enables support for LEDs connected to GPIO lines
+         controlled by a PWM timer on OMAP CPUs.
+
 comment "LED Triggers"
 
 config LEDS_TRIGGERS
index 500de3dc962adedcb2576e543754f6d54d439988..d39541a88d03eba4681880cce7d6e1f00d5b025f 100644 (file)
@@ -14,6 +14,8 @@ obj-$(CONFIG_LEDS_S3C24XX)            += leds-s3c24xx.o
 obj-$(CONFIG_LEDS_AMS_DELTA)           += leds-ams-delta.o
 obj-$(CONFIG_LEDS_NET48XX)             += leds-net48xx.o
 obj-$(CONFIG_LEDS_WRAP)                        += leds-wrap.o
+obj-$(CONFIG_LEDS_OMAP)                        += leds-omap.o
+obj-$(CONFIG_LEDS_OMAP_PWM)            += leds-omap-pwm.o
 
 # LED Triggers
 obj-$(CONFIG_LEDS_TRIGGER_TIMER)       += ledtrig-timer.o
diff --git a/drivers/leds/leds-omap-pwm.c b/drivers/leds/leds-omap-pwm.c
new file mode 100644 (file)
index 0000000..6b195d6
--- /dev/null
@@ -0,0 +1,354 @@
+/* drivers/leds/leds-omap_pwm.c
+ *
+ * Driver to blink LEDs using OMAP PWM timers
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Timo Teras
+ *
+ * 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/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/ctype.h>
+#include <asm/delay.h>
+#include <asm/arch/board.h>
+#include <asm/arch/dmtimer.h>
+
+struct omap_pwm_led {
+       struct led_classdev cdev;
+       struct omap_pwm_led_platform_data *pdata;
+       struct omap_dm_timer *intensity_timer;
+       struct omap_dm_timer *blink_timer;
+       int powered;
+       unsigned int on_period, off_period;
+};
+
+static inline struct omap_pwm_led *pdev_to_omap_pwm_led(struct platform_device *pdev)
+{
+       return platform_get_drvdata(pdev);
+}
+
+static inline struct omap_pwm_led *cdev_to_omap_pwm_led(struct led_classdev *led_cdev)
+{
+       return container_of(led_cdev, struct omap_pwm_led, cdev);
+}
+
+static void omap_pwm_led_set_blink(struct omap_pwm_led *led)
+{
+       if (!led->powered)
+               return;
+
+       if (led->on_period != 0 && led->off_period != 0) {
+               unsigned long load_reg, cmp_reg;
+
+               load_reg = 32768 * (led->on_period + led->off_period) / 1000;
+               cmp_reg = 32768 * led->on_period / 1000;
+
+               omap_dm_timer_stop(led->blink_timer);
+               omap_dm_timer_set_load(led->blink_timer, 1, -load_reg);
+               omap_dm_timer_set_match(led->blink_timer, 1, -cmp_reg);
+               omap_dm_timer_set_pwm(led->blink_timer, 1, 1,
+                                     OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
+               omap_dm_timer_write_counter(led->blink_timer, -2);
+               omap_dm_timer_start(led->blink_timer);
+       } else {
+               omap_dm_timer_set_pwm(led->blink_timer, 1, 1,
+                                     OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
+               omap_dm_timer_stop(led->blink_timer);
+       }
+}
+
+static void omap_pwm_led_power_on(struct omap_pwm_led *led)
+{
+       if (led->powered)
+               return;
+       led->powered = 1;
+
+       /* Select clock */
+       omap_dm_timer_enable(led->intensity_timer);
+       omap_dm_timer_set_source(led->intensity_timer, OMAP_TIMER_SRC_32_KHZ);
+
+       /* Turn voltage on */
+       if (led->pdata->set_power != NULL)
+               led->pdata->set_power(led->pdata, 1);
+
+       /* Enable PWM timers */
+       if (led->blink_timer != NULL) {
+               omap_dm_timer_enable(led->blink_timer);
+               omap_dm_timer_set_source(led->blink_timer,
+                                        OMAP_TIMER_SRC_32_KHZ);
+               omap_pwm_led_set_blink(led);
+       }
+
+       omap_dm_timer_set_load(led->intensity_timer, 1, 0xffffff00);
+}
+
+static void omap_pwm_led_power_off(struct omap_pwm_led *led)
+{
+       if (!led->powered)
+               return;
+       led->powered = 0;
+
+       /* Everything off */
+       omap_dm_timer_stop(led->intensity_timer);
+       omap_dm_timer_disable(led->intensity_timer);
+
+       if (led->blink_timer != NULL) {
+               omap_dm_timer_stop(led->blink_timer);
+               omap_dm_timer_disable(led->blink_timer);
+       }
+
+       if (led->pdata->set_power != NULL)
+               led->pdata->set_power(led->pdata, 0);
+}
+
+static void omap_pwm_led_set_pwm_cycle(struct omap_pwm_led *led, int cycle)
+{
+       int n;
+
+       if (cycle == 0)
+               n = 0xff;
+       else    n = cycle - 1;
+
+       if (cycle == LED_FULL) {
+               omap_dm_timer_set_pwm(led->intensity_timer, 1, 1,
+                                     OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
+               omap_dm_timer_stop(led->intensity_timer);
+       } else {
+               omap_dm_timer_set_pwm(led->intensity_timer, 0, 1,
+                                     OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
+               omap_dm_timer_set_match(led->intensity_timer, 1,
+                                       (0xffffff00) | cycle);
+               omap_dm_timer_start(led->intensity_timer);
+       }
+}
+
+static void omap_pwm_led_set(struct led_classdev *led_cdev,
+                            enum led_brightness value)
+{
+       struct omap_pwm_led *led = cdev_to_omap_pwm_led(led_cdev);
+
+       if (value != LED_OFF) {
+               omap_pwm_led_power_on(led);
+               omap_pwm_led_set_pwm_cycle(led, value);
+       } else {
+               omap_pwm_led_power_off(led);
+       }
+}
+
+static ssize_t omap_pwm_led_on_period_show(struct class_device *cdev, char *buf)
+{
+       struct led_classdev *led_cdev = class_get_devdata(cdev);
+       struct omap_pwm_led *led = cdev_to_omap_pwm_led(led_cdev);
+
+       return sprintf(buf, "%u\n", led->on_period) + 1;
+}
+
+static ssize_t omap_pwm_led_on_period_store(struct class_device *cdev,
+                                           const char *buf, size_t size)
+{
+       struct led_classdev *led_cdev = class_get_devdata(cdev);
+       struct omap_pwm_led *led = cdev_to_omap_pwm_led(led_cdev);
+       int ret = -EINVAL;
+       unsigned long val;
+       char *after;
+       size_t count;
+
+       val = simple_strtoul(buf, &after, 10);
+       count = after - buf;
+       if (*after && isspace(*after))
+               count++;
+
+       if (count == size) {
+               led->on_period = val;
+               omap_pwm_led_set_blink(led);
+               ret = count;
+       }
+
+       return ret;
+}
+
+static ssize_t omap_pwm_led_off_period_show(struct class_device *cdev, char *buf)
+{
+       struct led_classdev *led_cdev = class_get_devdata(cdev);
+       struct omap_pwm_led *led = cdev_to_omap_pwm_led(led_cdev);
+
+       return sprintf(buf, "%u\n", led->off_period) + 1;
+}
+
+static ssize_t omap_pwm_led_off_period_store(struct class_device *cdev,
+                                            const char *buf, size_t size)
+{
+       struct led_classdev *led_cdev = class_get_devdata(cdev);
+       struct omap_pwm_led *led = cdev_to_omap_pwm_led(led_cdev);
+       int ret = -EINVAL;
+       unsigned long val;
+       char *after;
+       size_t count;
+
+       val = simple_strtoul(buf, &after, 10);
+       count = after - buf;
+       if (*after && isspace(*after))
+               count++;
+
+       if (count == size) {
+               led->off_period = val;
+               omap_pwm_led_set_blink(led);
+               ret = count;
+       }
+
+       return ret;
+}
+
+static CLASS_DEVICE_ATTR(on_period, 0644, omap_pwm_led_on_period_show,
+                        omap_pwm_led_on_period_store);
+static CLASS_DEVICE_ATTR(off_period, 0644, omap_pwm_led_off_period_show,
+                        omap_pwm_led_off_period_store);
+
+static int omap_pwm_led_probe(struct platform_device *pdev)
+{
+       struct omap_pwm_led_platform_data *pdata = pdev->dev.platform_data;
+       struct omap_pwm_led *led;
+       int ret;
+
+       led = kzalloc(sizeof(struct omap_pwm_led), GFP_KERNEL);
+       if (led == NULL) {
+               dev_err(&pdev->dev, "No memory for device\n");
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(pdev, led);
+       led->cdev.brightness_set = omap_pwm_led_set;
+       led->cdev.default_trigger = NULL;
+       led->cdev.name = pdata->name;
+       led->pdata = pdata;
+
+       dev_info(&pdev->dev, "OMAP PWM LED (%s) at GP timer %d/%d\n",
+                pdata->name, pdata->intensity_timer, pdata->blink_timer);
+
+       /* register our new led device */
+       ret = led_classdev_register(&pdev->dev, &led->cdev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "led_classdev_register failed\n");
+               goto error_classdev;
+       }
+
+       /* get related dm timers */
+       led->intensity_timer = omap_dm_timer_request_specific(pdata->intensity_timer);
+       if (led->intensity_timer == NULL) {
+               dev_err(&pdev->dev, "failed to request intensity pwm timer\n");
+               ret = -ENODEV;
+               goto error_intensity;
+       }
+       omap_dm_timer_disable(led->intensity_timer);
+
+       if (pdata->blink_timer != 0) {
+               led->blink_timer = omap_dm_timer_request_specific(pdata->blink_timer);
+               if (led->blink_timer == NULL) {
+                       dev_err(&pdev->dev, "failed to request blinking pwm timer\n");
+                       ret = -ENODEV;
+                       goto error_blink1;
+               }
+               omap_dm_timer_disable(led->blink_timer);
+
+               ret = class_device_create_file(led->cdev.class_dev,
+                                              &class_device_attr_on_period);
+               if(ret)
+                       goto error_blink2;
+
+               ret = class_device_create_file(led->cdev.class_dev,
+                                               &class_device_attr_off_period);
+               if(ret)
+                       goto error_blink3;
+
+       }
+
+       return 0;
+
+error_blink3:
+       class_device_remove_file(led->cdev.class_dev,
+                                &class_device_attr_on_period);
+error_blink2:
+       dev_err(&pdev->dev, "failed to create device file(s)\n");
+error_blink1:
+       omap_dm_timer_free(led->intensity_timer);
+error_intensity:
+       led_classdev_unregister(&led->cdev);
+error_classdev:
+       kfree(led);
+       return ret;
+}
+
+static int omap_pwm_led_remove(struct platform_device *pdev)
+{
+       struct omap_pwm_led *led = pdev_to_omap_pwm_led(pdev);
+
+       class_device_remove_file(led->cdev.class_dev,
+                                &class_device_attr_on_period);
+       class_device_remove_file(led->cdev.class_dev,
+                                &class_device_attr_off_period);
+       led_classdev_unregister(&led->cdev);
+
+       omap_pwm_led_set(&led->cdev, LED_OFF);
+       if (led->blink_timer != NULL)
+               omap_dm_timer_free(led->blink_timer);
+       omap_dm_timer_free(led->intensity_timer);
+       kfree(led);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int omap_pwm_led_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct omap_pwm_led *led = pdev_to_omap_pwm_led(pdev);
+
+       led_classdev_suspend(&led->cdev);
+       return 0;
+}
+
+static int omap_pwm_led_resume(struct platform_device *pdev)
+{
+       struct omap_pwm_led *led = pdev_to_omap_pwm_led(pdev);
+
+       led_classdev_resume(&led->cdev);
+       return 0;
+}
+#else
+#define omap_pwm_led_suspend NULL
+#define omap_pwm_led_resume NULL
+#endif
+
+static struct platform_driver omap_pwm_led_driver = {
+       .probe          = omap_pwm_led_probe,
+       .remove         = omap_pwm_led_remove,
+       .suspend        = omap_pwm_led_suspend,
+       .resume         = omap_pwm_led_resume,
+       .driver         = {
+               .name           = "omap_pwm_led",
+               .owner          = THIS_MODULE,
+       },
+};
+
+static int __init omap_pwm_led_init(void)
+{
+       return platform_driver_register(&omap_pwm_led_driver);
+}
+
+static void __exit omap_pwm_led_exit(void)
+{
+       platform_driver_unregister(&omap_pwm_led_driver);
+}
+
+module_init(omap_pwm_led_init);
+module_exit(omap_pwm_led_exit);
+
+MODULE_AUTHOR("Timo Teras");
+MODULE_DESCRIPTION("OMAP PWM LED driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-omap.c b/drivers/leds/leds-omap.c
new file mode 100644 (file)
index 0000000..040b7e4
--- /dev/null
@@ -0,0 +1,135 @@
+/* drivers/leds/leds-omap.c
+ *
+ * (C) 2006 Samsung Electronics
+ * Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * OMAP - LEDs GPIO driver
+ *
+ * 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/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/led.h>
+
+/* our context */
+
+static void omap_set_led_gpio(struct led_classdev *led_cdev,
+                           enum led_brightness value)
+{
+       struct omap_led_config *led_dev;
+
+       led_dev = container_of(led_cdev, struct omap_led_config, cdev);
+
+       if (value)
+               omap_set_gpio_dataout(led_dev->gpio, 1);
+       else
+               omap_set_gpio_dataout(led_dev->gpio, 0);
+}
+
+static void omap_configure_led_gpio(int gpio)
+{
+       if (omap_request_gpio(gpio) < 0) {
+               printk(KERN_ERR "Failed to request GPIO%d for LEDs\n", gpio);
+               return;
+       }
+       omap_set_gpio_direction(gpio, 0);       /* OUT */
+}
+
+static int omap_led_probe(struct platform_device *dev)
+{
+       struct omap_led_platform_data *pdata = dev->dev.platform_data;
+       struct omap_led_config *leds = pdata->leds;
+       int i, ret = 0;
+
+       for (i = 0; ret >= 0 && i < pdata->nr_leds; i++) {
+               omap_configure_led_gpio(leds[i].gpio);
+               if (!leds[i].cdev.brightness_set)
+                       leds[i].cdev.brightness_set = omap_set_led_gpio;
+
+               ret = led_classdev_register(&dev->dev, &leds[i].cdev);
+       }
+
+       if (ret < 0 && i > 1) {
+               for (i = i - 2; i >= 0; i--)
+                       led_classdev_unregister(&leds[i].cdev);
+       }
+
+       return ret;
+}
+
+static int omap_led_remove(struct platform_device *dev)
+{
+       struct omap_led_platform_data *pdata = dev->dev.platform_data;
+       struct omap_led_config *leds = pdata->leds;
+       int i;
+
+       for (i = 0; i < pdata->nr_leds; i++)
+               led_classdev_unregister(&leds[i].cdev);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int omap_led_suspend(struct platform_device *dev, pm_message_t state)
+{
+       struct omap_led_platform_data *pdata = dev->dev.platform_data;
+       struct omap_led_config *leds = pdata->leds;
+       int i;
+
+       for (i = 0; i < pdata->nr_leds; i++)
+               led_classdev_suspend(&leds[i].cdev);
+
+       return 0;
+}
+
+static int omap_led_resume(struct platform_device *dev)
+{
+       struct omap_led_platform_data *pdata = dev->dev.platform_data;
+       struct omap_led_config *leds = pdata->leds;
+       int i;
+
+       for (i = 0; i < pdata->nr_leds; i++)
+               led_classdev_resume(&leds[i].cdev);
+
+       return 0;
+}
+#else
+#define omap_led_suspend       NULL
+#define omap_led_resume                NULL
+#endif
+
+static struct platform_driver omap_led_driver = {
+       .probe          = omap_led_probe,
+       .remove         = omap_led_remove,
+       .suspend        = omap_led_suspend,
+       .resume         = omap_led_resume,
+       .driver         = {
+               .name           = "omap-led",
+               .owner          = THIS_MODULE,
+       },
+};
+
+static int __init omap_led_init(void)
+{
+       return platform_driver_register(&omap_led_driver);
+}
+
+static void __exit omap_led_exit(void)
+{
+       platform_driver_unregister(&omap_led_driver);
+}
+
+module_init(omap_led_init);
+module_exit(omap_led_exit);
+
+MODULE_AUTHOR("Kyungmin Park<kyungmin.park@samsung.com>");
+MODULE_DESCRIPTION("OMAP LED driver");
+MODULE_LICENSE("GPL");
index 57357db31b8a7b58a841252fe7912b57e199a9b8..fea92e0bf266e21145a5acb3a9e451f7b6895a65 100644 (file)
@@ -763,4 +763,6 @@ source "drivers/media/video/pwc/Kconfig"
 
 endmenu # V4L USB devices
 
+source drivers/media/video/omap/Kconfig
+
 endmenu
index 9b1f3f06bb7ce267d5dc868be48b4e2dd6965cc4..9817c19dfe6595e568a261ba352bb4eecf4997b8 100644 (file)
@@ -85,6 +85,7 @@ obj-$(CONFIG_VIDEO_BTCX)  += btcx-risc.o
 obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
 
 obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
+obj-$(CONFIG_VIDEO_OMAP_CAMERA) += omap/
 
 obj-$(CONFIG_VIDEO_CX25840) += cx25840/
 obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
diff --git a/drivers/media/video/omap/Kconfig b/drivers/media/video/omap/Kconfig
new file mode 100644 (file)
index 0000000..809193b
--- /dev/null
@@ -0,0 +1,12 @@
+config VIDEO_OMAP_CAMERA
+       tristate "OMAP Camera support (EXPERIMENTAL)"
+       select VIDEO_BUF
+       depends on VIDEO_DEV && (ARCH_OMAP16XX || ARCH_OMAP24XX)
+       help
+         V4L2 camera driver support for OMAP1/2 based boards.
+       
+config VIDEO_CAMERA_SENSOR_OV9640
+       tristate "OV9640 sensor support"
+       depends on VIDEO_OMAP_CAMERA
+       help
+         OmniVision 9640 camera sensor support
diff --git a/drivers/media/video/omap/Makefile b/drivers/media/video/omap/Makefile
new file mode 100644 (file)
index 0000000..36ae615
--- /dev/null
@@ -0,0 +1,12 @@
+# Makefile for OMAP1/2 camera driver
+
+obj-$(CONFIG_VIDEO_OMAP_CAMERA) += omapcamera.o
+obj-$(CONFIG_VIDEO_CAMERA_SENSOR_OV9640) += sensor_ov9640.o
+
+objs-y$(CONFIG_ARCH_OMAP16XX) += omap16xxcam.o camera_core.o
+objs-y$(CONFIG_MACH_OMAP_H3) += h3_sensor_power.o
+objs-y$(CONFIG_MACH_OMAP_H4) += h4_sensor_power.o
+
+omapcamera-objs := $(objs-yy)
+
+EXTRA_CFLAGS = -I$(src)/..
diff --git a/drivers/media/video/omap/camera_core.c b/drivers/media/video/omap/camera_core.c
new file mode 100644 (file)
index 0000000..9440718
--- /dev/null
@@ -0,0 +1,1193 @@
+/*
+ * drivers/media/video/omap/camera_core.c
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc. 
+ *
+ * Video-for-Linux (Version 2) camera capture driver for
+ * the OMAP H2 and H3 camera controller.
+ *
+ * Adapted from omap24xx driver written by Andy Lowe (source@mvista.com)
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ * 
+ * This package 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. 
+ * 
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 
+ *
+ * History:
+ *   27/03/05   Vladimir Barinov - Added support for power management
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/version.h>
+#include <linux/dma-mapping.h>
+#include <linux/fb.h>
+
+#include <media/v4l2-common.h>
+
+#include <asm/io.h>
+
+#include "sensor_if.h"
+#include "camera_hw_if.h"
+#include "camera_core.h"
+
+
+static struct camera_device *camera_dev;
+static void camera_core_sgdma_process(struct camera_device *cam);
+
+/* module parameters */
+static int video_nr = -1;      /* video device minor (-1 ==> auto assign) */
+
+/* Maximum amount of memory to use for capture buffers.
+ * Default is 4800KB, enough to double-buffer SXGA.
+ */
+static int capture_mem = 1280*960*2*2;
+
+/*Size of video overlay framebuffer. This determines the maximum image size
+ *that can be previewed. Default is 600KB, enough for sxga.
+ */
+static int overlay_mem = 640*480*2;
+
+/* DMA completion routine for the scatter-gather DMA fragments. */
+/* This function is called when a scatter DMA fragment is completed */
+static void
+camera_core_callback_sgdma(void *arg1, void *arg2)
+{
+       struct camera_device *cam = (struct camera_device *)arg1;
+       int sgslot = (int)arg2;
+
+       struct sgdma_state *sgdma;
+
+       spin_lock(&cam->sg_lock);
+       sgdma = cam->sgdma + sgslot;
+       if (!sgdma->queued_sglist)
+       {
+               spin_unlock(&cam->sg_lock);
+               printk(KERN_ERR CAM_NAME ": SGDMA completed when none queued\n");
+               return;
+       }
+       if (!--sgdma->queued_sglist) {
+               /* queue for this sglist is empty so check whether transfer
+               ** of the frame has been completed */
+               if (sgdma->next_sglist == sgdma->sglen) {
+                       dma_callback_t callback = sgdma->callback;
+                       void *arg = sgdma->arg;
+                       /* all done with this sglist */
+                       cam->free_sgdma++;
+                       if (callback) {
+                               spin_unlock(&cam->sg_lock);
+                               (*callback)(cam, arg);
+                               camera_core_sgdma_process(cam);
+                               return;
+                       }
+               }
+       }
+       spin_unlock(&cam->sg_lock);
+       camera_core_sgdma_process(cam);
+
+       return;
+}
+
+static void
+camera_core_sgdma_init(struct camera_device *cam)
+{
+       int sg;
+
+       /* Initialize the underlying camera DMA */
+       cam->cam_hardware->init_dma(cam->hardware_data);
+       spin_lock_init(&cam->sg_lock);
+       
+       cam->free_sgdma = NUM_SG_DMA;
+       cam->next_sgdma = 0;
+       for (sg = 0; sg < NUM_SG_DMA; sg++) {
+               cam->sgdma[sg].sglen = 0;
+               cam->sgdma[sg].next_sglist = 0;
+               cam->sgdma[sg].queued_sglist = 0;
+               cam->sgdma[sg].csr = 0;
+               cam->sgdma[sg].callback = NULL;
+               cam->sgdma[sg].arg = NULL;
+       }
+}
+
+/*
+ * Process the scatter-gather DMA queue by starting queued transfers
+ * This function is called to program the dma to start the transfer of an image.
+ */
+static void
+camera_core_sgdma_process(struct camera_device *cam)
+{
+       unsigned long irqflags;
+       int queued_sgdma, sgslot;
+       struct sgdma_state *sgdma;
+       const struct scatterlist *sglist;
+       
+       spin_lock_irqsave(&cam->sg_lock, irqflags);
+       if (1 == cam->in_use) {
+               spin_unlock_irqrestore(&cam->sg_lock, irqflags);
+               return;
+       }
+       cam->in_use = 1;
+       spin_unlock_irqrestore(&cam->sg_lock, irqflags);
+
+       queued_sgdma = NUM_SG_DMA - cam->free_sgdma;
+       sgslot = (cam->next_sgdma + cam->free_sgdma) % (NUM_SG_DMA);
+       while (queued_sgdma > 0) {
+               sgdma = cam->sgdma + sgslot;
+               while (sgdma->next_sglist < sgdma->sglen) {
+                       sglist = sgdma->sglist + sgdma->next_sglist;
+                       if (cam->cam_hardware->start_dma(sgdma, camera_core_callback_sgdma,
+                               (void *)cam, (void *)sgslot, cam->hardware_data)) {
+                                       /* dma start failed */
+                                       cam->in_use = 0;
+                                       return;
+                       }
+                       else {
+                               /* dma start successful */
+                               sgdma->next_sglist ++;
+                               sgdma->queued_sglist ++;
+                       }
+               }
+               queued_sgdma-- ;
+               sgslot = (sgslot + 1) % (NUM_SG_DMA);
+       }
+
+       cam->in_use = 0;
+}
+
+/* Queue a scatter-gather DMA transfer from the camera to memory.
+ * Returns zero if the transfer was successfully queued, or
+ * non-zero if all of the scatter-gather slots are already in use.
+ */
+static int
+camera_core_sgdma_queue(struct camera_device *cam,
+        const struct scatterlist *sglist, int sglen, dma_callback_t callback,
+        void *arg)
+{
+       unsigned long irqflags;
+       struct sgdma_state *sgdma;
+
+       if ((sglen < 0) || ((sglen > 0) & !sglist))
+               return -EINVAL;
+
+       spin_lock_irqsave(&cam->sg_lock, irqflags);
+
+       if (!cam->free_sgdma) {
+               spin_unlock_irqrestore(&cam->sg_lock, irqflags);
+               return -EBUSY;
+       }
+
+       sgdma = cam->sgdma + cam->next_sgdma;
+
+       sgdma->sglist = sglist;
+       sgdma->sglen = sglen;
+       sgdma->next_sglist = 0;
+       sgdma->queued_sglist = 0;
+       sgdma->csr = 0;
+       sgdma->callback = callback;
+       sgdma->arg = arg;
+
+       cam->next_sgdma = (cam->next_sgdma + 1) % (NUM_SG_DMA); 
+       cam->free_sgdma--;
+
+       spin_unlock_irqrestore(&cam->sg_lock, irqflags);
+
+       camera_core_sgdma_process(cam);
+
+       return 0;
+}
+
+
+/* -------------------overlay routines ------------------------------*/
+/* callback routine for overlay DMA completion. We just start another DMA
+ * transfer unless overlay has been turned off
+ */
+
+static void
+camera_core_overlay_callback(void *arg1, void *arg)
+{
+       struct camera_device *cam = (struct camera_device *)arg1;
+       int err;
+       unsigned long irqflags;
+       int i, j;
+       int count, index;
+       unsigned char *fb_buf = phys_to_virt((unsigned long)camera_dev->fbuf.base);
+
+       spin_lock_irqsave(&cam->overlay_lock, irqflags);
+
+       if (!cam->previewing || cam->overlay_cnt == 0) {
+               spin_unlock_irqrestore(&cam->overlay_lock, irqflags);
+               return;
+       }
+
+       --cam->overlay_cnt;
+       sg_dma_address(&cam->overlay_sglist) = cam->overlay_base_phys;
+       sg_dma_len(&cam->overlay_sglist) = cam->pix.sizeimage;
+
+       count = 0;
+       j = ((cam->pix.width - 1) * cam->fbuf.fmt.bytesperline);
+       for (i = 0 ; i < cam->pix.sizeimage; i += cam->pix.bytesperline) {
+               for (index = 0; index < cam->pix.bytesperline; index++) {
+                       fb_buf[j] = *(((unsigned char *) cam->overlay_base) +
+                                                                i + index);
+                       index++;
+                       fb_buf[j + 1] = *(((unsigned char *) cam->overlay_base) + i + index);
+                       j = j - cam->fbuf.fmt.bytesperline;
+               }
+               count += 2;
+               j = ((cam->pix.width - 1) * cam->fbuf.fmt.bytesperline) + count;
+       }
+
+       while (cam->overlay_cnt < 2) {
+               err = camera_core_sgdma_queue(cam, &cam->overlay_sglist, 1,
+                       camera_core_overlay_callback, NULL);
+               if (err)
+                       break;
+               ++cam->overlay_cnt;
+       }
+
+       spin_unlock_irqrestore(&cam->overlay_lock, irqflags);
+
+}
+
+static void
+camera_core_start_overlay(struct camera_device *cam)
+{
+       int err;
+       unsigned long irqflags;
+
+       if (!cam->previewing) 
+               return;
+
+       spin_lock_irqsave(&cam->overlay_lock, irqflags);
+
+       sg_dma_address(&cam->overlay_sglist) = cam->overlay_base_phys;
+       sg_dma_len(&cam->overlay_sglist)= cam->pix.sizeimage;
+       while (cam->overlay_cnt < 2) {
+               err = camera_core_sgdma_queue(cam, &cam->overlay_sglist, 1,
+                               camera_core_overlay_callback, NULL);
+               if (err)
+                       break;
+               ++cam->overlay_cnt;
+       }
+
+       spin_unlock_irqrestore(&cam->overlay_lock, irqflags);
+}
+
+/* ------------------ videobuf_queue_ops ---------------------------------------- */
+
+/* This routine is called from interrupt context when a scatter-gather DMA
+ * transfer of a videobuf_buffer completes.
+ */
+static void
+camera_core_vbq_complete(void *arg1, void *arg)
+{
+       struct camera_device *cam = (struct camera_device *)arg1;
+       struct videobuf_buffer *vb = (struct videobuf_buffer *)arg;
+
+       spin_lock(&cam->vbq_lock);
+
+       do_gettimeofday(&vb->ts);
+       vb->field_count = cam->field_count;
+       cam->field_count += 2;
+       vb->state = STATE_DONE;
+
+       wake_up(&vb->done);
+       
+       spin_unlock(&cam->vbq_lock);
+}
+
+static void
+camera_core_vbq_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+       videobuf_waiton(vb, 0, 0);
+       videobuf_dma_unmap(q, &vb->dma);
+       videobuf_dma_free(&vb->dma);
+
+       vb->state = STATE_NEEDS_INIT;
+}
+
+/* Limit the number of available kernel image capture buffers based on the
+ * number requested, the currently selected image size, and the maximum
+ * amount of memory permitted for kernel capture buffers.
+ */
+static int
+camera_core_vbq_setup(struct videobuf_queue *q, unsigned int *cnt, unsigned int *size)
+{
+       struct camera_device *cam = q->priv_data;
+
+       if (*cnt <= 0)
+               *cnt = VIDEO_MAX_FRAME; /* supply a default number of buffers */
+
+       if (*cnt > VIDEO_MAX_FRAME)
+               *cnt = VIDEO_MAX_FRAME;
+
+       spin_lock(&cam->img_lock);
+       *size = cam->pix.sizeimage;
+       spin_unlock(&cam->img_lock);
+
+       while (*size * *cnt > capture_mem)
+               (*cnt)--;
+
+       return 0;
+}
+
+static int
+camera_core_vbq_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+        enum v4l2_field field)
+{
+       struct camera_device *cam = q->priv_data;
+       int err = 0;
+
+       spin_lock(&cam->img_lock);
+       if (cam->pix.sizeimage > vb->bsize) {
+               spin_unlock(&cam->img_lock);
+               return -EINVAL;
+       }
+       vb->size = cam->pix.sizeimage; 
+       vb->width = cam->pix.width;
+       vb->height = cam->pix.height;
+       vb->field = field;
+       spin_unlock(&cam->img_lock);
+
+       if (vb->state == STATE_NEEDS_INIT)
+               err = videobuf_iolock(q, vb, NULL);
+
+       if (!err)
+               vb->state = STATE_PREPARED;
+       else
+               camera_core_vbq_release (q, vb);
+
+       return err;
+}
+
+static void
+camera_core_vbq_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+       struct camera_device *cam = q->priv_data;
+       enum videobuf_state state = vb->state;
+       int err;
+
+       vb->state = STATE_QUEUED;
+       err = camera_core_sgdma_queue(cam, vb->dma.sglist, vb->dma.sglen,
+                camera_core_vbq_complete, vb);
+       if (err) {
+               /* Oops.  We're not supposed to get any errors here.  The only
+               * way we could get an error is if we ran out of scatter-gather
+               * DMA slots, but we are supposed to have at least as many
+               * scatter-gather DMA slots as video buffers so that can't
+               * happen.
+               */
+               printk(KERN_DEBUG CAM_NAME
+                       ": Failed to queue a video buffer for SGDMA\n");
+               vb->state = state;
+       }
+}
+
+/* ------------------ videobuf_queue_ops ---------------------------------------- */
+
+static int
+camera_core_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, 
+                    void *arg)
+{
+       struct camera_fh *fh  = file->private_data;
+       struct camera_device *cam = fh->cam;
+       int err;
+
+       switch (cmd) {
+               case VIDIOC_ENUMINPUT:
+               {
+                       /* default handler assumes 1 video input (the camera) */
+                       struct v4l2_input *input = (struct v4l2_input *)arg;
+                       int index = input->index;
+
+                       memset(input, 0, sizeof(*input));
+                       input->index = index;
+
+                       if (index > 0)
+                               return -EINVAL;
+
+                       strlcpy(input->name, "camera", sizeof(input->name));
+                       input->type = V4L2_INPUT_TYPE_CAMERA;
+
+                       return 0;
+               }
+
+               case VIDIOC_G_INPUT:
+               {
+                       unsigned int *input = arg;
+                       *input = 0;
+
+                       return 0;
+               }
+
+               case VIDIOC_S_INPUT:
+               {
+                       unsigned int *input = arg;
+
+                       if (*input > 0)
+                               return -EINVAL;
+
+                       return 0;
+               }
+
+               case VIDIOC_ENUM_FMT:
+               {
+                       struct v4l2_fmtdesc *fmt = arg;
+                       return cam->cam_sensor->enum_pixformat(fmt, cam->sensor_data);
+               }       
+
+               case VIDIOC_TRY_FMT:
+               {
+                       struct v4l2_format *fmt = arg;
+                       return cam->cam_sensor->try_format(&fmt->fmt.pix, cam->sensor_data);
+
+               }
+
+               case VIDIOC_G_FMT:
+               {
+                       struct v4l2_format *fmt = arg;
+
+                       /* get the current format */
+                       memset(&fmt->fmt.pix, 0, sizeof (fmt->fmt.pix));
+                       fmt->fmt.pix = cam->pix;
+                       
+                       return 0;
+               }
+
+               case VIDIOC_S_FMT:
+               {
+                       struct v4l2_format *fmt = arg;
+                       unsigned int temp_sizeimage = 0;
+
+                       temp_sizeimage = cam->pix.sizeimage;
+                       cam->cam_sensor->try_format(&fmt->fmt.pix, cam->sensor_data);
+                       cam->pix = fmt->fmt.pix;
+
+                       cam->xclk = cam->cam_sensor->calc_xclk(&cam->pix,
+                               &cam->nominal_timeperframe, cam->sensor_data);
+                       cam->cparm.timeperframe = cam->nominal_timeperframe;
+                       cam->xclk = cam->cam_hardware->set_xclk(cam->xclk, cam->hardware_data);
+                       return cam->cam_sensor->configure(&cam->pix, cam->xclk, 
+                                               &cam->cparm.timeperframe, cam->sensor_data);
+               }
+
+               case VIDIOC_QUERYCTRL:
+               {
+                       struct v4l2_queryctrl *qc = arg;
+                       return cam->cam_sensor->query_control(qc, cam->sensor_data);
+               }
+
+               case VIDIOC_G_CTRL:
+               {
+                       struct v4l2_control *vc = arg;
+                       return cam->cam_sensor->get_control(vc, cam->sensor_data);
+               }
+
+               case VIDIOC_S_CTRL:
+               {
+                       struct v4l2_control *vc = arg;
+                       return cam->cam_sensor->set_control(vc, cam->sensor_data);
+               }
+               
+               case VIDIOC_QUERYCAP:
+               {
+                       struct v4l2_capability *cap = 
+                               (struct v4l2_capability *) arg;
+
+                       memset(cap, 0, sizeof(*cap));
+                       strlcpy(cap->driver, CAM_NAME, sizeof(cap->driver));
+                       strlcpy(cap->card, cam->vfd->name, sizeof(cap->card));
+                       cap->bus_info[0] = '\0';
+                       cap->version = KERNEL_VERSION(0, 0, 0);
+                       cap->capabilities =
+                               V4L2_CAP_VIDEO_CAPTURE |
+                               V4L2_CAP_VIDEO_OVERLAY |
+                               V4L2_CAP_READWRITE | 
+                               V4L2_CAP_STREAMING;
+                       return 0;
+               }
+
+               case VIDIOC_G_FBUF: /* Get the frame buffer parameters */
+               {
+                       struct v4l2_framebuffer *fbuf =
+                               (struct v4l2_framebuffer *) arg;
+
+                       spin_lock(&cam->img_lock);
+                       *fbuf = cam->fbuf;
+                       spin_unlock(&cam->img_lock);
+                       return 0;
+               }
+
+               case VIDIOC_S_FBUF: /* set the frame buffer parameters */
+               {
+                       struct v4l2_framebuffer *fbuf =
+                               (struct v4l2_framebuffer *) arg;
+
+                       spin_lock(&cam->img_lock);
+                       if (cam->previewing) {
+                               spin_unlock(&cam->img_lock);
+                               return -EBUSY;
+                       }
+                       cam->fbuf.base = fbuf->base;
+                       cam->fbuf.fmt = fbuf->fmt;      
+                       
+                       spin_unlock(&cam->img_lock);
+                       return 0;
+               }
+
+               case VIDIOC_OVERLAY:
+               {
+                       int enable = *((int *) arg);
+
+                       /* 
+                        * check whether the capture format and 
+                        ** the display format matches 
+                        * return failure if they are different
+                        */
+                       if (cam->pix.pixelformat != cam->fbuf.fmt.pixelformat)
+                       {
+                               return -EINVAL;
+                       }
+
+                       /* If the camera image size is greater 
+                       ** than LCD size return failure */
+                       if ((cam->pix.width > cam->fbuf.fmt.height) || 
+                               (cam->pix.height > cam->fbuf.fmt.width))
+                       {
+                               return -EINVAL;
+                       }
+                       
+                       if (!cam->previewing && enable)
+                       {
+                               cam->previewing = fh;
+                               cam->overlay_cnt = 0;
+                               camera_core_start_overlay(cam);
+                       }
+                       else if (!enable)
+                       {
+                               cam->previewing = NULL;
+                       }
+       
+                       return 0;
+               }
+
+               case VIDIOC_REQBUFS:
+                       return videobuf_reqbufs(&fh->vbq, arg);
+
+               case VIDIOC_QUERYBUF:
+                       return videobuf_querybuf(&fh->vbq, arg);
+
+               case VIDIOC_QBUF:
+                       return videobuf_qbuf(&fh->vbq, arg);
+
+               case VIDIOC_DQBUF:
+                       return videobuf_dqbuf(&fh->vbq, arg,
+          file->f_flags & O_NONBLOCK);
+
+               case VIDIOC_STREAMON:
+               {
+                       spin_lock(&cam->img_lock);
+
+                       if (cam->streaming || cam->reading) {
+                               spin_unlock(&cam->img_lock);
+                               return -EBUSY;
+                       }
+                       else {
+                               cam->streaming = fh;
+                               /* FIXME: start camera interface */
+                       }
+
+                       spin_unlock(&cam->img_lock);
+
+                       return videobuf_streamon(&fh->vbq);
+               }
+               case VIDIOC_STREAMOFF:
+               {
+                       err = videobuf_streamoff(&fh->vbq);
+                       if (err < 0)
+                               return err;
+
+                       spin_lock(&cam->img_lock);
+                       if (cam->streaming == fh) {
+                               cam->streaming = NULL;
+                               /* FIXME: stop camera interface */
+                       }
+                       spin_unlock(&cam->img_lock);
+                       return 0;
+               }
+               case VIDIOC_ENUMSTD:
+               case VIDIOC_G_STD:
+               case VIDIOC_S_STD:
+               case VIDIOC_QUERYSTD:
+               {
+                       /* Digital cameras don't have an analog video standard, 
+                        * so we don't need to implement these ioctls.
+                        */
+                        return -EINVAL;
+               }
+               case VIDIOC_G_AUDIO:
+               case VIDIOC_S_AUDIO:
+               case VIDIOC_G_AUDOUT:
+               case VIDIOC_S_AUDOUT:
+               {
+                       /* we don't have any audio inputs or outputs */
+                       return -EINVAL;
+               }
+
+               case VIDIOC_G_JPEGCOMP:
+               case VIDIOC_S_JPEGCOMP:
+               {
+                       /* JPEG compression is not supported */
+                       return -EINVAL;
+               }
+
+               case VIDIOC_G_TUNER:
+               case VIDIOC_S_TUNER:
+               case VIDIOC_G_MODULATOR:
+               case VIDIOC_S_MODULATOR:
+               case VIDIOC_G_FREQUENCY:
+               case VIDIOC_S_FREQUENCY:
+               {
+                       /* we don't have a tuner or modulator */
+                       return -EINVAL;
+               }
+
+               case VIDIOC_ENUMOUTPUT:
+               case VIDIOC_G_OUTPUT:
+               case VIDIOC_S_OUTPUT:
+               {
+                       /* we don't have any video outputs */
+                       return -EINVAL;
+               }
+
+               default:
+               {
+                       /* unrecognized ioctl */
+                       return -ENOIOCTLCMD;
+               }
+       }
+       return 0;
+}
+
+/*
+ *  file operations
+ */
+
+static unsigned
+int camera_core_poll(struct file *file, struct poll_table_struct *wait)
+{
+       return -EINVAL;
+}
+
+/* ------------------------------------------------------------ */
+/* callback routine for read DMA completion. We just start another DMA
+ * transfer unless overlay has been turned off
+ */
+static void
+camera_core_capture_callback(void *arg1, void *arg)
+{
+       struct camera_device *cam = (struct camera_device *)arg1;
+       int err;
+       unsigned long irqflags;
+       static int done = 0;
+
+       spin_lock_irqsave(&cam->capture_lock, irqflags);
+       if (!cam->reading)
+       {
+               done = 0;
+               cam->capture_started = 0;
+               spin_unlock_irqrestore(&cam->capture_lock, irqflags);
+               return;
+       }
+
+       if (done < 14) {
+               ++done;
+               sg_dma_address(&cam->capture_sglist) = cam->capture_base_phys;
+               sg_dma_len(&cam->capture_sglist) = cam->pix.sizeimage;
+               err = camera_core_sgdma_queue(cam, &cam->capture_sglist, 1,
+                       camera_core_capture_callback, NULL);            
+       } else {
+               cam->capture_completed = 1;
+               if (cam->reading)
+               {
+                       /* Wake up any process which are waiting for the 
+                       ** DMA to complete */
+                       wake_up_interruptible(&camera_dev->new_video_frame);
+                       sg_dma_address(&cam->capture_sglist) = cam->capture_base_phys;
+                       sg_dma_len(&cam->capture_sglist) = cam->pix.sizeimage;
+                       err = camera_core_sgdma_queue(cam, &cam->capture_sglist, 1,
+                               camera_core_capture_callback, NULL);
+               }
+       }
+
+       spin_unlock_irqrestore(&cam->capture_lock, irqflags);
+}
+
+static ssize_t
+camera_core_read(struct file *file, char *data, size_t count, loff_t *ppos)
+{
+       struct camera_fh *fh = file->private_data;
+       struct camera_device *cam = fh->cam;
+       int err;
+       unsigned long irqflags;
+       long timeout;
+#if 0  /* use video_buf to do capture */
+       int i;
+       for (i = 0; i < 14; i++)
+               videobuf_read_one(file, &fh->vbq, data, count, ppos);
+       i = videobuf_read_one(file, &fh->vbq, data, count, ppos);
+       return i;
+#endif
+       
+       if (!cam->capture_base) {
+               cam->capture_base = (unsigned long)dma_alloc_coherent(NULL,
+                               cam->pix.sizeimage,
+                               (dma_addr_t *) &cam->capture_base_phys,
+                               GFP_KERNEL | GFP_DMA);
+       }
+       if (!cam->capture_base) {
+               printk(KERN_ERR CAM_NAME
+                       ": cannot allocate capture buffer\n");
+               return 0;
+       }
+
+       spin_lock_irqsave(&cam->capture_lock, irqflags);
+       cam->reading = fh;
+       cam->capture_started = 1;
+       sg_dma_address(&cam->capture_sglist) = cam->capture_base_phys;
+       sg_dma_len(&cam->capture_sglist)= cam->pix.sizeimage;
+       spin_unlock_irqrestore(&cam->capture_lock, irqflags);
+
+       err = camera_core_sgdma_queue(cam, &cam->capture_sglist, 1,
+                       camera_core_capture_callback, NULL);
+
+       /* Wait till DMA is completed */
+       timeout = HZ * 10;
+       cam->capture_completed = 0;
+       while (cam->capture_completed == 0) {
+               timeout = interruptible_sleep_on_timeout 
+                               (&cam->new_video_frame, timeout);
+               if (timeout == 0) {
+                       printk(KERN_ERR CAM_NAME ": timeout waiting video frame\n");    
+                       return -EIO; /* time out */
+               }
+       }
+       /* copy the data to the user buffer */
+       err = copy_to_user(data, (void *)cam->capture_base, cam->pix.sizeimage);
+       return (cam->pix.sizeimage - err);
+       
+}
+
+static int
+camera_core_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct camera_fh *fh = file->private_data;
+
+       return videobuf_mmap_mapper(&fh->vbq, vma);
+}
+
+static int
+camera_core_ioctl(struct inode *inode, struct file *file, unsigned int cmd, 
+                 unsigned long arg)
+{
+
+       return video_usercopy(inode, file, cmd, arg, camera_core_do_ioctl);
+}
+
+static int
+camera_core_release(struct inode *inode, struct file *file)
+{
+       struct camera_fh *fh = file->private_data;
+       struct camera_device *cam = fh->cam;
+       
+       file->private_data = NULL;
+       kfree(fh);
+
+       spin_lock(&cam->img_lock);
+       if (cam->previewing == fh) {
+               cam->previewing = NULL;
+       }
+       if (cam->streaming == fh) {
+               cam->streaming = NULL;
+       }
+       if (cam->reading == fh) {
+               cam->reading = NULL;
+       }
+       spin_unlock(&cam->img_lock);
+
+       camera_dev->cam_hardware->finish_dma(cam->hardware_data);
+
+       if (cam->capture_base) {
+               dma_free_coherent(NULL, cam->pix.sizeimage, 
+                                       (void *)cam->capture_base, 
+                                       cam->capture_base_phys);
+               cam->capture_base = 0;
+               cam->capture_base_phys = 0;
+       }
+       if (fh->vbq.read_buf) {
+               camera_core_vbq_release(&fh->vbq, fh->vbq.read_buf);
+               kfree(fh->vbq.read_buf);
+       }
+
+       cam->cam_hardware->close(cam->hardware_data);
+       cam->active = 0;
+       return 0;
+}
+
+static int
+camera_core_open(struct inode *inode, struct file *file)
+{
+       int minor = iminor(inode);
+       struct camera_device *cam = camera_dev;
+       struct camera_fh *fh;
+
+       if (!cam || !cam->vfd || (cam->vfd->minor != minor))
+               return -ENODEV;
+
+       /* allocate per-filehandle data */
+       fh = kmalloc(sizeof(*fh), GFP_KERNEL);
+       if (NULL == fh)
+               return -ENOMEM;
+       file->private_data = fh;
+       fh->cam = cam;
+       fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       spin_lock(&cam->img_lock);
+       if (cam->active == 1) {
+               printk (KERN_ERR CAM_NAME ": Camera device Active\n");
+               spin_unlock(&cam->img_lock);
+               return -EPERM;
+       }
+       cam->active = 1;
+       spin_unlock(&cam->img_lock);
+
+       videobuf_queue_init(&fh->vbq, &cam->vbq_ops, NULL, &cam->vbq_lock,
+               fh->type, V4L2_FIELD_NONE, sizeof(struct videobuf_buffer), fh);
+
+       cam->capture_completed = 0;
+       cam->capture_started = 0;
+
+       if (cam->cam_hardware->open(cam->hardware_data))
+       {
+               printk (KERN_ERR CAM_NAME ": Camera IF configuration failed\n");
+               cam->active = 0;
+               return -ENODEV;
+       }
+       
+       cam->xclk = cam->cam_hardware->set_xclk(cam->xclk, cam->hardware_data);
+       /* program the sensor for the capture format and rate */
+       if (cam->cam_sensor->configure(&cam->pix, cam->xclk, 
+                               &cam->cparm.timeperframe, cam->sensor_data))
+       {
+               printk (KERN_ERR CAM_NAME ": Camera sensor configuration failed\n");
+               cam->cam_hardware->close(cam->hardware_data);
+               cam->active = 0;
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int camera_core_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct camera_device *cam = platform_get_drvdata(pdev);
+       int ret = 0;
+
+       spin_lock(&cam->img_lock);
+       if (cam->active) {
+               cam->cam_hardware->close(cam->hardware_data);
+       }
+       cam->cam_sensor->power_off(cam->sensor_data);
+       spin_unlock(&cam->img_lock);
+
+       return ret;
+}
+
+static int camera_core_resume(struct platform_device *pdev)
+{
+       struct camera_device *cam = platform_get_drvdata(pdev);
+       int ret = 0;
+
+       spin_lock(&cam->img_lock);
+       cam->cam_sensor->power_on(cam->sensor_data);
+       if (cam->active) {
+               cam->capture_completed = 1;
+               cam->cam_hardware->open(cam->hardware_data);
+               cam->cam_hardware->set_xclk(cam->xclk, cam->hardware_data);
+
+               cam->cam_sensor->configure(&cam->pix, cam->xclk,
+                                          &cam->cparm.timeperframe,
+                                          cam->sensor_data);
+               camera_core_sgdma_process(cam);
+       }
+       spin_unlock(&cam->img_lock);
+       
+       return ret;
+}
+#endif /* CONFIG_PM */
+
+static struct file_operations camera_core_fops = 
+{
+       .owner                  = THIS_MODULE,
+       .llseek                 = no_llseek,
+       .read                   = camera_core_read,
+       .poll                   = camera_core_poll,
+       .ioctl                  = camera_core_ioctl,
+       .mmap                   = camera_core_mmap,
+       .open                   = camera_core_open,
+       .release                = camera_core_release,
+};
+
+static int __init camera_core_probe(struct platform_device *pdev)
+{
+       struct camera_device *cam;
+       struct video_device *vfd;
+       int     status;
+
+       cam = kzalloc(sizeof(struct camera_device), GFP_KERNEL);
+       if (!cam) {
+               printk(KERN_ERR CAM_NAME ": could not allocate memory\n");
+               status = -ENOMEM;
+               goto err0;
+       }
+
+       /* Save the pointer to camera device in a global variable */
+       camera_dev = cam;
+       
+       /* initialize the video_device struct */
+       vfd = cam->vfd = video_device_alloc();
+       if (!vfd) {
+               printk(KERN_ERR CAM_NAME 
+                       ": could not allocate video device struct\n");
+               status = -ENOMEM;
+               goto err1;
+       }
+       
+       vfd->release = video_device_release;
+
+       strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name));
+       vfd->type = VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CHROMAKEY;
+       
+       /* need to register for a VID_HARDWARE_* ID in videodev.h */
+       vfd->hardware = 0;
+       vfd->fops = &camera_core_fops;
+       video_set_drvdata(vfd, cam);
+       vfd->minor = -1;
+
+       /* initialize the videobuf queue ops */
+       cam->vbq_ops.buf_setup = camera_core_vbq_setup;
+       cam->vbq_ops.buf_prepare = camera_core_vbq_prepare;
+       cam->vbq_ops.buf_queue = camera_core_vbq_queue;
+       cam->vbq_ops.buf_release = camera_core_vbq_release;
+
+       /* initilize the overlay interface */
+       cam->overlay_size = overlay_mem;
+       if (cam->overlay_size > 0)
+       {
+               cam->overlay_base = (unsigned long) dma_alloc_coherent(NULL,
+                                       cam->overlay_size,
+                                       (dma_addr_t *) &cam->overlay_base_phys,
+                                       GFP_KERNEL | GFP_DMA);
+               if (!cam->overlay_base) {
+                       printk(KERN_ERR CAM_NAME
+                               ": cannot allocate overlay framebuffer\n");
+                       status = -ENOMEM;
+                       goto err2;
+               }
+       }
+       memset((void*)cam->overlay_base, 0, cam->overlay_size);
+       spin_lock_init(&cam->overlay_lock);
+       spin_lock_init(&cam->capture_lock);
+
+       /*Initialise the pointer to the sensor interface and camera interface */
+       cam->cam_sensor = &camera_sensor_if;
+       cam->cam_hardware = &camera_hardware_if;
+
+       /* initialize the camera interface */
+       cam->hardware_data = cam->cam_hardware->init();
+       if (!cam->hardware_data) {
+               printk(KERN_ERR CAM_NAME ": cannot initialize interface hardware\n");
+               status = -ENODEV;
+               goto err3;
+       }
+        
+       /* initialize the spinlock used to serialize access to the image 
+        * parameters
+        */
+       spin_lock_init(&cam->img_lock);
+
+       /* initialize the streaming capture parameters */
+       cam->cparm.capability = V4L2_CAP_TIMEPERFRAME;
+       cam->cparm.readbuffers = 1;
+
+       /* Enable the xclk output.  The sensor may (and does, in the case of 
+        * the OV9640) require an xclk input in order for its initialization 
+        * routine to work.
+        */
+       cam->xclk = 21000000;   /* choose an arbitrary xclk frequency */
+       cam->xclk = cam->cam_hardware->set_xclk(cam->xclk, cam->hardware_data);
+
+       /* initialize the sensor and define a default capture format cam->pix */
+       cam->sensor_data = cam->cam_sensor->init(&cam->pix);
+       if (!cam->sensor_data) {
+               cam->cam_hardware->disable(cam->hardware_data);
+               printk(KERN_ERR CAM_NAME ": cannot initialize sensor\n");
+               status = -ENODEV;
+               goto err4;
+       }
+
+       printk(KERN_INFO CAM_NAME ": %s interface with %s sensor\n",
+               cam->cam_hardware->name, cam->cam_sensor->name);
+
+       /* select an arbitrary default capture frame rate of 15fps */
+       cam->nominal_timeperframe.numerator = 1;
+       cam->nominal_timeperframe.denominator = 15;
+
+       /* calculate xclk based on the default capture format and default 
+        * frame rate
+        */
+       cam->xclk = cam->cam_sensor->calc_xclk(&cam->pix,
+               &cam->nominal_timeperframe, cam->sensor_data);
+       cam->cparm.timeperframe = cam->nominal_timeperframe;
+
+       /* initialise the wait queue */
+       init_waitqueue_head(&cam->new_video_frame);
+
+       /* Initialise the DMA structures */
+       camera_core_sgdma_init(cam);
+
+       /* Disable the Camera after detection */
+       cam->cam_hardware->disable(cam->hardware_data);
+       
+       platform_set_drvdata(pdev, cam);
+       
+       if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) {
+               printk(KERN_ERR CAM_NAME 
+                       ": could not register Video for Linux device\n");
+               status = -ENODEV;
+               goto err5;
+       }
+
+       printk(KERN_INFO CAM_NAME 
+              ": registered device video%d [v4l2]\n", vfd->minor);
+
+       return 0;
+
+ err5:
+       cam->cam_sensor->cleanup(cam->sensor_data);
+ err4:
+       cam->cam_hardware->cleanup(cam->hardware_data);
+ err3:
+       dma_free_coherent(NULL, cam->overlay_size,
+                               (void *)cam->overlay_base, 
+                               cam->overlay_base_phys);
+       cam->overlay_base = 0;
+ err2:
+       video_device_release(vfd);
+ err1:
+       kfree(cam);
+       camera_dev = NULL;
+ err0:
+       return status;
+}
+
+static int camera_core_remove(struct platform_device *pdev)
+{
+       struct camera_device *cam = platform_get_drvdata(pdev);
+       struct video_device *vfd;
+
+       vfd = cam->vfd;
+       if (vfd) {
+               if (vfd->minor == -1) {
+                       /* The device never got registered, so release the 
+                       ** video_device struct directly
+                       */
+                       video_device_release(vfd);
+               } else {
+                       /* The unregister function will release the video_device
+                       ** struct as well as unregistering it.
+                       */
+                       video_unregister_device(vfd);
+               }
+               cam->vfd = NULL;
+       }
+       if (cam->overlay_base) {
+               dma_free_coherent(NULL, cam->overlay_size,
+                                       (void *)cam->overlay_base, 
+                                       cam->overlay_base_phys);
+               cam->overlay_base = 0;
+       }       
+       cam->overlay_base_phys = 0;
+
+       cam->cam_sensor->cleanup(cam->sensor_data);
+       cam->cam_hardware->cleanup(cam->hardware_data);
+       kfree(cam);
+       camera_dev = NULL;
+
+       return 0;
+}
+
+static struct platform_driver camera_core_driver = {
+       .driver = {
+               .name           = CAM_NAME,
+               .owner          = THIS_MODULE,
+       },
+       .probe                  = camera_core_probe,
+       .remove                 = camera_core_remove,
+#ifdef CONFIG_PM
+       .suspend                = camera_core_suspend,
+       .resume                 = camera_core_resume,
+#endif
+};
+
+/* FIXME register omap16xx or omap24xx camera device in arch/arm/...
+ * system init code, with its resources and mux setup, NOT here.
+ * Then MODULE_ALIAS(CAM_NAME) so it hotplugs and coldplugs; this
+ * "legacy" driver style is trouble.
+ */
+static struct platform_device *cam;
+
+static void __exit
+camera_core_cleanup(void)
+{
+       platform_driver_unregister(&camera_core_driver);
+       platform_device_unregister(cam);
+}
+
+static char banner[] __initdata = KERN_INFO "OMAP Camera driver initializing\n";
+
+static int __init
+camera_core_init(void)
+{
+
+       printk(banner);
+       platform_driver_register(&camera_core_driver);
+
+       cam = platform_device_register_simple(CAM_NAME, -1, NULL, 0);
+
+       return 0;
+}
+
+MODULE_AUTHOR("Texas Instruments.");
+MODULE_DESCRIPTION("OMAP Video for Linux camera driver");
+MODULE_LICENSE("GPL");
+
+module_param(video_nr, int, 0);
+MODULE_PARM_DESC(video_nr, 
+               "Minor number for video device (-1 ==> auto assign)");
+module_param(capture_mem, int, 0);
+MODULE_PARM_DESC(capture_mem,
+        "Maximum amount of memory for capture buffers (default 4800KB)");
+
+module_init(camera_core_init);
+module_exit(camera_core_cleanup);
+
diff --git a/drivers/media/video/omap/camera_core.h b/drivers/media/video/omap/camera_core.h
new file mode 100644 (file)
index 0000000..0f94446
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ *  drivers/media/video/omap/camera_core.h
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc. 
+ * 
+ * This package 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. 
+ * 
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 
+ */
+
+#ifndef CAMERA_CORE__H
+#define CAMERA_CORE__H
+
+struct camera_fh;
+
+#include <media/video-buf.h>
+#include <asm/scatterlist.h>
+
+struct camera_device;
+typedef void (*dma_callback_t)(void *arg1, void *arg2);
+
+struct sgdma_state {
+       const struct scatterlist *sglist;
+       int sglen;              /* number of sglist entries */
+       int next_sglist;        /* index of next sglist entry to process */
+       int queued_sglist;      /* number of sglist entries queued for DMA */
+       unsigned long csr;      /* DMA return code */
+       dma_callback_t callback;
+       void *arg;
+};
+
+/* NUM_SG_DMA is the number of scatter-gather DMA transfers that can be queued.
+ */
+#define NUM_SG_DMA VIDEO_MAX_FRAME+2
+/* per-device data structure */
+struct camera_device {
+       struct device dev;
+       struct video_device *vfd;
+       
+       spinlock_t overlay_lock;        /* spinlock for overlay DMA counter */
+       int overlay_cnt;                /* count of queued overlay DMA xfers */
+       struct scatterlist overlay_sglist;
+       unsigned long overlay_base_phys;
+       unsigned long overlay_base;
+       unsigned long overlay_size;
+
+       spinlock_t vbq_lock;            /* spinlock for videobuf queues */
+       struct videobuf_queue_ops vbq_ops;      /* videobuf queue operations */
+       unsigned long field_count;      /* field counter for videobuf_buffer */
+
+       /* scatter-gather DMA management */
+       spinlock_t sg_lock;
+       int free_sgdma; /* number of free sg dma slots */
+       int next_sgdma; /* index of next sg dma slot to use */
+       struct sgdma_state sgdma[NUM_SG_DMA];
+       char in_use;
+
+       /* The img_lock is used to serialize access to the image parameters for 
+        * overlay and capture.  Need to use spin_lock_irq when writing to the 
+        * reading, streaming, and previewing parameters.  A regular spin_lock 
+        * will suffice for all other cases.
+        */
+       spinlock_t img_lock;
+       /* We allow reading from at most one filehandle at a time.
+        * non-NULL means reading is in progress.
+        */
+       struct camera_fh *reading;
+       /* We allow streaming from at most one filehandle at a time.  
+        * non-NULL means streaming is in progress.
+        */
+       struct camera_fh *streaming;
+       /* We allow previewing from at most one filehandle at a time.  
+        * non-NULL means previewing is in progress.
+        */
+       struct camera_fh *previewing;
+
+       /* capture parameters (frame rate, number of buffers) */
+       struct v4l2_captureparm cparm;
+
+       /* This is the frame period actually requested by the user. */
+       struct v4l2_fract nominal_timeperframe;
+       
+       /* frequency (in Hz) of camera interface xclk output */
+       unsigned long xclk;
+
+       /* Pointer to the sensor interface ops */
+       struct omap_camera_sensor *cam_sensor;
+       void *sensor_data;
+       
+       /* Pointer to the camera interface hardware ops */
+       struct camera_hardware *cam_hardware;
+       void *hardware_data;
+
+       /* pix defines the size and pixel format of the image captured by the 
+        * sensor.  This also defines the size of the framebuffers.  The 
+        * same pool of framebuffers is used for video capture and video 
+        * overlay.  These parameters are set/queried by the 
+        * VIDIOC_S_FMT/VIDIOC_G_FMT ioctls with a CAPTURE buffer type.
+        */
+       struct v4l2_pix_format pix;
+       struct v4l2_pix_format pix2;
+
+       /* crop defines the size and offset of the video overlay source window 
+        * within the framebuffer.  These parameters are set/queried by the 
+        * VIDIOC_S_CROP/VIDIOC_G_CROP ioctls with an OVERLAY buffer type.  
+        * The cropping rectangle allows a subset of the captured image to be 
+        * previewed.  It only affects the portion of the image previewed, not 
+        * captured; the entire camera image is always captured.
+        */
+       struct v4l2_rect crop;
+
+       /* win defines the size and offset of the video overlay target window 
+        * within the video display.  These parameters are set/queried by the 
+        * VIDIOC_S_FMT/VIDIOC_G_FMT ioctls with an OVERLAY buffer type.
+        */
+       struct v4l2_window win;
+
+       /* fbuf reflects the size of the video display.  It is queried with the 
+        * VIDIOC_G_FBUF ioctl.  The size of the video display cannot be 
+        * changed with the VIDIOC_S_FBUF ioctl.
+        */
+       struct v4l2_framebuffer fbuf;
+
+       /* end of generic stuff, the above should be common to all omaps */
+
+       /* note, 2420 uses videobuf to do caprure, it is more memory efficient
+          we need 1710 and 2420 do capture in the same way */
+       /* Variables to store the capture state */
+       /* Wait till DMA is completed */
+       wait_queue_head_t new_video_frame;
+       char capture_completed;
+       char capture_started;
+       spinlock_t capture_lock;
+       struct scatterlist capture_sglist;
+       unsigned long capture_base;
+       unsigned long capture_base_phys;
+
+       char active;
+};
+
+/* per-filehandle data structure */
+struct camera_fh {
+       struct camera_device *cam;
+       enum v4l2_buf_type type;
+       struct videobuf_queue vbq;
+};
+
+#define CAM_NAME "omap_camera"
+
+#endif /* CAMERA_CORE__H */
diff --git a/drivers/media/video/omap/camera_hw_if.h b/drivers/media/video/omap/camera_hw_if.h
new file mode 100644 (file)
index 0000000..0976e45
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *  drivers/media/video/omap/camera_hw_if.h
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc. 
+ * 
+ * Camera interface to OMAP camera capture drivers
+ * Camera interface hardware driver should implement this interface
+ *
+ * This package 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. 
+ * 
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 
+ */
+#ifndef OMAP_CAMERA_HW_IF_H
+#define OMAP_CAMERA_HW_IF_H
+
+#define LEN_HW_IF_NAME         31
+
+struct sgdma_state;
+
+struct camera_hardware {
+       unsigned int version;  //version of camera driver module
+       char name[LEN_HW_IF_NAME + 1];
+
+       void *(*init)(void);
+       int (*cleanup)(void *);
+
+       int (*open)(void *);  /* acquire h/w resources (irq,DMA), etc. */
+       int (*close)(void *); /* free h/w resources, stop i/f */
+
+       int (*enable)(void *);
+       int (*disable)(void *);
+
+       int (*abort)(void *);
+
+       int (*set_xclk)(int, void *);
+
+       int (*init_dma)(void *);
+       int (*start_dma)(struct sgdma_state *, void (*)(void *arg1, void *arg2),
+                       void *, void *, void *);
+       int (*finish_dma)(void *);
+};
+
+extern struct camera_hardware camera_hardware_if;
+
+#endif /* OMAP_CAMERA_HW_IF_H */
diff --git a/drivers/media/video/omap/h3_sensor_power.c b/drivers/media/video/omap/h3_sensor_power.c
new file mode 100644 (file)
index 0000000..ae76688
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * drivers/media/video/omap/h3_sensor_power.c
+ *
+ * H3 sensor powerup/down functions.
+ *
+ * Author: Andy Lowe (source@mvista.com)
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+
+#include <asm/arch/gpioexpander.h>
+
+int h3_sensor_powerup(void);
+int h3_sensor_powerdown(void);
+
+int
+h3_sensor_powerup(void)
+{
+       unsigned char expa;
+       int err;
+
+       /* read the current state of GPIO EXPA output */
+       if (( err = read_gpio_expa(&expa, 0x27))) {
+               printk(KERN_ERR "Error reading GPIO EXPA \n");
+               return err;
+       }
+       /* set GPIO EXPA P7 CAMERA_MOD_EN to power-up sensor */
+       if ((err = write_gpio_expa(expa | 0x80, 0x27))) {
+               printk(KERN_ERR "Error writing to GPIO EXPA \n");
+               return err;
+       }
+       return 0;
+}
+
+int
+h3_sensor_powerdown(void)
+{
+       unsigned char expa;
+       int err;
+
+       /* read the current state of GPIO EXPA output */
+       if (( err = read_gpio_expa(&expa, 0x27))) {
+               printk(KERN_ERR "Error reading GPIO EXPA \n");
+               return err;
+       }
+       /* clear GPIO EXPA P7 CAMERA_MOD_EN to power-up sensor */
+       if ((err = write_gpio_expa(expa & ~0x80, 0x27))) {
+               printk(KERN_ERR "Error writing to GPIO EXPA \n");
+               return err;
+       }
+       return 0;
+}
+
+EXPORT_SYMBOL(h3_sensor_powerup);
+EXPORT_SYMBOL(h3_sensor_powerdown);
diff --git a/drivers/media/video/omap/h3sensorpower.h b/drivers/media/video/omap/h3sensorpower.h
new file mode 100644 (file)
index 0000000..8587729
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * drivers/media/video/omap/h3sensorpower.h
+ *
+ * Copyright (C) 2005 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef H3SENSORPOWER_H
+#define H3SENSORPOWER_H
+
+int h3_sensor_powerup(void);
+int h3_sensor_powerdown(void);
+
+#endif /*H3SENSORPOWER_H*/
diff --git a/drivers/media/video/omap/h4_sensor_power.c b/drivers/media/video/omap/h4_sensor_power.c
new file mode 100644 (file)
index 0000000..f8db956
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * drivers/media/video/omap/h4_sensor_power.c
+ *
+ * H4 sensor powerup/down functions.
+ *
+ * Author: Andy Lowe (source@mvista.com)
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+
+#include <asm/arch/gpioexpander.h>
+
+int h4_sensor_powerup(void);
+int h4_sensor_powerdown(void);
+
+int
+h4_sensor_powerup(void)
+{
+       unsigned char expa;
+       int err;
+
+       /* read current state of GPIO EXPA outputs */
+       if ((err = read_gpio_expa(&expa, 0x20))) {
+               printk(KERN_ERR "Error reading GPIO EXPA\n");
+               return err;
+       }
+       /* Set GPIO EXPA P3 (CAMERA_MODULE_EN) to power-up sensor */
+       if ((err = write_gpio_expa(expa | 0x08, 0x20))) {
+               printk(KERN_ERR "Error writing to GPIO EXPA\n");
+               return err;
+       }
+
+       /* read current state of GPIO EXPA outputs */
+       if ((err = read_gpio_expa(&expa, 0x22))) {
+               printk(KERN_ERR "Error reading GPIO EXPA\n");
+               return err;
+       }
+       /* Clear GPIO EXPA P7 (CAM_RST) */
+       if ((err = write_gpio_expa(expa & ~0x80, 0x22))) {
+               printk(KERN_ERR "Error writing to GPIO EXPA\n");
+               return err;
+       }
+
+       return 0;
+}
+
+int
+h4_sensor_powerdown(void)
+{
+       unsigned char expa;
+       int err;
+
+       /* read current state of GPIO EXPA outputs */
+       if ((err = read_gpio_expa(&expa, 0x20))) {
+               printk(KERN_ERR "Error reading GPIO EXPA\n");
+               return err;
+       }
+       /* Clear GPIO EXPA P3 (CAMERA_MODULE_EN) to power-down sensor */
+       if ((err = write_gpio_expa(expa & ~0x08, 0x20))) {
+               printk(KERN_ERR "Error writing to GPIO EXPA\n");
+               return err;
+       }
+
+       return 0;
+}
+
+EXPORT_SYMBOL(h4_sensor_powerup);
+EXPORT_SYMBOL(h4_sensor_powerdown);
diff --git a/drivers/media/video/omap/h4sensorpower.h b/drivers/media/video/omap/h4sensorpower.h
new file mode 100644 (file)
index 0000000..4eeae11
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * drivers/media/video/omap/h4sensorpower.h
+ *
+ * Copyright (C) 2005 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef H4SENSORPOWER_H
+#define H4SENSORPOWER_H
+
+int h4_sensor_powerup(void);
+int h4_sensor_powerdown(void);
+
+#endif /*H4SENSORPOWER_H*/
diff --git a/drivers/media/video/omap/omap16xxcam.c b/drivers/media/video/omap/omap16xxcam.c
new file mode 100644 (file)
index 0000000..34cf1a6
--- /dev/null
@@ -0,0 +1,590 @@
+/*
+ * drivers/media/video/omap/omap16xxcam.c
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc. 
+ * 
+ * Video-for-Linux (Version 2) camera capture driver for
+ * the OMAP H2 and H3 camera controller.
+ *
+ * leverage some code from CEE distribution 
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ * 
+ * This package 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. 
+ * 
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 
+ */
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+
+#include <asm/arch/irqs.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/hardware.h>
+#include <asm/io.h>
+#include <asm/scatterlist.h>
+#include <asm/mach-types.h>
+
+#include "omap16xxcam.h"
+#include "camera_hw_if.h"
+#include "camera_core.h"
+
+#define CONF_CAMERAIF_RESET_R 5
+#define EN_PER   0
+
+/* NUM_CAMDMA_CHANNELS is the number of logical channels used for
+ * DMA data transfer.
+ */
+#define NUM_CAMDMA_CHANNELS 2
+
+typedef struct {
+        unsigned int ctrlclock;     /* 00 */
+        unsigned int it_status;     /* 04 */
+        unsigned int mode;          /* 08 */
+        unsigned int status;        /* 0C */
+        unsigned int camdata;       /* 10 */
+        unsigned int gpio;         /* 14 */
+        unsigned int peak_counter;  /* 18 */
+} camera_regs_t;
+
+struct camdma_state {
+       dma_callback_t callback;
+       void *arg1;
+       void *arg2;
+};
+
+struct omap16xxcam {
+       camera_regs_t *camera_regs;
+       unsigned long iobase_phys;
+
+       /* frequncy (in Hz) of camera interface functional clock (ocp_clk) */
+       unsigned long ocp_clk;
+
+       struct clk *func_clk;
+
+       /* dma related stuff */
+       spinlock_t dma_lock;
+       int free_dmach;
+       int next_dmach;
+       struct camdma_state camdma[NUM_CAMDMA_CHANNELS];
+       int dma_channel_number1;
+       int dma_channel_number2;
+
+       wait_queue_head_t vsync_wait;
+
+       int new;
+};
+static struct omap16xxcam hardware_data;
+   
+static int omap16xxcam_set_xclk(int, void *);
+static void omap16xx_cam_dma_link_callback(int, unsigned short, void *);
+
+/* Clears the camera data FIFO by setting RAZ_FIFO bit in MODE configuration
+   register. */
+static void
+omap16xx_cam_clear_fifo(struct omap16xxcam *data)
+{
+       data->camera_regs->mode |= RAZ_FIFO;
+       udelay(10);
+       data->camera_regs->mode &= ~RAZ_FIFO;
+}
+  
+static void
+omap16xx_cam_reset(struct omap16xxcam *data, int yes)
+{
+       if (machine_is_omap_h3())
+               data->camera_regs->gpio = yes ? 0 : 1;
+       else
+               data->camera_regs->gpio = yes ? 1 : 0;
+}
+
+static void 
+omap16xx_cam_init(void)
+{
+       /*
+        * FIXME - Use mux API's instead of directly writing in to MUX registers
+        */
+       omap_writel(omap_readl(FUNC_MUX_CTRL_4) & ~(0x1ff << 21), FUNC_MUX_CTRL_4);
+       omap_writel(0, FUNC_MUX_CTRL_5);
+       omap_writel(omap_readl(PULL_DWN_CTRL_0) & ~(0x1FFF << 17), PULL_DWN_CTRL_0);
+       omap_writel(omap_readl(PU_PD_SEL_0) & ~(0x1FFF << 17), PU_PD_SEL_0);
+
+       omap_writel(0xeaef, COMP_MODE_CTRL_0);
+       omap_writel(omap_readl(OMAP1610_RESET_CONTROL) & ~(1 << CONF_CAMERAIF_RESET_R),
+                       OMAP1610_RESET_CONTROL);
+       omap_writel(omap_readl(OMAP1610_RESET_CONTROL) | (1 << CONF_CAMERAIF_RESET_R),
+                       OMAP1610_RESET_CONTROL);
+    
+       /* Enable peripheral reset */
+       omap_writew(omap_readw(ARM_RSTCT2) | (1 << EN_PER), ARM_RSTCT2);
+
+       /* enable peripheral clock */
+       clk_enable(hardware_data.func_clk);
+}
+
+static void
+omap16xx_cam_waitfor_syncedge(struct omap16xxcam *data, u32 edge_mask)
+{
+       data->camera_regs->mode = (FIFO_TRIGGER_LVL << THRESHOLD_BIT) | edge_mask;
+       do {
+               interruptible_sleep_on(&data->vsync_wait);
+       } while (signal_pending(current));
+}
+
+static void
+omap16xx_cam_configure_dma(struct omap16xxcam *data)
+{
+
+       data->camera_regs->mode = (FIFO_TRIGGER_LVL << THRESHOLD_BIT)
+                        | EN_DMA | EN_FIFO_FULL;
+       data->camera_regs->ctrlclock |= LCLK_EN; 
+}
+
+/* acquire h/w resources DMA */
+static int
+omap16xx_cam_link_open(struct omap16xxcam *data)
+{
+       int ret;
+
+       /* Acquire first dma channel */
+       if ((ret = omap_request_dma(OMAP_DMA_CAMERA_IF_RX, 
+                               "camera dma 1", omap16xx_cam_dma_link_callback,
+                               (void *)data, &data->dma_channel_number1))) {
+                return ret;
+       }
+       /* Acquire second dma channel */
+       if ((ret = omap_request_dma(OMAP_DMA_CAMERA_IF_RX, 
+                               "camera dma 2", omap16xx_cam_dma_link_callback,
+                               (void *)data, &data->dma_channel_number2))) {
+                printk ("No DMA available for camera\n");
+                return ret;
+        }
+       data->next_dmach = data->dma_channel_number1;
+       OMAP_DMA_CLNK_CTRL_REG(data->dma_channel_number1) =
+               data->dma_channel_number2;
+       OMAP_DMA_CLNK_CTRL_REG(data->dma_channel_number2) =
+               data->dma_channel_number1;
+
+       return 0;
+}
+
+/* free h/w resources, stop i/f */
+static int
+omap16xx_cam_link_close(struct omap16xxcam *data)
+{
+       /* free dma channels */
+       omap_stop_dma(data->dma_channel_number1);
+       omap_stop_dma(data->dma_channel_number2);
+
+       omap_free_dma (data->dma_channel_number1);
+       omap_free_dma (data->dma_channel_number2);
+
+       return 0;
+}
+
+/* dma callback routine. */
+static void
+omap16xx_cam_dma_link_callback(int lch, unsigned short ch_status, void *data)
+{
+       int count;
+       void *arg1, *arg2;
+       struct sgdma_state *sgdma = sgdma;
+       struct omap16xxcam *cam = (struct omap16xxcam *)data;
+       dma_callback_t callback;
+
+       spin_lock(&cam->dma_lock);
+       if (cam->free_dmach == 2)
+       {
+               printk("callback all CHANNELS WERE IDLE \n");
+               spin_unlock(&cam->dma_lock);
+               return;
+       }
+       if (cam->free_dmach == 0) {
+               lch = cam->next_dmach;
+       } else {
+               lch = cam->next_dmach == cam->dma_channel_number1 ? 
+                       cam->dma_channel_number2 : cam->dma_channel_number1;
+       }
+
+       while (cam->free_dmach < 2)
+       {
+               if (OMAP_DMA_CCR_REG(lch) & (1 << 7))
+                       break;  
+
+               count = (lch == cam->dma_channel_number2) ? 1 : 0;
+
+               callback = cam->camdma[count].callback;
+               arg1 = cam->camdma[count].arg1;
+               arg2 = cam->camdma[count].arg2;
+               cam->free_dmach++;
+
+               spin_unlock(&cam->dma_lock);            
+               callback(arg1, arg2);
+               spin_lock(&cam->dma_lock);
+
+               lch = (lch == cam->dma_channel_number2) ? cam->dma_channel_number1 :
+                                                       cam->dma_channel_number2;
+       }
+       spin_unlock(&cam->dma_lock);
+       
+}
+
+static irqreturn_t
+omap16xx_cam_isr(int irq, void *client_data)
+{
+       struct omap16xxcam *data = (struct omap16xxcam *)client_data;
+       unsigned int itstat = data->camera_regs->it_status;
+
+       /* VSYNC UP interrupt, start filling FIFO and enabling DMA */
+       if (itstat & V_UP) {            
+               data->camera_regs->mode &= ~EN_V_UP;
+               omap16xx_cam_clear_fifo(data);  
+               omap16xx_cam_configure_dma(data);
+               omap_start_dma(data->next_dmach);
+               wake_up_interruptible(&data->vsync_wait);
+       }
+
+       if (itstat & V_DOWN) {
+               data->camera_regs->mode &= ~EN_V_DOWN;
+               wake_up_interruptible(&data->vsync_wait);
+       }
+
+       if (itstat & H_UP)
+               printk("H_UP\n");
+       
+       if (itstat & H_DOWN)
+               printk("H_DOWN\n");
+       
+       if (itstat & FIFO_FULL) {
+               omap16xx_cam_clear_fifo(data);  
+               printk("FIFO_FULL\n");
+       }
+       
+       if (itstat & DATA_XFER)
+               printk("DATA_TRANS\n");
+       
+       return IRQ_HANDLED;
+}
+/* ------------- below are interface functions ----------------- */
+/* ------------- these functions are named omap16xxcam_<name> -- */
+static int
+omap16xxcam_init_dma(void *priv)
+{
+       int ch;
+       struct omap16xxcam *data = (struct omap16xxcam *) priv;
+
+       data->free_dmach = 2;
+       for (ch = 0; ch < 2; ++ch) {
+               data->camdma[ch].callback = NULL;
+               data->camdma[ch].arg1 = NULL;
+               data->camdma[ch].arg2 = NULL;
+       }
+
+       return 0;
+}
+
+/* start the dma of chains */
+static int 
+omap16xxcam_start_dma(struct sgdma_state *sgdma,
+               dma_callback_t callback, void *arg1, void *arg2, void *priv)
+{
+       struct omap16xxcam *data = (struct omap16xxcam *) priv;
+       struct scatterlist *sglist;
+       unsigned long irqflags;
+       int dmach;
+       int prev_dmach;
+       int count;
+
+       spin_lock_irqsave(&data->dma_lock, irqflags);
+       sglist = (struct scatterlist *)(sgdma->sglist + sgdma->next_sglist);
+
+       if (!data->free_dmach) {
+               spin_unlock_irqrestore(&data->dma_lock, irqflags);
+               return -EBUSY;
+       } 
+       dmach = data->next_dmach;
+       count = (dmach == data->dma_channel_number2) ? 1:0;
+       data->camdma[count].callback = callback;
+       data->camdma[count].arg1 = arg1;
+       data->camdma[count].arg2 = arg2;
+
+       if (cpu_is_omap1710())
+               omap_set_dma_src_params(dmach, OMAP_DMA_PORT_OCP_T1,
+                           OMAP_DMA_AMODE_CONSTANT, CAM_CAMDATA_REG,
+                           0, 0);
+       else
+               omap_set_dma_src_params(dmach, OMAP_DMA_PORT_TIPB,
+                           OMAP_DMA_AMODE_CONSTANT, CAM_CAMDATA_REG,
+                           0, 0);
+
+       omap_set_dma_dest_params(dmach, OMAP_DMA_PORT_EMIFF,
+                            OMAP_DMA_AMODE_POST_INC, sg_dma_address(sglist),
+                            0, 0);
+
+       omap_set_dma_transfer_params(dmach, OMAP_DMA_DATA_TYPE_S32,
+                       FIFO_TRIGGER_LVL, 
+                       sg_dma_len(sglist)/(4 * FIFO_TRIGGER_LVL), 
+                       OMAP_DMA_SYNC_FRAME,
+                       0, 0);
+
+       OMAP_DMA_CLNK_CTRL_REG(dmach) &= ~( 1<< 15);
+
+       prev_dmach = (dmach == data->dma_channel_number2) ? 
+               data->dma_channel_number1 : data->dma_channel_number2;
+       
+       if (data->new) {
+               data->new = 0;
+               omap16xx_cam_waitfor_syncedge(data, EN_V_UP);
+       } else {
+               if (OMAP_DMA_CCR_REG(prev_dmach) & (1 << 7))
+                       OMAP_DMA_CLNK_CTRL_REG(prev_dmach) |= (1 << 15);
+               else {
+                       /* no transfer is in progress */
+                       omap_start_dma(dmach);
+               }       
+       }
+       
+       data->next_dmach = prev_dmach; 
+       data->free_dmach--;
+       spin_unlock_irqrestore(&data->dma_lock, irqflags);
+       return 0;
+}
+int static
+omap16xxcam_finish_dma(void *priv)
+{
+       struct omap16xxcam *data = (struct omap16xxcam *) priv;
+
+       while (data->free_dmach < 2)
+               mdelay(1);
+
+       return 0;
+}
+
+
+/* Enables the camera. Takes camera out of reset. Enables the clocks. */ 
+static int
+omap16xxcam_enable(void *priv)
+{
+       struct omap16xxcam *data = (struct omap16xxcam *) priv;
+
+       omap16xx_cam_reset(data, 1);
+       
+       /* give clock to camera_module */
+       data->camera_regs->mode = (FIFO_TRIGGER_LVL << THRESHOLD_BIT);
+       data->camera_regs->ctrlclock = MCLK_EN | CAMEXCLK_EN;
+
+       omap16xx_cam_clear_fifo(data);
+
+       /* wait for camera to settle down */
+       mdelay(5);
+
+       return 0;
+}
+/* Disables all the camera clocks. Put the camera interface in reset. */
+static int
+omap16xxcam_disable(void *priv)
+{      
+       struct omap16xxcam *data = (struct omap16xxcam *) priv;
+
+       omap16xx_cam_clear_fifo(data);
+
+       data->camera_regs->ctrlclock = 0x00000000;     
+       data->camera_regs->mode = 0x00000000;
+       
+       omap16xx_cam_reset(data, 0);
+
+       return 0;
+}
+
+/* Abort the data transfer */
+static int
+omap16xxcam_abort(void *priv)
+{
+       return omap16xxcam_disable(priv);
+}
+
+static int
+omap16xxcam_set_xclk(int xclk, void *priv)
+{      
+       struct omap16xxcam *data = (struct omap16xxcam *) priv;
+       int xclk_val;
+       int divisor = 1;
+       divisor = data->ocp_clk/xclk;
+       if ( divisor * xclk < data->ocp_clk)
+               ++divisor; 
+
+       switch (divisor) {
+               case 1:
+               case 2:
+                       xclk_val = FOSCMOD_TC2_CK2;
+                       break;
+               case 3:
+                       xclk_val = FOSCMOD_TC2_CK3;
+                       break;
+               case 4:
+               case 5:
+               case 6:
+               case 7:
+                       xclk_val = FOSCMOD_TC2_CK4;
+                       break;
+               case 8:
+               case 9:
+                       xclk_val = FOSCMOD_TC2_CK8;
+                       break;
+               case 10:
+               case 11:
+                       xclk_val = FOSCMOD_TC2_CK10;
+                       break;
+               case 12:
+               case 13:
+               case 14:
+               case 15:
+                       xclk_val = FOSCMOD_TC2_CK12;
+                       break;
+               case 16:
+                       xclk_val = FOSCMOD_TC2_CK16;
+                       break;
+               default:
+                       xclk_val = FOSCMOD_TC2_CK16;
+       }
+       
+       /* follow the protocol to change the XCLK clock */
+       data->camera_regs->ctrlclock &= ~CAMEXCLK_EN;
+       data->camera_regs->ctrlclock |= xclk_val;
+       data->camera_regs->ctrlclock |= CAMEXCLK_EN;
+
+       return (data->ocp_clk/divisor);
+}
+
+static int
+omap16xxcam_open(void *priv)
+{
+       struct omap16xxcam *data = (struct omap16xxcam *) priv;
+       int ret;
+
+       if ((ret = request_irq(INT_CAMERA, omap16xx_cam_isr, IRQF_DISABLED,
+                                       "camera", data))) {
+               printk("FAILED to aquire irq\n");
+               return ret;
+       }
+
+       data->new = 1;
+       omap16xxcam_enable(data);
+       omap16xxcam_init_dma(data);
+
+       return omap16xx_cam_link_open(data);
+}
+
+static int
+omap16xxcam_close(void *priv)
+{
+       struct omap16xxcam *data = (struct omap16xxcam *) priv;
+
+       omap16xxcam_disable(priv);
+        
+       free_irq(INT_CAMERA, data);
+       
+       return omap16xx_cam_link_close(data);
+}
+
+static int
+omap16xxcam_cleanup(void *priv)
+{
+       struct omap16xxcam *data = (struct omap16xxcam *) priv;
+
+       if (!data->camera_regs)
+               return -EINVAL;
+
+       omap16xxcam_disable(data);
+       if (cpu_is_omap1710())
+               iounmap((void *)data->camera_regs);
+       data->camera_regs= NULL;
+
+       if (data->iobase_phys) {
+               release_mem_region(data->iobase_phys, CAMERA_IOSIZE);
+               data->iobase_phys = 0;
+       }
+
+       if (hardware_data.func_clk) {
+               clk_disable(hardware_data.func_clk);
+               clk_put(hardware_data.func_clk);
+               hardware_data.func_clk = NULL;
+       }
+
+       return 0;
+}
+
+/* Initialise the OMAP camera interface */
+static void *
+omap16xxcam_init(void)
+{
+       unsigned long cam_iobase;
+
+       if (!request_mem_region(CAMERA_BASE, CAMERA_IOSIZE,
+                               camera_hardware_if.name)) {
+               pr_debug("%s is already in use\n", camera_hardware_if.name);
+               return NULL;
+       }
+
+       if (cpu_is_omap1710()) {
+               cam_iobase = (unsigned long) ioremap (CAMERA_BASE,
+                               CAMERA_IOSIZE);
+               if (!cam_iobase) {
+                       printk("CANNOT MAP CAMERA REGISTER\n");
+                       return NULL;
+               }
+       }
+       else
+               cam_iobase = io_p2v(CAMERA_BASE);
+
+       /* Set the base address of the camera registers */
+       hardware_data.camera_regs = (camera_regs_t *)cam_iobase;
+       hardware_data.iobase_phys = (unsigned long) CAMERA_BASE;
+
+       /* get the input clock value to camera interface and store it */
+       if (cpu_is_omap1710())
+               hardware_data.func_clk = clk_get(0, "tc2_ck");
+       else
+               hardware_data.func_clk = clk_get(0, "armper_ck");
+       hardware_data.ocp_clk = clk_get_rate(hardware_data.func_clk);
+
+       /* Init the camera IF */
+       omap16xx_cam_init();
+       /* enable it. This is needed for sensor detection */
+       omap16xxcam_enable((void*)&hardware_data);
+       /* Init dma data */
+       spin_lock_init(&hardware_data.dma_lock);
+
+       init_waitqueue_head(&hardware_data.vsync_wait);
+       return (void*)&hardware_data;
+}
+
+struct camera_hardware camera_hardware_if = {
+       .version        = 0x01,
+       .name           = "OMAP16xx Parallel Camera",
+       .init           = omap16xxcam_init,
+       .cleanup        = omap16xxcam_cleanup,
+       .open           = omap16xxcam_open,
+       .close          = omap16xxcam_close,
+       .enable         = omap16xxcam_enable,
+       .disable        = omap16xxcam_disable,
+       .abort          = omap16xxcam_abort,
+       .set_xclk       = omap16xxcam_set_xclk,
+       .init_dma       = omap16xxcam_init_dma,
+       .start_dma      = omap16xxcam_start_dma,
+       .finish_dma     = omap16xxcam_finish_dma,
+};
+
diff --git a/drivers/media/video/omap/omap16xxcam.h b/drivers/media/video/omap/omap16xxcam.h
new file mode 100644 (file)
index 0000000..14de5b7
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ *  drivers/media/video/omap/omap16xxcam.h
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc. 
+ * 
+ * This package 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. 
+ * 
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 
+ */
+#ifndef OMAP_16XX_CAM_H
+#define OMAP_16XX_CAM_H
+
+#define DMA_ELEM_SIZE   4
+#define FIFO_TRIGGER_LVL (32)
+
+/*
+ * ---------------------------------------------------------------------------
+ *  OMAP1610 Camera Interface
+ * ---------------------------------------------------------------------------
+ */
+
+#ifdef CONFIG_MACH_OMAP_H3
+#define CAMERA_BASE          (0x2007d800)
+#else
+#define CAMERA_BASE          (IO_PHYS + 0x6800)
+#endif
+
+#define CAM_CTRLCLOCK_REG    (CAMERA_BASE + 0x00)
+#define CAM_IT_STATUS_REG    (CAMERA_BASE + 0x04)
+#define CAM_MODE_REG         (CAMERA_BASE + 0x08)
+#define CAM_STATUS_REG       (CAMERA_BASE + 0x0C)
+#define CAM_CAMDATA_REG      (CAMERA_BASE + 0x10)
+#define CAM_GPIO_REG         (CAMERA_BASE + 0x14)
+#define CAM_PEAK_CTR_REG     (CAMERA_BASE + 0x18)
+#define CAMERA_IOSIZE        0x1C
+
+/* CTRLCLOCK bit shifts */
+#define FOSCMOD_BIT                    0
+#define FOSCMOD_MASK                   (0x7 << FOSCMOD_BIT)
+#define FOSCMOD_12MHz          0x0
+#define        FOSCMOD_6MHz            0x2
+#define        FOSCMOD_9_6MHz          0x4
+#define        FOSCMOD_24MHz           0x5
+#define        FOSCMOD_8MHz            0x6
+#define        FOSCMOD_TC2_CK2         0x3
+#define        FOSCMOD_TC2_CK3         0x1
+#define        FOSCMOD_TC2_CK4         0x5
+#define        FOSCMOD_TC2_CK8         0x0
+#define        FOSCMOD_TC2_CK10        0x4
+#define        FOSCMOD_TC2_CK12        0x6
+#define        FOSCMOD_TC2_CK16        0x2
+#define        POLCLK                  (1<<3)
+#define        CAMEXCLK_EN             (1<<4)
+#define        MCLK_EN                 (1<<5)
+#define        DPLL_EN                 (1<<6)
+#define        LCLK_EN                 (1<<7)
+
+/* IT_STATUS bit shifts */
+#define V_UP           (1<<0)
+#define V_DOWN         (1<<1)
+#define H_UP           (1<<2)
+#define H_DOWN         (1<<3)
+#define FIFO_FULL      (1<<4)
+#define DATA_XFER      (1<<5)
+
+/* MODE bit shifts */
+#define CAMOSC         (1<<0)
+#define IMGSIZE_BIT    1
+#define IMGSIZE_MASK   (0x3 << IMGSIZE_BIT)
+#define        IMGSIZE_CIF      (0x0 << IMGSIZE_BIT)    /* 352x288 */
+#define        IMGSIZE_QCIF     (0x1 << IMGSIZE_BIT)    /* 176x144 */
+#define        IMGSIZE_VGA      (0x2 << IMGSIZE_BIT)    /* 640x480 */
+#define        IMGSIZE_QVGA     (0x3 << IMGSIZE_BIT)    /* 320x240 */
+#define ORDERCAMD      (1<<3)
+#define EN_V_UP        (1<<4)
+#define EN_V_DOWN      (1<<5)
+#define EN_H_UP        (1<<6)
+#define EN_H_DOWN      (1<<7)
+#define EN_DMA         (1<<8)
+#define THRESHOLD      (1<<9)
+#define THRESHOLD_BIT  9
+#define THRESHOLD_MASK (0x7f<<9)
+#define EN_NIRQ        (1<<16)
+#define EN_FIFO_FULL   (1<<17)
+#define RAZ_FIFO       (1<<18)
+
+/* STATUS bit shifts */
+#define VSTATUS        (1<<0)
+#define HSTATUS        (1<<1)
+
+/* GPIO bit shifts */
+#define CAM_RST        (1<<0)
+
+
+#define XCLK_6MHZ     6000000
+#define XCLK_8MHZ     8000000
+#define XCLK_9_6MHZ   9000000
+#define XCLK_12MHZ   12000000
+#define XCLK_24MHZ   24000000
+
+#endif /* OMAP_16XX_CAM_H */
diff --git a/drivers/media/video/omap/ov9640.h b/drivers/media/video/omap/ov9640.h
new file mode 100644 (file)
index 0000000..4cdba05
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * drivers/media/video/omap/ov9640.h
+ *
+ * Register definitions for the OmniVision OV9640 CameraChip.
+ *
+ * Author: Andy Lowe (source@mvista.com)
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License 
+ * version 2. This program is licensed "as is" without any warranty of any 
+ * kind, whether express or implied.
+ */
+
+#ifndef OV9640_H
+#define OV9640_H
+
+/* The OV9640 I2C sensor chip has a fixed slave address of 0x30. */
+#ifdef CONFIG_OMAP24XX_VIRTIO
+#define OV9640_I2C_ADDR                0x60
+#else
+#define OV9640_I2C_ADDR                0x30
+#endif
+
+/* define register offsets for the OV9640 sensor chip */
+#define OV9640_GAIN            0x00
+#define OV9640_BLUE            0x01
+#define OV9640_RED             0x02
+#define OV9640_VREF            0x03
+#define OV9640_COM1            0x04
+#define OV9640_BAVE            0x05
+#define OV9640_GEAVE           0x06
+#define OV9640_RAVE            0x08
+#define OV9640_COM2            0x09
+#define OV9640_PID             0x0A
+#define OV9640_VER             0x0B
+#define OV9640_COM3            0x0C
+#define OV9640_COM4            0x0D
+#define OV9640_COM5            0x0E
+#define OV9640_COM6            0x0F
+#define OV9640_AECH            0x10
+#define OV9640_CLKRC           0x11
+#define OV9640_COM7            0x12
+#define OV9640_COM8            0x13
+#define OV9640_COM9            0x14
+#define OV9640_COM10           0x15
+#define OV9640_HSTRT           0x17
+#define OV9640_HSTOP           0x18
+#define OV9640_VSTRT           0x19
+#define OV9640_VSTOP           0x1A
+#define OV9640_PSHFT           0x1B
+#define OV9640_MIDH            0x1C
+#define OV9640_MIDL            0x1D
+#define OV9640_MVFP            0x1E
+#define OV9640_LAEC            0x1F
+#define OV9640_BOS             0x20
+#define OV9640_GBOS            0x21
+#define OV9640_GROS            0x22
+#define OV9640_ROS             0x23
+#define OV9640_AEW             0x24
+#define OV9640_AEB             0x25
+#define OV9640_VPT             0x26
+#define OV9640_BBIAS           0x27
+#define OV9640_GBBIAS          0x28
+#define OV9640_EXHCH           0x2A
+#define OV9640_EXHCL           0x2B
+#define OV9640_RBIAS           0x2C
+#define OV9640_ADVFL           0x2D
+#define OV9640_ADVFH           0x2E
+#define OV9640_YAVE            0x2F
+#define OV9640_HSYST           0x30
+#define OV9640_HSYEN           0x31
+#define OV9640_HREF            0x32
+#define OV9640_CHLF            0x33
+#define OV9640_ARBLM           0x34
+#define OV9640_ADC             0x37
+#define OV9640_ACOM            0x38
+#define OV9640_OFON            0x39
+#define OV9640_TSLB            0x3A
+#define OV9640_COM11           0x3B
+#define OV9640_COM12           0x3C
+#define OV9640_COM13           0x3D
+#define OV9640_COM14           0x3E
+#define OV9640_EDGE            0x3F
+#define OV9640_COM15           0x40
+#define OV9640_COM16           0x41
+#define OV9640_COM17           0x42
+#define OV9640_MTX1            0x4F
+#define OV9640_MTX2            0x50
+#define OV9640_MTX3            0x51
+#define OV9640_MTX4            0x52
+#define OV9640_MTX5            0x53
+#define OV9640_MTX6            0x54
+#define OV9640_MTX7            0x55
+#define OV9640_MTX8            0x56
+#define OV9640_MTX9            0x57
+#define OV9640_MTXS            0x58
+#define OV9640_LCC1            0x62
+#define OV9640_LCC2            0x63
+#define OV9640_LCC3            0x64
+#define OV9640_LCC4            0x65
+#define OV9640_LCC5            0x66
+#define OV9640_MANU            0x67
+#define OV9640_MANV            0x68
+#define OV9640_HV              0x69
+#define OV9640_MBD             0x6A
+#define OV9640_DBLV            0x6B
+#define OV9640_GSP1            0x6C
+#define OV9640_GSP2            0x6D
+#define OV9640_GSP3            0x6E
+#define OV9640_GSP4            0x6F
+#define OV9640_GSP5            0x70
+#define OV9640_GSP6            0x71
+#define OV9640_GSP7            0x72
+#define OV9640_GSP8            0x73
+#define OV9640_GSP9            0x74
+#define OV9640_GSP10           0x75
+#define OV9640_GSP11           0x76
+#define OV9640_GSP12           0x77
+#define OV9640_GSP13           0x78
+#define OV9640_GSP14           0x79
+#define OV9640_GSP15           0x7A
+#define OV9640_GSP16           0x7B
+#define OV9640_GST1            0x7C
+#define OV9640_GST2            0x7D
+#define OV9640_GST3            0x7E
+#define OV9640_GST4            0x7F
+#define OV9640_GST5            0x80
+#define OV9640_GST6            0x81
+#define OV9640_GST7            0x82
+#define OV9640_GST8            0x83
+#define OV9640_GST9            0x84
+#define OV9640_GST10           0x85
+#define OV9640_GST11           0x86
+#define OV9640_GST12           0x87
+#define OV9640_GST13           0x88
+#define OV9640_GST14           0x89
+#define OV9640_GST15           0x8A
+
+#define OV9640_NUM_REGS                (OV9640_GST15 + 1)
+
+#define OV9640_PID_MAGIC       0x96    /* high byte of product ID number */
+#define OV9640_VER_REV2                0x48    /* low byte of product ID number */
+#define OV9640_VER_REV3                0x49    /* low byte of product ID number */
+#define OV9640_MIDH_MAGIC      0x7F    /* high byte of mfg ID */
+#define OV9640_MIDL_MAGIC      0xA2    /* low byte of mfg ID */
+
+/* define a structure for ov9640 register initialization values */
+struct ov9640_reg {
+       unsigned char reg;
+       unsigned char val;
+};
+
+enum image_size { QQCIF, QQVGA, QCIF, QVGA, CIF, VGA, SXGA };
+enum pixel_format { YUV, RGB565, RGB555 };
+#define NUM_IMAGE_SIZES 7
+#define NUM_PIXEL_FORMATS 3
+
+struct capture_size {
+       unsigned long width;
+       unsigned long height;
+};
+
+/* Array of image sizes supported by OV9640.  These must be ordered from 
+ * smallest image size to largest.
+ */
+const static struct capture_size ov9640_sizes[] = {
+       {   88,  72 },  /* QQCIF */
+       {  160, 120 },  /* QQVGA */
+       {  176, 144 },  /* QCIF */
+       {  320, 240 },  /* QVGA */
+       {  352, 288 },  /* CIF */
+       {  640, 480 },  /* VGA */
+       { 1280, 960 },  /* SXGA */
+};
+
+#endif /* ifndef OV9640_H */
+
diff --git a/drivers/media/video/omap/sensor_if.h b/drivers/media/video/omap/sensor_if.h
new file mode 100644 (file)
index 0000000..47bb716
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * drivers/media/video/omap/sensor_if.h
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc. 
+ * 
+ * Sensor interface to OMAP camera capture drivers
+ * Sensor driver should implement this interface
+ *
+ * This package 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. 
+ * 
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 
+ */
+#ifndef OMAP_SENSOR_IF_H
+#define OMAP_SENSOR_IF_H
+
+#define OMAP_SENSOR_NAME_LEN           31
+
+struct omap_camera_sensor {
+       unsigned int version;
+       char name[OMAP_SENSOR_NAME_LEN + 1];
+
+       void *(*init)(struct v4l2_pix_format *);
+       int (*cleanup)(void *);
+
+       int (*power_on)(void *);
+       int (*power_off)(void *);
+
+       int (*enum_pixformat)(struct v4l2_fmtdesc *, void *);
+       int (*try_format)(struct v4l2_pix_format *, void *);
+
+       unsigned long (*calc_xclk)(struct v4l2_pix_format *,
+                                  struct v4l2_fract *, void *);
+
+       int (*configure)(struct v4l2_pix_format *, unsigned long,
+                        struct v4l2_fract *, void *);
+
+       int (*query_control) (struct v4l2_queryctrl *, void *);
+       int (*get_control)(struct v4l2_control *, void *);
+       int (*set_control)(struct v4l2_control *, void *);
+
+};
+
+extern struct omap_camera_sensor camera_sensor_if;
+
+#endif
diff --git a/drivers/media/video/omap/sensor_ov9640.c b/drivers/media/video/omap/sensor_ov9640.c
new file mode 100644 (file)
index 0000000..78c8250
--- /dev/null
@@ -0,0 +1,1220 @@
+
+/*
+ * drivers/media/video/omap/sensor_ov9640.c
+ *
+ * Ov9640 Sensor driver for OMAP camera sensor interface
+ *
+ * Author: Andy Lowe (source@mvista.com)
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License 
+ * version 2. This program is licensed "as is" without any warranty of any 
+ * kind, whether express or implied.
+ */
+
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <media/video-buf.h>
+#include <linux/delay.h>
+#include <asm/mach-types.h>
+#include <asm/arch/gpio.h>
+
+#include "sensor_if.h"
+#include "ov9640.h"
+#include "h3sensorpower.h"
+#include "h4sensorpower.h"
+
+
+struct ov9640_sensor {
+       /* I2C parameters */
+       struct i2c_client client;
+       int ver; /* OV9640 version */
+};
+
+static struct ov9640_sensor ov9640;
+
+/* list of image formats supported by OV9640 sensor */
+const static struct v4l2_fmtdesc ov9640_formats[] = {
+       {
+               /* Note:  V4L2 defines RGB565 as:
+                *
+                *      Byte 0                    Byte 1
+                *      g2 g1 g0 r4 r3 r2 r1 r0   b4 b3 b2 b1 b0 g5 g4 g3
+                *
+                * We interpret RGB565 as:
+                *
+                *      Byte 0                    Byte 1
+                *      g2 g1 g0 b4 b3 b2 b1 b0   r4 r3 r2 r1 r0 g5 g4 g3
+                */
+               .description    = "RGB565, le",
+               .pixelformat    = V4L2_PIX_FMT_RGB565,
+       },{
+               /* Note:  V4L2 defines RGB565X as:
+                *
+                *      Byte 0                    Byte 1
+                *      b4 b3 b2 b1 b0 g5 g4 g3   g2 g1 g0 r4 r3 r2 r1 r0
+                *
+                * We interpret RGB565X as:
+                *
+                *      Byte 0                    Byte 1
+                *      r4 r3 r2 r1 r0 g5 g4 g3   g2 g1 g0 b4 b3 b2 b1 b0
+                */
+               .description    = "RGB565, be",
+               .pixelformat    = V4L2_PIX_FMT_RGB565X,
+       },
+       {
+               .description    = "YUYV (YUV 4:2:2), packed",
+               .pixelformat    = V4L2_PIX_FMT_YUYV,
+       },{
+               .description    = "UYVY, packed",
+               .pixelformat    = V4L2_PIX_FMT_UYVY,
+       },
+       {
+               /* Note:  V4L2 defines RGB555 as:
+                *
+                *      Byte 0                    Byte 1
+                *      g2 g1 g0 r4 r3 r2 r1 r0   x  b4 b3 b2 b1 b0 g4 g3
+                *
+                * We interpret RGB555 as:
+                *
+                *      Byte 0                    Byte 1
+                *      g2 g1 g0 b4 b3 b2 b1 b0   x  r4 r3 r2 r1 r0 g4 g3
+                */
+               .description    = "RGB555, le",
+               .pixelformat    = V4L2_PIX_FMT_RGB555,
+       },{
+               /* Note:  V4L2 defines RGB555X as:
+                *
+                *      Byte 0                    Byte 1
+                *      x  b4 b3 b2 b1 b0 g4 g3   g2 g1 g0 r4 r3 r2 r1 r0
+                *
+                * We interpret RGB555X as:
+                *
+                *      Byte 0                    Byte 1
+                *      x  r4 r3 r2 r1 r0 g4 g3   g2 g1 g0 b4 b3 b2 b1 b0
+                */
+               .description    = "RGB555, be",
+               .pixelformat    = V4L2_PIX_FMT_RGB555X,
+       }
+};
+
+#define NUM_CAPTURE_FORMATS ARRAY_SIZE(ov9640_formats)
+#ifdef CONFIG_ARCH_OMAP24XX
+#define NUM_OVERLAY_FORMATS 4
+#else
+#define NUM_OVERLAY_FORMATS 2
+#endif
+
+/* register initialization tables for OV9640 */
+
+#define OV9640_REG_TERM 0xFF   /* terminating list entry for reg */
+#define OV9640_VAL_TERM 0xFF   /* terminating list entry for val */
+
+/* common OV9640 register initialization for all image sizes, pixel formats, 
+ * and frame rates
+ */
+const static struct ov9640_reg ov9640_common[] = {
+#ifdef CONFIG_ARCH_OMAP24XX
+       { 0x12, 0x80 }, { 0x11, 0x80 }, { 0x13, 0x8F }, /* COM7, CLKRC, COM8 */
+       { 0x01, 0x80 }, { 0x02, 0x80 }, { 0x04, 0x00 }, /* BLUE, RED, COM1 */
+       { 0x0E, 0x81 }, { 0x0F, 0x4F }, { 0x14, 0x4A }, /* COM5, COM6, COM9 */
+#else
+       { 0x12, 0x80 }, { 0x11, 0x80 }, { 0x13, 0x88 }, /* COM7, CLKRC, COM8 */
+       { 0x01, 0x58 }, { 0x02, 0x24 }, { 0x04, 0x00 }, /* BLUE, RED, COM1 */
+       { 0x0E, 0x81 }, { 0x0F, 0x4F }, { 0x14, 0xcA }, /* COM5, COM6, COM9 */
+#endif
+       { 0x16, 0x02 }, { 0x1B, 0x01 }, { 0x24, 0x70 }, /* ?, PSHFT, AEW */
+       { 0x25, 0x68 }, { 0x26, 0xD3 }, { 0x27, 0x90 }, /* AEB, VPT, BBIAS */
+       { 0x2A, 0x00 }, { 0x2B, 0x00 }, { 0x32, 0x24 }, /* EXHCH, EXHCL, HREF */
+       { 0x33, 0x02 }, { 0x37, 0x02 }, { 0x38, 0x13 }, /* CHLF, ADC, ACOM */
+       { 0x39, 0xF0 }, { 0x3A, 0x00 }, { 0x3B, 0x01 }, /* OFON, TSLB, COM11 */
+       { 0x3D, 0x90 }, { 0x3E, 0x02 }, { 0x3F, 0xF2 }, /* COM13, COM14, EDGE */
+       { 0x41, 0x02 }, { 0x42, 0xC8 },         /* COM16, COM17 */
+       { 0x43, 0xF0 }, { 0x44, 0x10 }, { 0x45, 0x6C }, /* ?, ?, ? */
+       { 0x46, 0x6C }, { 0x47, 0x44 }, { 0x48, 0x44 }, /* ?, ?, ? */
+       { 0x49, 0x03 }, { 0x59, 0x49 }, { 0x5A, 0x94 }, /* ?, ?, ? */
+       { 0x5B, 0x46 }, { 0x5C, 0x84 }, { 0x5D, 0x5C }, /* ?, ?, ? */
+       { 0x5E, 0x08 }, { 0x5F, 0x00 }, { 0x60, 0x14 }, /* ?, ?, ? */
+       { 0x61, 0xCE },                                 /* ? */
+       { 0x62, 0x70 }, { 0x63, 0x00 }, { 0x64, 0x04 }, /* LCC1, LCC2, LCC3 */
+       { 0x65, 0x00 }, { 0x66, 0x00 },                 /* LCC4, LCC5 */
+       { 0x69, 0x00 }, { 0x6A, 0x3E }, { 0x6B, 0x3F }, /* HV, MBD, DBLV */
+       { 0x6C, 0x40 }, { 0x6D, 0x30 }, { 0x6E, 0x4B }, /* GSP1, GSP2, GSP3 */
+       { 0x6F, 0x60 }, { 0x70, 0x70 }, { 0x71, 0x70 }, /* GSP4, GSP5, GSP6 */
+       { 0x72, 0x70 }, { 0x73, 0x70 }, { 0x74, 0x60 }, /* GSP7, GSP8, GSP9 */
+       { 0x75, 0x60 }, { 0x76, 0x50 }, { 0x77, 0x48 }, /* GSP10,GSP11,GSP12 */
+       { 0x78, 0x3A }, { 0x79, 0x2E }, { 0x7A, 0x28 }, /* GSP13,GSP14,GSP15 */
+       { 0x7B, 0x22 }, { 0x7C, 0x04 }, { 0x7D, 0x07 }, /* GSP16,GST1, GST2 */
+       { 0x7E, 0x10 }, { 0x7F, 0x28 }, { 0x80, 0x36 }, /* GST3, GST4, GST5 */
+       { 0x81, 0x44 }, { 0x82, 0x52 }, { 0x83, 0x60 }, /* GST6, GST7, GST8 */
+       { 0x84, 0x6C }, { 0x85, 0x78 }, { 0x86, 0x8C }, /* GST9, GST10,GST11 */
+       { 0x87, 0x9E }, { 0x88, 0xBB }, { 0x89, 0xD2 }, /* GST12,GST13,GST14 */
+#ifdef CONFIG_ARCH_OMAP24XX
+       { 0x8A, 0xE6 }, { 0x13, 0x8F }, { 0x00, 0x7F }, /* GST15, COM8 */
+#else
+       { 0x8A, 0xE6 }, { 0x13, 0xaF }, { 0x15, 0x02 }, /* GST15, COM8 */
+       { 0x22, 0x8a }, /* GROS */
+#endif
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+
+/* OV9640 register configuration for all combinations of pixel format and 
+ * image size
+ */
+       /* YUV (YCbCr) QQCIF */
+const static struct ov9640_reg qqcif_yuv[] = {
+       { 0x12, 0x08 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x24 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x0F },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* YUV (YCbCr) QQVGA */
+const static struct ov9640_reg qqvga_yuv[] = {
+       { 0x12, 0x10 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x24 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x0F },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* YUV (YCbCr) QCIF */
+const static struct ov9640_reg qcif_yuv[] = {
+       { 0x12, 0x08 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x0F },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* YUV (YCbCr) QVGA */
+const static struct ov9640_reg qvga_yuv[] = {
+       { 0x12, 0x10 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x0F },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* YUV (YCbCr) CIF */
+const static struct ov9640_reg cif_yuv[] = {
+       { 0x12, 0x20 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x0F },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* YUV (YCbCr) VGA */
+const static struct ov9640_reg vga_yuv[] = {
+       { 0x12, 0x40 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x0F },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* YUV (YCbCr) SXGA */
+const static struct ov9640_reg sxga_yuv[] = {
+       { 0x12, 0x00 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x0F },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB565 QQCIF */
+const static struct ov9640_reg qqcif_565[] = {
+       { 0x12, 0x0C }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x24 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB565 QQVGA */
+const static struct ov9640_reg qqvga_565[] = {
+       { 0x12, 0x14 }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x24 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB565 QCIF */
+const static struct ov9640_reg qcif_565[] = {
+       { 0x12, 0x0C }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB565 QVGA */
+const static struct ov9640_reg qvga_565[] = {
+       { 0x12, 0x14 }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB565 CIF */
+const static struct ov9640_reg cif_565[] = {
+       { 0x12, 0x24 }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB565 VGA */
+const static struct ov9640_reg vga_565[] = {
+       { 0x12, 0x44 }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB565 SXGA */
+const static struct ov9640_reg sxga_565[] = {
+       { 0x12, 0x04 }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB555 QQCIF */
+const static struct ov9640_reg qqcif_555[] = {
+       { 0x12, 0x0C }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x24 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB555 QQVGA */
+const static struct ov9640_reg qqvga_555[] = {
+       { 0x12, 0x14 }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x24 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB555 QCIF */
+const static struct ov9640_reg qcif_555[] = {
+       { 0x12, 0x0C }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB555 QVGA */
+const static struct ov9640_reg qvga_555[] = {
+       { 0x12, 0x14 }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB555 CIF */
+const static struct ov9640_reg cif_555[] = {
+       { 0x12, 0x24 }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB555 VGA */
+const static struct ov9640_reg vga_555[] = {
+       { 0x12, 0x44 }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB555 SXGA */
+const static struct ov9640_reg sxga_555[] = {
+       { 0x12, 0x04 }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+
+#define DEF_GAIN         31
+#define DEF_AUTOGAIN      1
+#define DEF_EXPOSURE    154
+#define DEF_AEC           1
+#define DEF_FREEZE_AGCAEC 0
+#define DEF_BLUE        153
+#define DEF_RED         (255 - DEF_BLUE)
+#define DEF_AWB           1
+#define DEF_HFLIP         0
+#define DEF_VFLIP         0
+
+/* Our own specific controls */
+#define V4L2_CID_FREEZE_AGCAEC V4L2_CID_PRIVATE_BASE+0
+#define V4L2_CID_AUTOEXPOSURE V4L2_CID_PRIVATE_BASE+1
+#define V4L2_CID_LAST_PRIV  V4L2_CID_AUTOEXPOSURE
+
+/*  Video controls  */
+static struct vcontrol {
+        struct v4l2_queryctrl qc;
+        int current_value;
+        u8 reg;
+        u8 mask;
+        u8 start_bit;
+} control[] = {
+        { { V4L2_CID_GAIN, V4L2_CTRL_TYPE_INTEGER, "Gain", 0, 63, 1,
+            DEF_GAIN },
+          0, OV9640_GAIN, 0x3f, 0 },
+        { { V4L2_CID_AUTOGAIN, V4L2_CTRL_TYPE_BOOLEAN, "Auto Gain", 0, 1, 0,
+            DEF_AUTOGAIN },
+          0, OV9640_COM8, 0x04, 2 },
+        { { V4L2_CID_EXPOSURE, V4L2_CTRL_TYPE_INTEGER, "Exposure", 0, 255, 1,
+            DEF_EXPOSURE },
+          0, OV9640_AECH, 0xff, 0 },
+        { { V4L2_CID_AUTOEXPOSURE, V4L2_CTRL_TYPE_BOOLEAN, "Auto Exposure", 0, 1, 0,
+            DEF_AEC },
+          0, OV9640_COM8, 0x01, 0 },
+        { { V4L2_CID_FREEZE_AGCAEC, V4L2_CTRL_TYPE_BOOLEAN, "Freeze AGC/AEC", 0,1,0,
+            DEF_FREEZE_AGCAEC },
+          0, OV9640_COM9, 0x01, 0 },
+        { { V4L2_CID_RED_BALANCE, V4L2_CTRL_TYPE_INTEGER, "Red Balance", 0, 255, 1,
+            DEF_RED },
+          0, OV9640_RED, 0xff, 0 },
+        { { V4L2_CID_BLUE_BALANCE, V4L2_CTRL_TYPE_INTEGER, "Blue Balance", 0, 255, 1,
+            DEF_BLUE },
+          0, OV9640_BLUE, 0xff, 0 },
+        { { V4L2_CID_AUTO_WHITE_BALANCE, V4L2_CTRL_TYPE_BOOLEAN, "Auto White Balance", 0,1,0,
+            DEF_AWB },
+          0, OV9640_COM8, 0x02, 1 },
+        { { V4L2_CID_HFLIP, V4L2_CTRL_TYPE_BOOLEAN, "Mirror Image", 0, 1, 0,
+            DEF_HFLIP },
+          0, OV9640_MVFP, 0x20, 5 },
+        { { V4L2_CID_VFLIP, V4L2_CTRL_TYPE_BOOLEAN, "Vertical Flip", 0, 1, 0,
+            DEF_VFLIP },
+          0, OV9640_MVFP, 0x10, 4 },
+};
+
+#define NUM_CONTROLS ARRAY_SIZE(control)
+
+const static struct ov9640_reg *
+       ov9640_reg_init[NUM_PIXEL_FORMATS][NUM_IMAGE_SIZES] =
+{
+ { qqcif_yuv, qqvga_yuv, qcif_yuv, qvga_yuv, cif_yuv, vga_yuv, sxga_yuv },
+ { qqcif_565, qqvga_565, qcif_565, qvga_565, cif_565, vga_565, sxga_565 },
+ { qqcif_555, qqvga_555, qcif_555, qvga_555, cif_555, vga_555, sxga_555 },
+};
+
+
+/* 
+ * Read a value from a register in an OV9640 sensor device.  The value is 
+ * returned in 'val'.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int 
+ov9640_read_reg(struct i2c_client *client, u8 reg, u8 *val)
+{
+       int err;
+       struct i2c_msg msg[1];
+       unsigned char data[1];
+
+       if (!client->adapter)
+               return -ENODEV;
+
+       msg->addr = client->addr;
+       msg->flags = 0;
+       msg->len = 1;
+       msg->buf = data;
+       *data = reg;
+       err = i2c_transfer(client->adapter, msg, 1);
+       if (err >= 0) {
+               msg->flags = I2C_M_RD;
+               err = i2c_transfer(client->adapter, msg, 1);
+       }
+       if (err >= 0) {
+               *val = *data;
+               return 0;
+       }
+       return err;
+}
+
+/* Write a value to a register in an OV9640 sensor device.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int 
+ov9640_write_reg(struct i2c_client *client, u8 reg, u8 val)
+{
+       int err;
+       struct i2c_msg msg[1];
+       unsigned char data[2];
+
+       if (!client->adapter)
+               return -ENODEV;
+       
+       msg->addr = client->addr;
+       msg->flags = 0;
+       msg->len = 2;
+       msg->buf = data;
+       data[0] = reg;
+       data[1] = val;
+       err = i2c_transfer(client->adapter, msg, 1);
+       if (err >= 0)
+               return 0;
+       return err;
+}
+
+static int 
+ov9640_write_reg_mask(struct i2c_client *client, u8 reg, u8 *val, u8 mask)
+{
+       u8 oldval, newval;
+       int rc;
+
+       if (mask == 0xff)
+               newval = *val;
+       else {
+               /* need to do read - modify - write */
+               if ((rc = ov9640_read_reg(client, reg, &oldval)))
+                       return rc;
+               oldval &= (~mask);              /* Clear the masked bits */
+               *val &= mask;                  /* Enforce mask on value */
+               newval = oldval | *val;        /* Set the desired bits */
+       }
+
+       /* write the new value to the register */
+       if ((rc = ov9640_write_reg(client, reg, newval)))
+               return rc;
+
+       if ((rc = ov9640_read_reg(client, reg, &newval)))
+               return rc;
+
+       *val = newval & mask;
+       return 0;
+}
+
+static int 
+ov9640_read_reg_mask(struct i2c_client *client, u8 reg, u8 *val, u8 mask)
+{
+       int rc;
+
+       if ((rc = ov9640_read_reg(client, reg, val)))
+               return rc;
+       (*val) &= mask;
+
+       return 0;
+}
+
+/* Initialize a list of OV9640 registers.
+ * The list of registers is terminated by the pair of values 
+ * { OV9640_REG_TERM, OV9640_VAL_TERM }.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int 
+ov9640_write_regs(struct i2c_client *client, const struct ov9640_reg reglist[])
+{
+       int err;
+       const struct ov9640_reg *next = reglist;
+       
+       while (!((next->reg == OV9640_REG_TERM) 
+               && (next->val == OV9640_VAL_TERM)))
+       {
+               err = ov9640_write_reg(client, next->reg, next->val);
+               udelay(100);
+               if (err)
+                       return err;
+               next++;
+       }
+       return 0;
+}
+
+/* Returns the index of the requested ID from the control structure array */
+static int
+find_vctrl(int id)
+{
+       int i;
+
+       if (id < V4L2_CID_BASE)
+               return -EDOM;
+
+       for (i = NUM_CONTROLS - 1; i >= 0; i--)
+               if (control[i].qc.id == id)
+                       break;
+       if (i < 0)
+               i = -EINVAL;
+       return i;
+}
+
+/* Calculate the internal clock divisor (value of the CLKRC register) of the 
+ * OV9640 given the image size, the frequency (in Hz) of its XCLK input and a 
+ * desired frame period (in seconds).  The frame period 'fper' is expressed as 
+ * a fraction.  The frame period is an input/output parameter.
+ * Returns the value of the OV9640 CLKRC register that will yield the frame 
+ * period returned in 'fper' at the specified xclk frequency.  The 
+ * returned period will be as close to the requested period as possible.
+ */
+static unsigned char
+ov9640_clkrc(enum image_size isize, unsigned long xclk, struct v4l2_fract *fper)
+{
+       unsigned long fpm, fpm_max;     /* frames per minute */
+       unsigned long divisor;
+       const unsigned long divisor_max = 64;
+#ifdef CONFIG_ARCH_OMAP24XX
+       const static unsigned long clks_per_frame[] =
+               { 200000, 400000, 200000, 400000, 400000, 800000, 3200000 };
+      /*         QQCIF   QQVGA    QCIF    QVGA  CIF     VGA    SXGA
+       *         199680,400000, 199680, 400000, 399360, 800000, 3200000
+       */
+#else
+       const static unsigned long clks_per_frame[] = 
+               { 200000, 200000, 200000, 200000, 400000, 800000, 3200000 };
+#endif
+
+       if (fper->numerator > 0)
+               fpm = (fper->denominator*60)/fper->numerator;
+       else
+               fpm = 0xffffffff;
+       fpm_max = (xclk*60)/clks_per_frame[isize];
+       if (fpm_max == 0)
+               fpm_max = 1;
+       if (fpm > fpm_max)
+               fpm = fpm_max;
+       if (fpm == 0)
+               fpm = 1;
+       divisor = fpm_max/fpm;
+       if (divisor > divisor_max)
+               divisor = divisor_max;
+       fper->numerator = divisor*60;
+       fper->denominator = fpm_max;
+
+       /* try to reduce the fraction */
+       while (!(fper->denominator % 5) && !(fper->numerator % 5)) {
+               fper->numerator /= 5;
+               fper->denominator /= 5;
+       }
+       while (!(fper->denominator % 3) && !(fper->numerator % 3)) {
+               fper->numerator /= 3;
+               fper->denominator /= 3;
+       }
+       while (!(fper->denominator % 2) && !(fper->numerator % 2)) {
+               fper->numerator /= 2;
+               fper->denominator /= 2;
+       }
+       if (fper->numerator < fper->denominator) {
+               if (!(fper->denominator % fper->numerator)) {
+                       fper->denominator /= fper->numerator;
+                       fper->numerator = 1;
+               }
+       }
+       else {
+               if (!(fper->numerator % fper->denominator)) {
+                       fper->numerator /= fper->denominator;
+                       fper->denominator = 1;
+               }
+       }
+
+       /* we set bit 7 in CLKRC to enable the digital PLL */
+       return (0x80 | (divisor - 1));
+}
+
+/* Configure the OV9640 for a specified image size, pixel format, and frame 
+ * period.  xclk is the frequency (in Hz) of the xclk input to the OV9640.  
+ * fper is the frame period (in seconds) expressed as a fraction.
+ * Returns zero if successful, or non-zero otherwise.
+ * The actual frame period is returned in fper.
+ */
+static int
+ov9640_configure(struct i2c_client *client, 
+       enum image_size isize, 
+       enum pixel_format pfmt,
+       unsigned long xclk,
+       struct v4l2_fract *fper)
+{
+       int err;
+       unsigned char clkrc;
+
+       /* common register initialization */
+       err = ov9640_write_regs(client, ov9640_common);
+       if (err)
+               return err;
+
+       /* configure image size and pixel format */
+       err = ov9640_write_regs(client, ov9640_reg_init[pfmt][isize]);
+       if (err)
+               return err;
+
+       /* configure frame rate */
+       clkrc = ov9640_clkrc(isize, xclk, fper);
+       err = ov9640_write_reg(client, OV9640_CLKRC, clkrc);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static int
+ov9640_powerup(void)
+{
+       int err;
+
+       if (machine_is_omap_h2())
+               return 0;
+
+#ifdef CONFIG_OMAP_OSK_MISTRAL
+       if (machine_is_omap_osk())
+               omap_set_gpio_dataout(11, 1);
+#endif
+
+       if (machine_is_omap_h3()) {
+               err = h3_sensor_powerup();
+               if (err)
+                       return err;
+       }
+
+       if (machine_is_omap_h4()) {
+               err = h4_sensor_powerup();
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+static int
+ov9640_powerdown(void)
+{
+       int err;
+
+       if (machine_is_omap_h2())
+               return 0;
+
+#ifdef CONFIG_OMAP_OSK_MISTRAL
+       if (machine_is_omap_osk())
+               omap_set_gpio_dataout(11, 0);
+#endif
+
+       if (machine_is_omap_h3()) {
+               err = h3_sensor_powerdown();
+               if (err)
+                       return err;
+       }
+
+       if (machine_is_omap_h4()) {
+               err = h4_sensor_powerdown();
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int
+ov9640sensor_power_on(void *priv)
+{
+       return ov9640_powerup();
+}
+
+static int
+ov9640sensor_power_off(void *priv)
+{
+       return ov9640_powerdown();
+}
+
+/* Detect if an OV9640 is present, and if so which revision. 
+ * A device is considered to be detected if the manufacturer ID (MIDH and MIDL) 
+ * and the product ID (PID) registers match the expected values.  
+ * Any value of the version ID (VER) register is accepted.
+ * Here are the version numbers we know about:
+ *     0x48 --> OV9640 Revision 1 or OV9640 Revision 2
+ *     0x49 --> OV9640 Revision 3
+ * Returns a negative error number if no device is detected, or the 
+ * non-negative value of the version ID register if a device is detected.
+ */
+static int
+ov9640_detect(struct i2c_client *client)
+{
+       u8 midh, midl, pid, ver;
+
+       if (!client)
+               return -ENODEV;
+       if (ov9640_read_reg(client, OV9640_MIDH, &midh))
+               return -ENODEV;
+       if (ov9640_read_reg(client, OV9640_MIDL, &midl))
+               return -ENODEV;
+       if (ov9640_read_reg(client, OV9640_PID, &pid))
+               return -ENODEV;
+       if (ov9640_read_reg(client, OV9640_VER, &ver))
+               return -ENODEV;
+
+       if ((midh != OV9640_MIDH_MAGIC) 
+               || (midl != OV9640_MIDL_MAGIC)
+               || (pid != OV9640_PID_MAGIC))
+       {
+               /* We didn't read the values we expected, so 
+                * this must not be an OV9640.
+                */
+               return -ENODEV;
+       }
+       return ver;
+}
+
+static struct i2c_driver ov9640sensor_i2c_driver;
+
+/* This function registers an I2C client via i2c_attach_client() for an OV9640 
+ * sensor device.  If 'probe' is non-zero, then the I2C client is only 
+ * registered if the device can be detected.  If 'probe' is zero, then no 
+ * device detection is attempted and the I2C client is always registered.
+ * Returns zero if an I2C client is successfully registered, or non-zero 
+ * otherwise.
+ */
+static int 
+ov9640_i2c_attach_client(struct i2c_adapter *adap, int addr, int probe)
+{
+       struct ov9640_sensor *sensor = &ov9640;
+       struct i2c_client *client = &sensor->client;
+       int err;
+
+       if (client->adapter)
+               return -EBUSY;  /* our client is already attached */
+
+       client->addr = addr;
+       client->driver = &ov9640sensor_i2c_driver;
+       client->adapter = adap;
+       strcpy(client->name, ov9640sensor_i2c_driver.driver.name);
+
+       err = i2c_attach_client(client);
+       if (err) {
+               client->adapter = NULL;
+               return err;
+       }
+
+       if (probe) {
+               err = ov9640_detect(client);
+               if (err < 0) {
+                       i2c_detach_client(client);
+                       client->adapter = NULL;
+                       return err;
+               }
+               sensor->ver = err;
+       }
+       return 0;
+}
+
+/* This function is called by i2c_del_adapter() and i2c_del_driver() 
+ * if the adapter or driver with which this I2C client is associated is 
+ * removed.  This function unregisters the client via i2c_detach_client().
+ * Returns zero if the client is successfully detached, or non-zero 
+ * otherwise.
+ */
+static int 
+ov9640_i2c_detach_client(struct i2c_client *client)
+{
+       int err;
+
+       if (!client->adapter)
+               return -ENODEV; /* our client isn't attached */
+
+       err = i2c_detach_client(client);
+       client->adapter = NULL;
+
+       return err;
+}
+
+/* This function will be called for each registered I2C bus adapter when our 
+ * I2C driver is registered via i2c_add_driver().  It will also be called 
+ * whenever a new I2C adapter is registered after our I2C driver is registered.
+ * This function probes the specified I2C bus adapter to determine if an 
+ * OV9640 sensor device is present.  If a device is detected, an I2C client 
+ * is registered for it via ov9640_i2c_attach_client().  Note that we can't use 
+ * the standard i2c_probe() function to look for the sensor because the OMAP 
+ * I2C controller doesn't support probing.
+ * Returns zero if an OV9640 device is detected and an I2C client successfully 
+ * registered for it, or non-zero otherwise.
+ */
+static int 
+ov9640_i2c_probe_adapter(struct i2c_adapter *adap)
+{
+       return ov9640_i2c_attach_client(adap, OV9640_I2C_ADDR, 1);
+}
+
+/* Find the best match for a requested image capture size.  The best match 
+ * is chosen as the nearest match that has the same number or fewer pixels 
+ * as the requested size, or the smallest image size if the requested size 
+ * has fewer pixels than the smallest image.
+ */
+static enum image_size
+ov9640_find_size(unsigned int width, unsigned int height)
+{
+       enum image_size isize;
+       unsigned long pixels = width*height;
+
+       for (isize = QQCIF; isize < SXGA; isize++) {
+               if (ov9640_sizes[isize + 1].height*
+                       ov9640_sizes[isize + 1].width > pixels)
+               {
+                       return isize;
+               }
+       }
+       return SXGA;
+}
+
+/* following are sensor interface functions implemented by 
+ * OV9640 sensor driver.
+ */
+static int
+ov9640sensor_query_control(struct v4l2_queryctrl *qc, void *priv)
+{
+       int i;
+
+       i = find_vctrl (qc->id);
+       if (i == -EINVAL) {
+               qc->flags = V4L2_CTRL_FLAG_DISABLED;
+               return 0;
+       }
+       if (i < 0)
+               return -EINVAL;
+
+       *qc = control[i].qc;
+       return 0;
+}
+
+static int
+ov9640sensor_get_control(struct v4l2_control *vc, void *priv)
+{
+       struct ov9640_sensor *sensor = (struct ov9640_sensor *) priv;
+       struct i2c_client *client = &sensor->client;
+       int i, val;
+       struct vcontrol * lvc;
+       
+       i = find_vctrl(vc->id);
+       if (i < 0)
+               return -EINVAL;
+
+       lvc = &control[i];      
+       if (ov9640_read_reg_mask(client, lvc->reg, (u8 *)&val, lvc->mask))
+               return -EIO;
+               
+       val = val >> lvc->start_bit;    
+       if (val >= 0) {
+               vc->value = lvc->current_value = val;
+               return 0;
+       } else
+               return val;
+}
+
+static int
+ov9640sensor_set_control(struct v4l2_control *vc, void *priv)
+{
+       struct ov9640_sensor *sensor = (struct ov9640_sensor *) priv;
+       struct i2c_client *client = &sensor->client;
+       struct vcontrol *lvc;
+       int val = vc->value;
+       int i;
+
+       i = find_vctrl(vc->id);
+       if (i < 0)
+               return -EINVAL;
+
+       lvc = &control[i];
+       val = val << lvc->start_bit;
+       if (ov9640_write_reg_mask(client, lvc->reg, (u8 *)&val, (u8)lvc->mask))
+               return -EIO;
+
+       val = val>> lvc->start_bit;
+       if (val >= 0) {
+               lvc->current_value = val;
+               return 0;
+       } else
+               return val;
+}
+
+/* Implement the VIDIOC_ENUM_FMT ioctl for the CAPTURE buffer type.
+ */
+static int
+ov9640sensor_enum_pixformat(struct v4l2_fmtdesc *fmt, void *priv)
+{
+       int index = fmt->index;
+       enum v4l2_buf_type type = fmt->type;
+
+       memset(fmt, 0, sizeof(*fmt));
+       fmt->index = index;
+       fmt->type = type;
+
+       switch (fmt->type) {
+               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               if (index >= NUM_CAPTURE_FORMATS)
+                       return -EINVAL;
+               break;
+
+               case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+               if (index >= NUM_OVERLAY_FORMATS)
+                       return -EINVAL;
+               break;
+
+               default:
+                       return -EINVAL;
+       }
+
+       fmt->flags = ov9640_formats[index].flags;
+       strlcpy(fmt->description, ov9640_formats[index].description, sizeof(fmt->description));
+       fmt->pixelformat = ov9640_formats[index].pixelformat;
+
+       return 0;
+}
+
+/* Implement the VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type.  This 
+ * ioctl is used to negotiate the image capture size and pixel format 
+ * without actually making it take effect.
+ */
+static int
+ov9640sensor_try_format(struct v4l2_pix_format *pix, void *priv)
+{
+       enum image_size isize;
+       int ifmt;
+
+       isize = ov9640_find_size(pix->width, pix->height);
+       pix->width = ov9640_sizes[isize].width;
+       pix->height = ov9640_sizes[isize].height;
+       for (ifmt = 0; ifmt < NUM_CAPTURE_FORMATS; ifmt++) {
+               if (pix->pixelformat == ov9640_formats[ifmt].pixelformat)
+                       break;
+       }
+       if (ifmt == NUM_CAPTURE_FORMATS)
+               ifmt = 0;
+       pix->pixelformat = ov9640_formats[ifmt].pixelformat;
+       pix->field = V4L2_FIELD_NONE;
+       pix->bytesperline = pix->width*2;
+       pix->sizeimage = pix->bytesperline*pix->height;
+       pix->priv = 0;
+       switch (pix->pixelformat) {
+               case V4L2_PIX_FMT_YUYV:
+               case V4L2_PIX_FMT_UYVY:
+               default:
+                       pix->colorspace = V4L2_COLORSPACE_JPEG;
+                       break;
+               case V4L2_PIX_FMT_RGB565:
+               case V4L2_PIX_FMT_RGB565X:
+               case V4L2_PIX_FMT_RGB555:
+               case V4L2_PIX_FMT_RGB555X:
+                       pix->colorspace = V4L2_COLORSPACE_SRGB;
+                       break;
+       }
+       return 0;
+}
+
+/* Given the image capture format in pix, the nominal frame period in 
+ * timeperframe, calculate the required xclk frequency 
+ * The nominal xclk input frequency of the OV9640 is 24MHz, maximum 
+ * frequency is 48MHz, and minimum frequency is 10MHz.
+ */
+static unsigned long
+ov9640sensor_calc_xclk(struct v4l2_pix_format *pix,
+                       struct v4l2_fract *timeperframe, void *priv)
+{
+       unsigned long tgt_xclk;                 /* target xclk */
+       unsigned long tgt_fpm;                  /* target frames per minute */
+       enum image_size isize;
+
+       /* We use arbitrary rules to select the xclk frequency.  If the 
+        * capture size is VGA and the frame rate is greater than 900 
+        * frames per minute, or if the capture size is SXGA and the 
+        * frame rate is greater than 450 frames per minutes, then the 
+        * xclk frequency will be set to 48MHz.  Otherwise, the xclk 
+        * frequency will be set to 24MHz.  If the mclk frequency is such that 
+        * the target xclk frequency is not achievable, then xclk will be set 
+        * as close as to the target as possible.
+        */
+       if ((timeperframe->numerator == 0) 
+               || (timeperframe->denominator == 0))
+       {
+               /* supply a default nominal_timeperframe of 15 fps */
+               timeperframe->numerator = 1;
+               timeperframe->denominator = 15;
+       }
+       tgt_fpm = (timeperframe->denominator*60)
+               / timeperframe->numerator;
+       tgt_xclk = 24000000;
+       isize = ov9640_find_size(pix->width, pix->height);
+       switch (isize) {
+               case SXGA:
+                       if (tgt_fpm > 450)
+                               tgt_xclk = 48000000;
+                       break;
+               case VGA:
+                       if (tgt_fpm > 900)
+                               tgt_xclk = 48000000;
+                       break;
+               default:
+                       break;
+       }
+       return tgt_xclk;
+}
+
+/* Given a capture format in pix, the frame period in timeperframe, and
+ * the xclk frequency, set the capture format of the OV9640 sensor.
+ * The actual frame period will be returned in timeperframe.
+ */
+static int
+ov9640sensor_configure(struct v4l2_pix_format *pix, unsigned long xclk,
+                       struct v4l2_fract *timeperframe, void *priv)
+{
+       struct ov9640_sensor *sensor = (struct ov9640_sensor *) priv;
+       enum pixel_format pfmt = YUV;
+
+       switch (pix->pixelformat) {
+               case V4L2_PIX_FMT_RGB565:
+               case V4L2_PIX_FMT_RGB565X:
+                       pfmt = RGB565;
+                       break;
+               case V4L2_PIX_FMT_RGB555:
+               case V4L2_PIX_FMT_RGB555X:
+                       pfmt = RGB555;
+                       break;
+               case V4L2_PIX_FMT_YUYV:
+               case V4L2_PIX_FMT_UYVY:
+               default:
+                       pfmt = YUV;
+       }
+
+       return ov9640_configure(&sensor->client,
+                               ov9640_find_size(pix->width, pix->height),
+                               pfmt, xclk, timeperframe);
+}
+
+/* Prepare for the driver to exit.
+ * Balances ov9640sensor_init().
+ * This function must de-initialize the sensor and its associated data 
+ * structures.
+ */
+static int
+ov9640sensor_cleanup(void *priv)
+{
+       struct ov9640_sensor *sensor = (struct ov9640_sensor *) priv;
+
+       if (sensor) {
+               i2c_del_driver(&ov9640sensor_i2c_driver);
+               ov9640_powerdown();
+       }
+       return 0;
+}
+
+
+static struct i2c_driver ov9640sensor_i2c_driver = {
+       .driver = {
+               .name           = "ov9640",
+       },
+       .id             = I2C_DRIVERID_MISC, /*FIXME:accroding to i2c-ids.h */
+       .attach_adapter = ov9640_i2c_probe_adapter,
+       .detach_client  = ov9640_i2c_detach_client,
+};
+
+
+/* Initialize the OV9640 sensor.
+ * This routine allocates and initializes the data structure for the sensor, 
+ * powers up the sensor, registers the I2C driver, and sets a default image 
+ * capture format in pix.  The capture format is not actually programmed 
+ * into the OV9640 sensor by this routine.
+ * This function must return a non-NULL value to indicate that 
+ * initialization is successful.
+ */
+static void *
+ov9640sensor_init(struct v4l2_pix_format *pix)
+{
+       struct ov9640_sensor *sensor = &ov9640;
+       int err;
+
+       memset(sensor, 0, sizeof(*sensor));
+       /* power-up the sensor */
+       if (ov9640_powerup())
+               return NULL;
+
+       err = i2c_add_driver(&ov9640sensor_i2c_driver);
+       if (err) {
+               printk(KERN_ERR "Failed to register OV9640 I2C client.\n");
+               return NULL;
+       }
+       if (!sensor->client.adapter) {
+               printk(KERN_WARNING 
+                       "Failed to detect OV9640 sensor chip.\n");
+               return NULL;
+       }
+       else
+               printk(KERN_INFO 
+                       "OV9640 sensor chip version 0x%02x detected\n", sensor->ver);
+
+       /* Make the default capture format QCIF RGB565 */
+       pix->width = ov9640_sizes[QCIF].width;
+       pix->height = ov9640_sizes[QCIF].height;
+       pix->pixelformat = V4L2_PIX_FMT_RGB565;
+       ov9640sensor_try_format(pix, NULL);
+
+       return (void *)sensor;
+}
+
+struct omap_camera_sensor camera_sensor_if = {
+       .version        = 0x01,
+       .name           = "OV9640",
+       .init           = ov9640sensor_init,
+       .cleanup        = ov9640sensor_cleanup,
+       .enum_pixformat = ov9640sensor_enum_pixformat,
+       .try_format     = ov9640sensor_try_format,
+       .calc_xclk      = ov9640sensor_calc_xclk,
+       .configure      = ov9640sensor_configure,
+       .query_control  = ov9640sensor_query_control,
+       .get_control    = ov9640sensor_get_control,
+       .set_control    = ov9640sensor_set_control,
+       .power_on       = ov9640sensor_power_on,
+       .power_off      = ov9640sensor_power_off,
+};
+EXPORT_SYMBOL_GPL(camera_sensor_if);
+
+MODULE_LICENSE("GPL");
+
+#if 0
+void print_ov9640_regs(void *priv)
+{
+       struct ov9640_sensor *sensor = (struct ov9640_sensor *) priv;
+       u8 reg, val;
+       for (reg=0x00; reg <=0x8A; reg++)
+               if (ov9640_read_reg(&sensor->client,reg,&val))
+                       printk("error reading %x\n", reg);
+               else
+                       printk("reg %x = %x\n", reg, val);       
+}
+#endif
index d30540b2761420cff6bf445f761b8d0b27b34b40..796172a26ca8b8cc94e32d6412db0a52c84f7cde 100644 (file)
@@ -37,6 +37,7 @@
 #include <asm/arch/mux.h>
 #include <asm/arch/fpga.h>
 #include <asm/arch/tps65010.h>
+#include <asm/arch/board-sx1.h>
 
 #define        OMAP_MMC_REG_CMD        0x00
 #define        OMAP_MMC_REG_ARGL       0x04
@@ -907,7 +908,9 @@ static void innovator_fpga_socket_power(int on)
  */
 static void mmc_omap_power(struct mmc_omap_host *host, int on)
 {
-       if (on) {
+       if (machine_is_sx1())
+               sx1_setmmcpower(on);
+       else if (on) {
                if (machine_is_omap_innovator())
                        innovator_fpga_socket_power(1);
                else if (machine_is_omap_h2())
index 23fab14f1637cab5fb4ee175ff5eaea6db141915..3d26615c5e670dba62c0277447ee2fd843f945b7 100644 (file)
@@ -345,7 +345,7 @@ static int parse_cmdline_partitions(struct mtd_info *master,
  *
  * This function needs to be visible for bootloaders.
  */
-static int mtdpart_setup(char *s)
+int mtdpart_setup(char *s)
 {
        cmdline = s;
        return 1;
index e8d9ae535673d68d04b547f029dbdadefd6b3e58..a0a12af08aa034db80cf10cafb742d456bacb925 100644 (file)
@@ -61,12 +61,14 @@ static void omap_set_vpp(struct map_info *map, int enable)
 {
        static int      count;
 
-       if (enable) {
-               if (count++ == 0)
-                       OMAP_EMIFS_CONFIG_REG |= OMAP_EMIFS_CONFIG_WP;
-       } else {
-               if (count && (--count == 0))
-                       OMAP_EMIFS_CONFIG_REG &= ~OMAP_EMIFS_CONFIG_WP;
+       if (!cpu_is_omap24xx()) {
+               if (enable) {
+                       if (count++ == 0)
+                               OMAP_EMIFS_CONFIG_REG |= OMAP_EMIFS_CONFIG_WP;
+               } else {
+                       if (count && (--count == 0))
+                               OMAP_EMIFS_CONFIG_REG &= ~OMAP_EMIFS_CONFIG_WP;
+               }
        }
 }
 
@@ -133,11 +135,12 @@ out_free_info:
 static int __devexit omapflash_remove(struct platform_device *pdev)
 {
        struct omapflash_info *info = platform_get_drvdata(pdev);
+       struct flash_platform_data *pdata = pdev->dev.platform_data;
 
        platform_set_drvdata(pdev, NULL);
 
        if (info) {
-               if (info->parts) {
+               if (info->parts || (pdata && pdata->parts)) {
                        del_mtd_partitions(info->mtd);
                        kfree(info->parts);
                } else
index 358f55a82dbe4ebb73b1b0ee460063a6145e3f0e..dac231acacbd08c098913ce16cf7100dd3078c78 100644 (file)
@@ -63,6 +63,19 @@ config MTD_NAND_AMS_DELTA
        help
          Support for NAND flash on Amstrad E3 (Delta).
 
+config MTD_NAND_OMAP
+       tristate "NAND Flash device on OMAP H3/H2/P2 boards"
+       depends on ARM && ARCH_OMAP1 && MTD_NAND && (MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_PERSEUS2)
+       help
+         Support for NAND flash on Texas Instruments H3/H2/P2 platforms.
+
+config MTD_NAND_OMAP_HW
+       bool "OMAP HW NAND Flash controller support"
+        depends on ARM && ARCH_OMAP16XX && MTD_NAND
+
+       help
+         Driver for TI OMAP16xx hardware NAND flash controller.
+
 config MTD_NAND_TOTO
        tristate "NAND Flash device on TOTO board"
        depends on ARCH_OMAP && MTD_NAND && BROKEN
index f7a53f0b70177451680402a2c2cce4c98991cd6e..69da27e2285e107aab70b90915c43f5a03de027e 100644 (file)
@@ -23,6 +23,8 @@ obj-$(CONFIG_MTD_NAND_TS7250)         += ts7250.o
 obj-$(CONFIG_MTD_NAND_NANDSIM)         += nandsim.o
 obj-$(CONFIG_MTD_NAND_CS553X)          += cs553x_nand.o
 obj-$(CONFIG_MTD_NAND_NDFC)            += ndfc.o
+obj-$(CONFIG_MTD_NAND_OMAP)            += omap-nand-flash.o
+obj-$(CONFIG_MTD_NAND_OMAP_HW)         += omap-hw.o
 obj-$(CONFIG_MTD_NAND_AT91)            += at91_nand.o
 
 nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/omap-hw.c b/drivers/mtd/nand/omap-hw.c
new file mode 100644 (file)
index 0000000..3888961
--- /dev/null
@@ -0,0 +1,869 @@
+/*
+ *  drivers/mtd/nand/omap-hw.c
+ *
+ *  This is the MTD driver for OMAP1710 internal HW NAND controller.
+ *
+ *  Copyright (C) 2004-2006 Nokia Corporation
+ *
+ *  Author: Jarkko Lavinen <jarkko.lavinen@nokia.com> and
+ *          Juha Yrjölä <juha.yrjola@nokia.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.
+ *
+ * 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; see the file COPYING. If not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/dma.h>
+
+#define NAND_BASE              0xfffbcc00
+#define NND_REVISION           0x00
+#define NND_ACCESS             0x04
+#define NND_ADDR_SRC           0x08
+#define NND_CTRL               0x10
+#define NND_MASK               0x14
+#define NND_STATUS             0x18
+#define NND_READY              0x1c
+#define NND_COMMAND            0x20
+#define NND_COMMAND_SEC                0x24
+#define NND_ECC_SELECT         0x28
+#define NND_ECC_START          0x2c
+#define NND_ECC_9              0x4c
+#define NND_RESET              0x50
+#define NND_FIFO               0x54
+#define NND_FIFOCTRL           0x58
+#define NND_PSC_CLK            0x5c
+#define NND_SYSTEST            0x60
+#define NND_SYSCFG             0x64
+#define NND_SYSSTATUS          0x68
+#define NND_FIFOTEST1          0x6c
+#define NND_FIFOTEST2          0x70
+#define NND_FIFOTEST3          0x74
+#define NND_FIFOTEST4          0x78
+#define NND_PSC1_CLK           0x8c
+#define NND_PSC2_CLK           0x90
+
+
+#define NND_CMD_READ1_LOWER    0x00
+#define NND_CMD_WRITE1_LOWER   0x00
+#define NND_CMD_READ1_UPPER    0x01
+#define NND_CMD_WRITE1_UPPER   0x01
+#define NND_CMD_PROGRAM_END    0x10
+#define NND_CMD_READ2_SPARE    0x50
+#define NND_CMD_WRITE2_SPARE   0x50
+#define NND_CMD_ERASE          0x60
+#define NND_CMD_STATUS         0x70
+#define NND_CMD_PROGRAM                0x80
+#define NND_CMD_READ_ID                0x90
+#define NND_CMD_ERASE_END      0xD0
+#define NND_CMD_RESET          0xFF
+
+
+#define NAND_Ecc_P1e           (1 << 0)
+#define NAND_Ecc_P2e           (1 << 1)
+#define NAND_Ecc_P4e           (1 << 2)
+#define NAND_Ecc_P8e           (1 << 3)
+#define NAND_Ecc_P16e          (1 << 4)
+#define NAND_Ecc_P32e          (1 << 5)
+#define NAND_Ecc_P64e          (1 << 6)
+#define NAND_Ecc_P128e         (1 << 7)
+#define NAND_Ecc_P256e         (1 << 8)
+#define NAND_Ecc_P512e         (1 << 9)
+#define NAND_Ecc_P1024e                (1 << 10)
+#define NAND_Ecc_P2048e                (1 << 11)
+
+#define NAND_Ecc_P1o           (1 << 16)
+#define NAND_Ecc_P2o           (1 << 17)
+#define NAND_Ecc_P4o           (1 << 18)
+#define NAND_Ecc_P8o           (1 << 19)
+#define NAND_Ecc_P16o          (1 << 20)
+#define NAND_Ecc_P32o          (1 << 21)
+#define NAND_Ecc_P64o          (1 << 22)
+#define NAND_Ecc_P128o         (1 << 23)
+#define NAND_Ecc_P256o         (1 << 24)
+#define NAND_Ecc_P512o         (1 << 25)
+#define NAND_Ecc_P1024o                (1 << 26)
+#define NAND_Ecc_P2048o                (1 << 27)
+
+#define TF(value)      (value ? 1 : 0)
+
+#define P2048e(a)      (TF(a & NAND_Ecc_P2048e)        << 0 )
+#define P2048o(a)      (TF(a & NAND_Ecc_P2048o)        << 1 )
+#define P1e(a)         (TF(a & NAND_Ecc_P1e)           << 2 )
+#define P1o(a)         (TF(a & NAND_Ecc_P1o)           << 3 )
+#define P2e(a)         (TF(a & NAND_Ecc_P2e)           << 4 )
+#define P2o(a)         (TF(a & NAND_Ecc_P2o)           << 5 )
+#define P4e(a)         (TF(a & NAND_Ecc_P4e)           << 6 )
+#define P4o(a)         (TF(a & NAND_Ecc_P4o)           << 7 )
+
+#define P8e(a)         (TF(a & NAND_Ecc_P8e)           << 0 )
+#define P8o(a)         (TF(a & NAND_Ecc_P8o)           << 1 )
+#define P16e(a)                (TF(a & NAND_Ecc_P16e)          << 2 )
+#define P16o(a)                (TF(a & NAND_Ecc_P16o)          << 3 )
+#define P32e(a)                (TF(a & NAND_Ecc_P32e)          << 4 )
+#define P32o(a)                (TF(a & NAND_Ecc_P32o)          << 5 )
+#define P64e(a)                (TF(a & NAND_Ecc_P64e)          << 6 )
+#define P64o(a)                (TF(a & NAND_Ecc_P64o)          << 7 )
+
+#define P128e(a)       (TF(a & NAND_Ecc_P128e)         << 0 )
+#define P128o(a)       (TF(a & NAND_Ecc_P128o)         << 1 )
+#define P256e(a)       (TF(a & NAND_Ecc_P256e)         << 2 )
+#define P256o(a)       (TF(a & NAND_Ecc_P256o)         << 3 )
+#define P512e(a)       (TF(a & NAND_Ecc_P512e)         << 4 )
+#define P512o(a)       (TF(a & NAND_Ecc_P512o)         << 5 )
+#define P1024e(a)      (TF(a & NAND_Ecc_P1024e)        << 6 )
+#define P1024o(a)      (TF(a & NAND_Ecc_P1024o)        << 7 )
+
+#define P8e_s(a)       (TF(a & NAND_Ecc_P8e)           << 0 )
+#define P8o_s(a)       (TF(a & NAND_Ecc_P8o)           << 1 )
+#define P16e_s(a)      (TF(a & NAND_Ecc_P16e)          << 2 )
+#define P16o_s(a)      (TF(a & NAND_Ecc_P16o)          << 3 )
+#define P1e_s(a)       (TF(a & NAND_Ecc_P1e)           << 4 )
+#define P1o_s(a)       (TF(a & NAND_Ecc_P1o)           << 5 )
+#define P2e_s(a)       (TF(a & NAND_Ecc_P2e)           << 6 )
+#define P2o_s(a)       (TF(a & NAND_Ecc_P2o)           << 7 )
+
+#define P4e_s(a)       (TF(a & NAND_Ecc_P4e)           << 0 )
+#define P4o_s(a)       (TF(a & NAND_Ecc_P4o)           << 1 )
+
+extern struct nand_oobinfo jffs2_oobinfo;
+
+/*
+ * MTD structure for OMAP board
+ */
+static struct mtd_info *omap_mtd;
+static struct clk *omap_nand_clk;
+static int omap_nand_dma_ch;
+static struct completion omap_nand_dma_comp;
+static unsigned long omap_nand_base = io_p2v(NAND_BASE);
+
+static inline u32 nand_read_reg(int idx)
+{
+       return __raw_readl(omap_nand_base + idx);
+}
+
+static inline void nand_write_reg(int idx, u32 val)
+{
+       __raw_writel(val, omap_nand_base + idx);
+}
+
+static inline u8 nand_read_reg8(int idx)
+{
+       return __raw_readb(omap_nand_base + idx);
+}
+
+static inline void nand_write_reg8(int idx, u8 val)
+{
+       __raw_writeb(val, omap_nand_base + idx);
+}
+
+static void omap_nand_select_chip(struct mtd_info *mtd, int chip)
+{
+       u32 l;
+
+       switch(chip) {
+       case -1:
+               l = nand_read_reg(NND_CTRL);
+               l |= (1 << 8) | (1 << 10) | (1 << 12) | (1 << 14);
+               nand_write_reg(NND_CTRL, l);
+               break;
+       case 0:
+               /* Also CS1, CS2, CS4 would be available */
+               l = nand_read_reg(NND_CTRL);
+               l &= ~(1 << 8);
+               nand_write_reg(NND_CTRL, l);
+               break;
+       default:
+               BUG();
+       }
+}
+
+static void nand_dma_cb(int lch, u16 ch_status, void *data)
+{
+       complete((struct completion *) data);
+}
+
+static void omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
+                                         unsigned int u32_count, int is_write)
+{
+       const int block_size = 16;
+       unsigned int block_count, len;
+       int dma_ch;
+       unsigned long fifo_reg, timeout, jiffies_before, jiffies_spent;
+       static unsigned long max_jiffies = 0;
+
+       dma_ch = omap_nand_dma_ch;
+       block_count = u32_count * 4 / block_size;
+       nand_write_reg(NND_STATUS, 0x0f);
+       nand_write_reg(NND_FIFOCTRL, (block_size << 24) | block_count);
+       fifo_reg = NAND_BASE + NND_FIFO;
+       if (is_write) {
+               omap_set_dma_dest_params(dma_ch, OMAP_DMA_PORT_TIPB,
+                                        OMAP_DMA_AMODE_CONSTANT, fifo_reg,
+                                        0, 0);
+               omap_set_dma_src_params(dma_ch, OMAP_DMA_PORT_EMIFF,
+                                       OMAP_DMA_AMODE_POST_INC,
+                                       virt_to_phys(addr),
+                                       0, 0);
+//             omap_set_dma_src_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4);
+               /* Set POSTWRITE bit */
+               nand_write_reg(NND_CTRL, nand_read_reg(NND_CTRL) | (1 << 16));
+       } else {
+               omap_set_dma_src_params(dma_ch, OMAP_DMA_PORT_TIPB,
+                                       OMAP_DMA_AMODE_CONSTANT, fifo_reg,
+                                       0, 0);
+               omap_set_dma_dest_params(dma_ch, OMAP_DMA_PORT_EMIFF,
+                                        OMAP_DMA_AMODE_POST_INC,
+                                        virt_to_phys(addr),
+                                        0, 0);
+//             omap_set_dma_dest_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_8);
+               /* Set PREFETCH bit */
+               nand_write_reg(NND_CTRL, nand_read_reg(NND_CTRL) | (1 << 17));
+       }
+       omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S32, block_size / 4,
+                                    block_count, OMAP_DMA_SYNC_FRAME,
+                                    0, 0);
+       init_completion(&omap_nand_dma_comp);
+
+       len = u32_count << 2;
+       consistent_sync(addr, len, DMA_TO_DEVICE);
+       omap_start_dma(dma_ch);
+       jiffies_before = jiffies;
+       timeout = wait_for_completion_timeout(&omap_nand_dma_comp,
+                                             msecs_to_jiffies(1000));
+       jiffies_spent = (unsigned long)((long)jiffies - (long)jiffies_before);
+       if (jiffies_spent > max_jiffies)
+               max_jiffies = jiffies_spent;
+
+       if (timeout == 0) {
+               printk(KERN_WARNING "omap-hw-nand: DMA timeout after %u ms, max. seen latency %u ms\n",
+                      jiffies_to_msecs(jiffies_spent),
+                      jiffies_to_msecs(max_jiffies));
+               if (OMAP_DMA_CCR_REG(dma_ch) & (1 << 7)) {
+                       /* If the DMA transfer is still running, something
+                        * is really wrong. */
+                       printk(KERN_ERR "omap-hw-nand: DMA transfer still running. Not good.\n");
+                       printk(KERN_INFO "DMA ch %d: CCR %04x, CSR %04x, CCDEN_L %04x\n",
+                              dma_ch, omap_readw(OMAP_DMA_CCR_REG(dma_ch)), omap_readw(OMAP_DMA_CSR_REG(dma_ch)),
+                              omap_readw(OMAP_DMA_BASE + 0x40 * (dma_ch) + 0x34));
+               }
+       }
+       if (!is_write)
+               consistent_sync(addr, len, DMA_FROM_DEVICE);
+
+       nand_write_reg(NND_CTRL, nand_read_reg(NND_CTRL) & ~((1 << 16) | (1 << 17)));
+}
+
+static void fifo_read(u32 *out, unsigned int len)
+{
+       const int block_size = 16;
+       unsigned long status_reg, fifo_reg;
+       int c;
+
+       status_reg = omap_nand_base + NND_STATUS;
+       fifo_reg = omap_nand_base + NND_FIFO;
+       len = len * 4 / block_size;
+       nand_write_reg(NND_FIFOCTRL, (block_size << 24) | len);
+       nand_write_reg(NND_STATUS, 0x0f);
+       nand_write_reg(NND_CTRL, nand_read_reg(NND_CTRL) | (1 << 17));
+       c = block_size / 4;
+       while (len--) {
+               int i;
+
+               while ((__raw_readl(status_reg) & (1 << 2)) == 0);
+               __raw_writel(0x0f, status_reg);
+               for (i = 0; i < c; i++) {
+                       u32 l = __raw_readl(fifo_reg);
+                       *out++ = l;
+               }
+       }
+       nand_write_reg(NND_CTRL, nand_read_reg(NND_CTRL) & ~(1 << 17));
+       nand_write_reg(NND_STATUS, 0x0f);
+}
+
+static void omap_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+       unsigned long access_reg;
+
+       if (likely(((unsigned long) buf & 3) == 0 && (len & 3) == 0)) {
+               int u32_count = len >> 2;
+               u32 *dest = (u32 *) buf;
+               /* If the transfer is big enough and the length divisible by
+                * 16, we try to use DMA transfer, or FIFO copy in case of
+                * DMA failure (e.g. all channels busy) */
+               if (u32_count > 64 && (u32_count & 3) == 0) {
+                       if (omap_nand_dma_ch >= 0) {
+                               omap_nand_dma_transfer(mtd, buf, u32_count, 0);
+                               return;
+                       }
+                       /* In case of an error, fallback to FIFO copy */
+                       fifo_read((u32 *) buf, u32_count);
+                       return;
+               }
+               access_reg = omap_nand_base + NND_ACCESS;
+               /* Small buffers we just read directly */
+               while (u32_count--)
+                       *dest++ = __raw_readl(access_reg);
+       } else {
+               /* If we're not word-aligned, we use byte copy */
+               access_reg = omap_nand_base + NND_ACCESS;
+               while (len--)
+                       *buf++ = __raw_readb(access_reg);
+       }
+}
+
+static void omap_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+       if (likely(((unsigned long) buf & 3) == 0 && (len & 3) == 0)) {
+               const u32 *src = (const u32 *) buf;
+
+               len >>= 2;
+#if 0
+               /* If the transfer is big enough and length divisible by 16,
+                * we try to use DMA transfer. */
+               if (len > 256 / 4 && (len & 3) == 0) {
+                       if (omap_nand_dma_transfer(mtd, (void *) buf, len, 1) == 0)
+                               return;
+                       /* In case of an error, fallback to CPU copy */
+               }
+#endif
+               while (len--)
+                       nand_write_reg(NND_ACCESS, *src++);
+       } else {
+               while (len--)
+                       nand_write_reg8(NND_ACCESS, *buf++);
+       }
+}
+
+static int omap_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+       if (likely(((unsigned long) buf & 3) == 0 && (len & 3) == 0)) {
+               const u32 *dest = (const u32 *) buf;
+               len >>= 2;
+               while (len--)
+                       if (*dest++ != nand_read_reg(NND_ACCESS))
+                               return -EFAULT;
+       } else {
+               while (len--)
+                       if (*buf++ != nand_read_reg8(NND_ACCESS))
+                               return -EFAULT;
+       }
+       return 0;
+}
+
+static u_char omap_nand_read_byte(struct mtd_info *mtd)
+{
+       return nand_read_reg8(NND_ACCESS);
+}
+
+static int omap_nand_dev_ready(struct mtd_info *mtd)
+{
+       u32 l;
+
+       l = nand_read_reg(NND_READY);
+       return l & 0x01;
+}
+
+static int nand_write_command(u8 cmd, u32 addr, int addr_valid)
+{
+       if (addr_valid) {
+               nand_write_reg(NND_ADDR_SRC, addr);
+               nand_write_reg8(NND_COMMAND, cmd);
+       } else {
+               nand_write_reg(NND_ADDR_SRC, 0);
+               nand_write_reg8(NND_COMMAND_SEC, cmd);
+       }
+       while (!omap_nand_dev_ready(NULL));
+       return 0;
+}
+
+/*
+ * Send command to NAND device
+ */
+static void omap_nand_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
+{
+       struct nand_chip *this = mtd->priv;
+
+       /*
+        * Write out the command to the device.
+        */
+       if (command == NAND_CMD_SEQIN) {
+               int readcmd;
+
+               if (column >= mtd->writesize) {
+                       /* OOB area */
+                       column -= mtd->writesize;
+                       readcmd = NAND_CMD_READOOB;
+               } else if (column < 256) {
+                       /* First 256 bytes --> READ0 */
+                       readcmd = NAND_CMD_READ0;
+               } else {
+                       column -= 256;
+                       readcmd = NAND_CMD_READ1;
+               }
+               nand_write_command(readcmd, 0, 0);
+       }
+       switch (command) {
+       case NAND_CMD_RESET:
+       case NAND_CMD_PAGEPROG:
+       case NAND_CMD_STATUS:
+       case NAND_CMD_ERASE2:
+               nand_write_command(command, 0, 0);
+               break;
+       case NAND_CMD_ERASE1:
+               nand_write_command(command, ((page_addr & 0xFFFFFF00) << 1) | (page_addr & 0XFF), 1);
+               break;
+       default:
+               nand_write_command(command, (page_addr << this->page_shift) | column, 1);
+       }
+}
+
+static void omap_nand_command_lp(struct mtd_info *mtd, unsigned command, int column, int page_addr)
+{
+       struct nand_chip *this = mtd->priv;
+
+       if (command == NAND_CMD_READOOB) {
+               column += mtd->writesize;
+               command = NAND_CMD_READ0;
+       }
+       switch (command) {
+       case NAND_CMD_RESET:
+       case NAND_CMD_PAGEPROG:
+       case NAND_CMD_STATUS:
+       case NAND_CMD_ERASE2:           
+               nand_write_command(command, 0, 0);
+               break;
+       case NAND_CMD_ERASE1:
+               nand_write_command(command, page_addr << this->page_shift >> 11, 1);
+               break;
+       default:
+               nand_write_command(command, (page_addr << 16) | column, 1);
+       }
+       if (command == NAND_CMD_READ0)
+               nand_write_command(NAND_CMD_READSTART, 0, 0);
+}
+
+/*
+ * Generate non-inverted ECC bytes.
+ *
+ * Using noninverted ECC can be considered ugly since writing a blank
+ * page ie. padding will clear the ECC bytes. This is no problem as long
+ * nobody is trying to write data on the seemingly unused page.
+ *
+ * Reading an erased page will produce an ECC mismatch between
+ * generated and read ECC bytes that has to be dealt with separately.
+ */
+static int omap_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
+{
+       u32 l;
+       int reg;
+       int n;
+       struct nand_chip *this = mtd->priv;
+
+       /* Ex NAND_ECC_HW12_2048 */
+       if ((this->ecc.mode == NAND_ECC_HW) && (this->ecc.size  == 2048))
+               n = 4;
+       else
+               n = 1;
+       reg = NND_ECC_START;
+       while (n--) {
+               l = nand_read_reg(reg);
+               *ecc_code++ = l;          // P128e, ..., P1e
+               *ecc_code++ = l >> 16;    // P128o, ..., P1o
+               // P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e
+               *ecc_code++ = ((l >> 8) & 0x0f) | ((l >> 20) & 0xf0);
+               reg += 4;
+       }
+       return 0;
+}
+
+/*
+ * This function will generate true ECC value, which can be used
+ * when correcting data read from NAND flash memory core
+ */
+static void gen_true_ecc(u8 *ecc_buf)
+{
+       u32 tmp = ecc_buf[0] | (ecc_buf[1] << 16) | ((ecc_buf[2] & 0xF0) << 20) | ((ecc_buf[2] & 0x0F) << 8);
+
+       ecc_buf[0] = ~(P64o(tmp) | P64e(tmp) | P32o(tmp) | P32e(tmp) | P16o(tmp) | P16e(tmp) | P8o(tmp) | P8e(tmp) );
+       ecc_buf[1] = ~(P1024o(tmp) | P1024e(tmp) | P512o(tmp) | P512e(tmp) | P256o(tmp) | P256e(tmp) | P128o(tmp) | P128e(tmp));
+       ecc_buf[2] = ~( P4o(tmp) | P4e(tmp) | P2o(tmp) | P2e(tmp) | P1o(tmp) | P1e(tmp) | P2048o(tmp) | P2048e(tmp));
+}
+
+/*
+ * This function compares two ECC's and indicates if there is an error.
+ * If the error can be corrected it will be corrected to the buffer
+ */
+static int omap_nand_compare_ecc(u8 *ecc_data1,   /* read from NAND memory */
+                                u8 *ecc_data2,   /* read from register */
+                                u8 *page_data)
+{
+       uint   i;
+       u8     tmp0_bit[8], tmp1_bit[8], tmp2_bit[8];
+       u8     comp0_bit[8], comp1_bit[8], comp2_bit[8];
+       u8     ecc_bit[24];
+       u8     ecc_sum = 0;
+       u8     find_bit = 0;
+       uint   find_byte = 0;
+       int    isEccFF;
+
+       isEccFF = ((*(u32 *)ecc_data1 & 0xFFFFFF) == 0xFFFFFF);
+
+       gen_true_ecc(ecc_data1);
+       gen_true_ecc(ecc_data2);
+
+       for (i = 0; i <= 2; i++) {
+               *(ecc_data1 + i) = ~(*(ecc_data1 + i));
+               *(ecc_data2 + i) = ~(*(ecc_data2 + i));
+       }
+
+       for (i = 0; i < 8; i++) {
+               tmp0_bit[i]      = *ecc_data1 % 2;
+               *ecc_data1       = *ecc_data1 / 2;
+       }
+
+       for (i = 0; i < 8; i++) {
+               tmp1_bit[i]      = *(ecc_data1 + 1) % 2;
+               *(ecc_data1 + 1) = *(ecc_data1 + 1) / 2;
+       }
+
+       for (i = 0; i < 8; i++) {
+               tmp2_bit[i]      = *(ecc_data1 + 2) % 2;
+               *(ecc_data1 + 2) = *(ecc_data1 + 2) / 2;
+       }
+
+       for (i = 0; i < 8; i++) {
+               comp0_bit[i]     = *ecc_data2 % 2;
+               *ecc_data2       = *ecc_data2 / 2;
+       }
+
+       for (i = 0; i < 8; i++) {
+               comp1_bit[i]     = *(ecc_data2 + 1) % 2;
+               *(ecc_data2 + 1) = *(ecc_data2 + 1) / 2;
+       }
+
+       for (i = 0; i < 8; i++) {
+               comp2_bit[i]     = *(ecc_data2 + 2) % 2;
+               *(ecc_data2 + 2) = *(ecc_data2 + 2) / 2;
+       }
+
+       for (i = 0; i< 6; i++ )
+               ecc_bit[i] = tmp2_bit[i + 2] ^ comp2_bit[i + 2];
+
+       for (i = 0; i < 8; i++)
+               ecc_bit[i + 6] = tmp0_bit[i] ^ comp0_bit[i];
+
+       for (i = 0; i < 8; i++)
+               ecc_bit[i + 14] = tmp1_bit[i] ^ comp1_bit[i];
+
+       ecc_bit[22] = tmp2_bit[0] ^ comp2_bit[0];
+       ecc_bit[23] = tmp2_bit[1] ^ comp2_bit[1];
+
+       for (i = 0; i < 24; i++)
+               ecc_sum += ecc_bit[i];
+
+       switch (ecc_sum) {
+       case 0:
+               /* Not reached because this function is not called if
+                  ECC values are equal */
+               return 0;
+
+       case 1:
+               /* Uncorrectable error */
+               DEBUG (MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR 1\n");
+               return -1;
+
+       case 12:
+               /* Correctable error */
+               find_byte = (ecc_bit[23] << 8) + 
+                           (ecc_bit[21] << 7) + 
+                           (ecc_bit[19] << 6) +
+                           (ecc_bit[17] << 5) +
+                           (ecc_bit[15] << 4) +
+                           (ecc_bit[13] << 3) +
+                           (ecc_bit[11] << 2) +
+                           (ecc_bit[9]  << 1) +
+                           ecc_bit[7];
+
+               find_bit = (ecc_bit[5] << 2) + (ecc_bit[3] << 1) + ecc_bit[1];
+
+               DEBUG (MTD_DEBUG_LEVEL0, "Correcting single bit ECC error at offset: %d, bit: %d\n", find_byte, find_bit);
+
+               page_data[find_byte] ^= (1 << find_bit);
+
+               return 0;
+       default:
+               if (isEccFF) {
+                       if (ecc_data2[0] == 0 && ecc_data2[1] == 0 && ecc_data2[2] == 0)
+                               return 0;
+               } 
+               DEBUG (MTD_DEBUG_LEVEL0, "UNCORRECTED_ERROR default\n");
+               return -1;
+       }
+}
+
+static int omap_nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
+{
+       struct nand_chip *this;
+       int block_count = 0, i, r;
+
+       this = mtd->priv;
+       /* Ex NAND_ECC_HW12_2048 */
+       if ((this->ecc.mode == NAND_ECC_HW) && (this->ecc.size  == 2048))
+               block_count = 4;
+       else
+               block_count = 1;
+       for (i = 0; i < block_count; i++) {
+               if (memcmp(read_ecc, calc_ecc, 3) != 0) {
+                       r = omap_nand_compare_ecc(read_ecc, calc_ecc, dat);
+                       if (r < 0)
+                               return r;
+               }
+               read_ecc += 3;
+               calc_ecc += 3;
+               dat += 512;
+       }
+       return 0;
+}
+
+static void omap_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+       nand_write_reg(NND_RESET, 0x01);
+}
+
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+
+extern int mtdpart_setup(char *);
+
+static int __init add_dynamic_parts(struct mtd_info *mtd)
+{
+       static const char *part_parsers[] = { "cmdlinepart", NULL };
+       struct mtd_partition *parts;
+       const struct omap_flash_part_str_config *cfg;
+       char *part_str = NULL;
+       size_t part_str_len;
+       int c;
+
+       cfg = omap_get_var_config(OMAP_TAG_FLASH_PART_STR, &part_str_len);
+       if (cfg != NULL) {
+               part_str = kmalloc(part_str_len + 1, GFP_KERNEL);
+               if (part_str == NULL)
+                       return -ENOMEM;
+               memcpy(part_str, cfg->part_table, part_str_len);
+               part_str[part_str_len] = '\0';
+               mtdpart_setup(part_str);
+       }
+       c = parse_mtd_partitions(omap_mtd, part_parsers, &parts, 0);
+       if (part_str != NULL) {
+               mtdpart_setup(NULL);
+               kfree(part_str);
+       }
+       if (c <= 0)
+               return -1;
+
+       add_mtd_partitions(mtd, parts, c);
+
+       return 0;
+}
+
+#else
+
+static inline int add_dynamic_parts(struct mtd_info *mtd)
+{
+       return -1;
+}
+
+#endif
+
+static inline int calc_psc(int ns, int cycle_ps)
+{
+       return (ns * 1000 + (cycle_ps - 1)) / cycle_ps;
+}
+
+static void set_psc_regs(int psc_ns, int psc1_ns, int psc2_ns)
+{
+       int psc[3], i;
+       unsigned long rate, ps;
+
+       rate = clk_get_rate(omap_nand_clk);
+       ps = 1000000000 / (rate / 1000);
+       psc[0] = calc_psc(psc_ns, ps);
+       psc[1] = calc_psc(psc1_ns, ps);
+       psc[2] = calc_psc(psc2_ns, ps);
+       for (i = 0; i < 3; i++) {
+               if (psc[i] < 2)
+                       psc[i] = 2;
+               else if (psc[i] > 256)
+                       psc[i] = 256;
+       }
+       nand_write_reg(NND_PSC_CLK, psc[0] - 1);
+       nand_write_reg(NND_PSC1_CLK, psc[1] - 1);
+       nand_write_reg(NND_PSC2_CLK, psc[2] - 1);
+       printk(KERN_INFO "omap-hw-nand: using PSC values %d, %d, %d\n", psc[0], psc[1], psc[2]);
+}
+
+/*
+ * Main initialization routine
+ */
+static int __init omap_nand_init(void)
+{
+       struct nand_chip *this;
+       int err = 0;
+       u32 l;
+
+       omap_nand_clk = clk_get(NULL, "armper_ck");
+       BUG_ON(omap_nand_clk == NULL);
+       clk_enable(omap_nand_clk);
+
+       l = nand_read_reg(NND_REVISION);        
+       printk(KERN_INFO "omap-hw-nand: OMAP NAND Controller rev. %d.%d\n", l>>4, l & 0xf);
+
+       /* Reset the NAND Controller */
+       nand_write_reg(NND_SYSCFG, 0x02);
+       while ((nand_read_reg(NND_SYSSTATUS) & 0x01) == 0);
+
+       /* No Prefetch, no postwrite, write prot & enable pairs disabled,
+          addres counter set to send 4 byte addresses to flash,
+          A8 is set not to be sent to flash (erase addre needs formatting),
+          choose little endian, enable 512 byte ECC logic,        
+        */
+       nand_write_reg(NND_CTRL, 0xFF01);
+
+       /* Allocate memory for MTD device structure and private data */
+       omap_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
+       if (!omap_mtd) {
+               printk(KERN_WARNING "omap-hw-nand: Unable to allocate OMAP NAND MTD device structure.\n");
+               err = -ENOMEM;
+               goto free_clock;
+       }
+#if 1
+       err = omap_request_dma(OMAP_DMA_NAND, "NAND", nand_dma_cb,
+                              &omap_nand_dma_comp, &omap_nand_dma_ch);
+       if (err < 0) {
+               printk(KERN_WARNING "omap-hw-nand: Unable to reserve DMA channel\n");
+               omap_nand_dma_ch = -1;
+       }
+#else
+       omap_nand_dma_ch = -1;
+#endif
+       /* Get pointer to private data */
+       this = (struct nand_chip *) (&omap_mtd[1]);
+
+       /* Initialize structures */
+       memset((char *) omap_mtd, 0, sizeof(struct mtd_info));
+       memset((char *) this, 0, sizeof(struct nand_chip));
+
+       /* Link the private data with the MTD structure */
+       omap_mtd->priv = this;
+       omap_mtd->name = "omap-nand";
+
+       this->options = NAND_SKIP_BBTSCAN;
+
+       /* Used from chip select and nand_command() */
+       this->read_byte = omap_nand_read_byte;
+
+       this->select_chip   = omap_nand_select_chip;
+       this->dev_ready     = omap_nand_dev_ready;
+       this->chip_delay    = 0;
+       this->ecc.mode      = NAND_ECC_HW;
+       this->ecc.bytes     = 3;
+       this->ecc.size      = 512;
+       this->cmdfunc       = omap_nand_command;
+       this->write_buf     = omap_nand_write_buf;
+       this->read_buf      = omap_nand_read_buf;
+       this->verify_buf    = omap_nand_verify_buf;
+       this->ecc.calculate = omap_nand_calculate_ecc;
+       this->ecc.correct   = omap_nand_correct_data;
+       this->ecc.hwctl     = omap_nand_enable_hwecc;
+
+       nand_write_reg(NND_SYSCFG, 0x1); /* Enable auto idle */
+       nand_write_reg(NND_PSC_CLK, 10);
+       /* Scan to find existance of the device */
+       if (nand_scan(omap_mtd, 1)) {
+               err = -ENXIO;
+               goto out_mtd;
+       }
+
+       set_psc_regs(25, 15, 35);
+       if (this->page_shift == 11) {
+               this->cmdfunc = omap_nand_command_lp;
+               l = nand_read_reg(NND_CTRL);
+               l |= 1 << 4; /* Set the A8 bit in CTRL reg */
+               nand_write_reg(NND_CTRL, l);
+               this->ecc.mode = NAND_ECC_HW;
+               this->ecc.steps = 1;
+               this->ecc.size = 2048;
+               this->ecc.bytes = 12;
+               omap_mtd->eccsize = 2048;
+               nand_write_reg(NND_ECC_SELECT, 6);
+       }
+
+       /* We have to do bbt scanning ourselves */
+       if (this->scan_bbt (omap_mtd)) {
+               err = -ENXIO;
+               goto out_mtd;
+       }
+
+       err = add_dynamic_parts(omap_mtd);
+       if (err < 0) {
+               printk(KERN_ERR "omap-hw-nand: no partitions defined\n");
+               err = -ENODEV;
+               nand_release(omap_mtd);
+               goto out_mtd;
+       }
+       /* init completed */
+       return 0;
+out_mtd:
+       if (omap_nand_dma_ch >= 0)
+               omap_free_dma(omap_nand_dma_ch);
+       kfree(omap_mtd);
+free_clock:
+       clk_put(omap_nand_clk);
+       return err;
+}
+
+module_init(omap_nand_init);
+
+/*
+ * Clean up routine
+ */
+static void __exit omap_nand_cleanup (void)
+{
+       clk_disable(omap_nand_clk);
+       clk_put(omap_nand_clk);
+       nand_release(omap_mtd);
+       kfree(omap_mtd);
+}
+
+module_exit(omap_nand_cleanup);
+
diff --git a/drivers/mtd/nand/omap-nand-flash.c b/drivers/mtd/nand/omap-nand-flash.c
new file mode 100644 (file)
index 0000000..a231e18
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * drivers/mtd/nand/omap-nand-flash.c
+ *
+ * Copyright (c) 2004 Texas Instruments, Jian Zhang <jzhang@ti.com>
+ * Copyright (c) 2004 David Brownell
+ *
+ * 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/ioport.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/flash.h>
+#include <asm/arch/tc.h>
+
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+
+#define        DRIVER_NAME     "omapnand"
+
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *part_probes[] = { "cmdlinepart", NULL };
+#endif
+
+struct omap_nand_info {
+       struct nand_platform_data *pdata;
+       struct mtd_partition    *parts;
+       struct mtd_info         mtd;
+       struct nand_chip        nand;
+};
+
+/*
+ *     hardware specific access to control-lines
+ *     NOTE:  boards may use different bits for these!!
+ *
+ *     ctrl:
+ *     NAND_NCE: bit 0 - don't care
+ *     NAND_CLE: bit 1 -> bit 1  (0x0002)
+ *     NAND_ALE: bit 2 -> bit 2  (0x0004)
+ */
+
+static void omap_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+       struct nand_chip *chip = mtd->priv;
+       unsigned long mask;
+
+       if (cmd == NAND_CMD_NONE)
+               return;
+
+       mask = (ctrl & NAND_CLE) ? 0x02 : 0;
+       if (ctrl & NAND_ALE)
+               mask |= 0x04;
+       writeb(cmd, (unsigned long)chip->IO_ADDR_W | mask);
+}
+
+static int omap_nand_dev_ready(struct mtd_info *mtd)
+{
+       struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd);
+
+       return info->pdata->dev_ready(info->pdata);
+}
+
+static int __devinit omap_nand_probe(struct platform_device *pdev)
+{
+       struct omap_nand_info           *info;
+       struct nand_platform_data       *pdata = pdev->dev.platform_data;
+       struct resource                 *res = pdev->resource;
+       unsigned long                   size = res->end - res->start + 1;
+       int                             err;
+
+       info = kzalloc(sizeof(struct omap_nand_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       if (!request_mem_region(res->start, size, pdev->dev.driver->name)) {
+               err = -EBUSY;
+               goto out_free_info;
+       }
+
+       info->nand.IO_ADDR_R = ioremap(res->start, size);
+       if (!info->nand.IO_ADDR_R) {
+               err = -ENOMEM;
+               goto out_release_mem_region;
+       }
+       info->nand.IO_ADDR_W = info->nand.IO_ADDR_R;
+       info->nand.cmd_ctrl = omap_nand_hwcontrol;
+       info->nand.ecc.mode = NAND_ECC_SOFT;
+       info->nand.options = pdata->options;
+       if (pdata->dev_ready)
+               info->nand.dev_ready = omap_nand_dev_ready;
+       else
+               info->nand.chip_delay = 20;
+
+       info->mtd.name = pdev->dev.bus_id;
+       info->mtd.priv = &info->nand;
+
+       info->pdata = pdata;
+
+       /* DIP switches on H2 and some other boards change between 8 and 16 bit
+        * bus widths for flash.  Try the other width if the first try fails.
+        */
+       if (nand_scan(&info->mtd, 1)) {
+               info->nand.options ^= NAND_BUSWIDTH_16;
+               if (nand_scan(&info->mtd, 1)) {
+                       err = -ENXIO;
+                       goto out_iounmap;
+               }
+       }
+       info->mtd.owner = THIS_MODULE;
+
+#ifdef CONFIG_MTD_PARTITIONS
+       err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0);
+       if (err > 0)
+               add_mtd_partitions(&info->mtd, info->parts, err);
+       else if (err < 0 && pdata->parts)
+               add_mtd_partitions(&info->mtd, pdata->parts, pdata->nr_parts);
+       else
+#endif
+               add_mtd_device(&info->mtd);
+
+       platform_set_drvdata(pdev, info);
+
+       return 0;
+
+out_iounmap:
+       iounmap(info->nand.IO_ADDR_R);
+out_release_mem_region:
+       release_mem_region(res->start, size);
+out_free_info:
+       kfree(info);
+
+       return err;
+}
+
+static int omap_nand_remove(struct platform_device *pdev)
+{
+       struct omap_nand_info *info = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+       /* Release NAND device, its internal structures and partitions */
+       nand_release(&info->mtd);
+       iounmap(info->nand.IO_ADDR_R);
+       kfree(info);
+       return 0;
+}
+
+static struct platform_driver omap_nand_driver = {
+       .probe          = omap_nand_probe,
+       .remove         = omap_nand_remove,
+       .driver         = {
+               .name   = DRIVER_NAME,
+       },
+};
+MODULE_ALIAS(DRIVER_NAME);
+
+static int __init omap_nand_init(void)
+{
+       return platform_driver_register(&omap_nand_driver);
+}
+
+static void __exit omap_nand_exit(void)
+{
+       platform_driver_unregister(&omap_nand_driver);
+}
+
+module_init(omap_nand_init);
+module_exit(omap_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jian Zhang <jzhang@ti.com> (and others)");
+MODULE_DESCRIPTION("Glue layer for NAND flash on TI OMAP boards");
+
index 7c8ccc09b60126a448a70c1ef4e3f77975a1f434..51a8b2c03ec2be278f280db4b4f5be2192eced05 100644 (file)
@@ -433,5 +433,15 @@ config MCS_FIR
          To compile it as a module, choose M here: the module will be called
          mcs7780.
 
+config OMAP_IR
+       tristate "OMAP IrDA(SIR/MIR/FIR)"
+       depends on IRDA && ARCH_OMAP
+       select GPIOEXPANDER_OMAP if (MACH_OMAP_H3 || MACH_OMAP_H4)
+        help
+         Say Y here if you want to build support for the Texas Instruments
+         OMAP IrDA device driver, which supports SIR/MIR/FIR. This driver
+         relies on platform specific helper routines so available capabilities
+         may vary from one OMAP target to another.
+
 endmenu
 
index 5be09f1b9ee2f4b8dc056540342955405b72b215..89c6389c697355c24f460f329353778ae00e5028 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_VLSI_FIR)                += vlsi_ir.o
 obj-$(CONFIG_VIA_FIR)          += via-ircc.o
 obj-$(CONFIG_PXA_FICP)         += pxaficp_ir.o
 obj-$(CONFIG_MCS_FIR)          += mcs7780.o
+obj-$(CONFIG_OMAP_IR)          += omap-ir.o
 # Old dongle drivers for old SIR drivers
 obj-$(CONFIG_ESI_DONGLE_OLD)           += esi.o
 obj-$(CONFIG_TEKRAM_DONGLE_OLD)        += tekram.o
diff --git a/drivers/net/irda/omap-ir.c b/drivers/net/irda/omap-ir.c
new file mode 100644 (file)
index 0000000..85658dc
--- /dev/null
@@ -0,0 +1,905 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ *
+ *     Infra-red driver for the OMAP1610-H2 and OMAP1710-H3 and H4 Platforms
+ *       (SIR/MIR/FIR modes)
+ *       (based on omap-sir.c)
+ *
+ * Copyright 2003 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *        source@mvista.com
+ *
+ * Copyright 2004 Texas Instruments.
+ *
+ *  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  SOFTWARE  IS PROVIDED          ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,          INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED          TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN         CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ *
+ Modifications:
+ Feb 2004, Texas Instruments
+ - Ported to 2.6 kernel (Feb 2004).
+ *
+ Apr 2004, Texas Instruments
+ - Added support for H3 (Apr 2004).
+ Nov 2004, Texas Instruments
+ - Added support for Power Management.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/slab.h>
+#include <linux/rtnetlink.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irmod.h>
+#include <net/irda/wrapper.h>
+#include <net/irda/irda_device.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/serial.h>
+#include <asm/mach-types.h>
+#include <asm/dma.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/irda.h>
+
+#define UART3_EFR_EN                   (1 << 4)
+#define UART3_MCR_EN_TCR_TLR           (1 << 6)
+
+#define UART3_LCR_WL_8                 (3 << 0)
+#define UART3_LCR_SP2                  (1 << 2)
+#define UART3_LCR_DIVEN                        (1 << 7)
+
+#define UART3_FCR_FIFO_EN              (1 << 0)
+#define UART3_FCR_FIFO_RX              (1 << 1)
+#define UART3_FCR_FIFO_TX              (1 << 2)
+#define UART3_FCR_FIFO_DMA1            (1 << 3)
+#define UART3_FCR_FIFO_TX_TRIG16       (1 << 4)
+#define UART3_FCR_FIFO_RX_TRIG16       (1 << 6)
+#define UART3_FCR_CONFIG       (\
+               UART3_FCR_FIFO_EN | UART3_FCR_FIFO_RX   |\
+               UART3_FCR_FIFO_TX | UART3_FCR_FIFO_DMA1 |\
+               UART3_FCR_FIFO_TX_TRIG16                |\
+               UART3_FCR_FIFO_RX_TRIG16)
+
+#define UART3_SCR_TX_TRIG1             (1 << 6)
+#define UART3_SCR_RX_TRIG1             (1 << 7)
+
+#define UART3_MDR1_RESET               (0x07)
+#define UART3_MDR1_SIR                 (1 << 0)
+#define UART3_MDR1_MIR                 (4 << 0)
+#define UART3_MDR1_FIR                 (5 << 0)
+#define UART3_MDR1_SIP_AUTO            (1 << 6)
+
+#define UART3_MDR2_TRIG1               (0 << 1)
+#define UART3_MDR2_IRTX_UNDERRUN       (1 << 0)
+
+#define UART3_ACERG_TX_UNDERRUN_DIS    (1 << 4)
+#define UART3_ACERG_SD_MODE_LOW                (1 << 6)
+#define UART3_ACERG_DIS_IR_RX          (1 << 5)
+
+#define UART3_IER_EOF                  (1 << 5)
+#define UART3_IER_CTS                  (1 << 7)
+
+#define UART3_IIR_TX_STATUS            (1 << 5)
+#define UART3_IIR_EOF                  (0x80)
+
+#define IS_FIR(omap_ir)                ((omap_ir)->speed >= 4000000)
+
+struct omap_irda {
+       unsigned char open;
+       int speed;              /* Current IrDA speed */
+       int newspeed;
+
+       struct net_device_stats stats;
+       struct irlap_cb *irlap;
+       struct qos_info qos;
+
+       int rx_dma_channel;
+       int tx_dma_channel;
+
+       dma_addr_t rx_buf_dma_phys;     /* Physical address of RX DMA buffer */
+       dma_addr_t tx_buf_dma_phys;     /* Physical address of TX DMA buffer */
+
+       void *rx_buf_dma_virt;          /* Virtual address of RX DMA buffer */
+       void *tx_buf_dma_virt;          /* Virtual address of TX DMA buffer */
+
+       struct device *dev;
+       struct omap_irda_config *pdata;
+};
+
+static void inline uart_reg_out(int idx, u8 val)
+{
+       omap_writeb(val, idx);
+}
+
+static u8 inline uart_reg_in(int idx)
+{
+       u8 b = omap_readb(idx);
+       return b;
+}
+
+/* forward declarations */
+extern void omap_stop_dma(int lch);
+static int omap_irda_set_speed(struct net_device *dev, int speed);
+
+static void omap_irda_start_rx_dma(struct omap_irda *omap_ir)
+{
+       /* Configure DMA */
+       omap_set_dma_src_params(omap_ir->rx_dma_channel, 0x3, 0x0,
+                               omap_ir->pdata->src_start,
+                               0, 0);
+
+       omap_enable_dma_irq(omap_ir->rx_dma_channel, 0x01);
+
+       omap_set_dma_dest_params(omap_ir->rx_dma_channel, 0x0, 0x1,
+                               omap_ir->rx_buf_dma_phys,
+                               0, 0);
+
+       omap_set_dma_transfer_params(omap_ir->rx_dma_channel, 0x0,
+                               IRDA_SKB_MAX_MTU, 0x1,
+                               0x0, omap_ir->pdata->rx_trigger, 0);
+
+       omap_start_dma(omap_ir->rx_dma_channel);
+}
+
+static void omap_start_tx_dma(struct omap_irda *omap_ir, int size)
+{
+       /* Configure DMA */
+       omap_set_dma_dest_params(omap_ir->tx_dma_channel, 0x03, 0x0,
+                               omap_ir->pdata->dest_start, 0, 0);
+
+       omap_enable_dma_irq(omap_ir->tx_dma_channel, 0x01);
+
+       omap_set_dma_src_params(omap_ir->tx_dma_channel, 0x0, 0x1,
+                               omap_ir->tx_buf_dma_phys,
+                               0, 0);
+
+       omap_set_dma_transfer_params(omap_ir->tx_dma_channel, 0x0, size, 0x1,
+                               0x0, omap_ir->pdata->tx_trigger, 0);
+
+       /* Start DMA */
+       omap_start_dma(omap_ir->tx_dma_channel);
+}
+
+/* DMA RX callback - normally, we should not go here,
+ * it calls only if something is going wrong
+ */
+static void omap_irda_rx_dma_callback(int lch, u16 ch_status, void *data)
+{
+       struct net_device *dev = data;
+       struct omap_irda *omap_ir = netdev_priv(dev);
+
+       printk(KERN_ERR "RX Transfer error or very big frame\n");
+
+       /* Clear interrupts */
+       uart_reg_in(UART3_IIR);
+
+       omap_ir->stats.rx_frame_errors++;
+
+       uart_reg_in(UART3_RESUME);
+
+       /* Re-init RX DMA */
+       omap_irda_start_rx_dma(omap_ir);
+}
+
+/* DMA TX callback - calling when frame transfer has been finished */
+static void omap_irda_tx_dma_callback(int lch, u16 ch_status, void *data)
+{
+       struct net_device *dev = data;
+       struct omap_irda *omap_ir = netdev_priv(dev);
+
+       /*Stop DMA controller */
+       omap_stop_dma(omap_ir->tx_dma_channel);
+}
+
+/*
+ * Set the IrDA communications speed.
+ * Interrupt have to be disabled here.
+ */
+static int omap_irda_startup(struct net_device *dev)
+{
+       struct omap_irda *omap_ir = netdev_priv(dev);
+
+       /* FIXME: use clk_* apis for UART3 clock*/
+       /* Enable UART3 clock and set UART3 to IrDA mode */
+       if (machine_is_omap_h2() || machine_is_omap_h3())
+               omap_writel(omap_readl(MOD_CONF_CTRL_0) | (1 << 31) | (1 << 15),
+                               MOD_CONF_CTRL_0);
+
+       /* Only for H2?
+        */
+       if (omap_ir->pdata->transceiver_mode && machine_is_omap_h2()) {
+               /* Is it select_irda on H2 ? */
+               omap_writel(omap_readl(FUNC_MUX_CTRL_A) | 7,
+                                       FUNC_MUX_CTRL_A);
+               omap_ir->pdata->transceiver_mode(omap_ir->dev, IR_SIRMODE);
+       }
+
+       uart_reg_out(UART3_MDR1, UART3_MDR1_RESET);     /* Reset mode */
+
+       /* Clear DLH and DLL */
+       uart_reg_out(UART3_LCR, UART3_LCR_DIVEN);
+
+       uart_reg_out(UART3_DLL, 0);
+       uart_reg_out(UART3_DLH, 0);
+       uart_reg_out(UART3_LCR, 0xbf);  /* FIXME: Add #define */
+
+       uart_reg_out(UART3_EFR, UART3_EFR_EN);
+       uart_reg_out(UART3_LCR, UART3_LCR_DIVEN);
+
+       /* Enable access to UART3_TLR and UART3_TCR registers */
+       uart_reg_out(UART3_MCR, UART3_MCR_EN_TCR_TLR);
+
+       uart_reg_out(UART3_SCR, 0);
+       /* Set Rx trigger to 1 and Tx trigger to 1 */
+       uart_reg_out(UART3_TLR, 0);
+
+       /* Set LCR to 8 bits and 1 stop bit */
+       uart_reg_out(UART3_LCR, 0x03);
+
+       /* Clear RX and TX FIFO and enable FIFO */
+       /* Use DMA Req for transfers */
+       uart_reg_out(UART3_FCR, UART3_FCR_CONFIG);
+
+       uart_reg_out(UART3_MCR, 0);
+
+       uart_reg_out(UART3_SCR, UART3_SCR_TX_TRIG1 |
+                       UART3_SCR_RX_TRIG1);
+
+       /* Enable UART3 SIR Mode,(Frame-length method to end frames) */
+       uart_reg_out(UART3_MDR1, UART3_MDR1_SIR);
+
+       /* Set Status FIFO trig to 1 */
+       uart_reg_out(UART3_MDR2, 0);
+
+       /* Enables RXIR input */
+       /* and disable TX underrun */
+       /* SEND_SIP pulse */
+       uart_reg_out(UART3_ACREG, UART3_ACERG_SD_MODE_LOW |
+                       UART3_ACERG_TX_UNDERRUN_DIS);
+
+       /* Enable EOF Interrupt only */
+       uart_reg_out(UART3_IER, UART3_IER_CTS | UART3_IER_EOF);
+
+       /* Set Maximum Received Frame size to 2048 bytes */
+       uart_reg_out(UART3_RXFLL, 0x00);
+       uart_reg_out(UART3_RXFLH, 0x08);
+
+       uart_reg_in(UART3_RESUME);
+
+       return 0;
+}
+
+static int omap_irda_shutdown(struct omap_irda *omap_ir)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       /* Disable all UART3 Interrupts */
+       uart_reg_out(UART3_IER, 0);
+
+       /* Disable UART3 and disable baud rate generator */
+       uart_reg_out(UART3_MDR1, UART3_MDR1_RESET);
+
+       /* set SD_MODE pin to high and Disable RX IR */
+       uart_reg_out(UART3_ACREG, (UART3_ACERG_DIS_IR_RX |
+                       ~(UART3_ACERG_SD_MODE_LOW)));
+
+       /* Clear DLH and DLL */
+       uart_reg_out(UART3_LCR, UART3_LCR_DIVEN);
+       uart_reg_out(UART3_DLL, 0);
+       uart_reg_out(UART3_DLH, 0);
+
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+static irqreturn_t
+omap_irda_irq(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct omap_irda *omap_ir = netdev_priv(dev);
+       struct sk_buff *skb;
+
+       u8 status;
+       int w = 0;
+
+       /* Clear EOF interrupt */
+       status = uart_reg_in(UART3_IIR);
+
+       if (status & UART3_IIR_TX_STATUS) {
+               u8 mdr2 = uart_reg_in(UART3_MDR2);
+               if (mdr2 & UART3_MDR2_IRTX_UNDERRUN)
+                       printk(KERN_ERR "IrDA Buffer underrun error\n");
+
+               omap_ir->stats.tx_packets++;
+
+               if (omap_ir->newspeed) {
+                       omap_irda_set_speed(dev, omap_ir->newspeed);
+                       omap_ir->newspeed = 0;
+               }
+
+               netif_wake_queue(dev);
+               if (!(status & UART3_IIR_EOF))
+                       return IRQ_HANDLED;
+       }
+
+       /* Stop DMA and if there are no errors, send frame to upper layer */
+       omap_stop_dma(omap_ir->rx_dma_channel);
+
+       status = uart_reg_in(UART3_SFLSR);      /* Take a frame status */
+
+       if (status != 0) {      /* Bad frame? */
+               omap_ir->stats.rx_frame_errors++;
+               uart_reg_in(UART3_RESUME);
+       } else {
+               /* We got a frame! */
+               skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
+
+               if (!skb) {
+                       printk(KERN_ERR "omap_sir: out of memory for RX SKB\n");
+                       return IRQ_HANDLED;
+               }
+               /*
+                * Align any IP headers that may be contained
+                * within the frame.
+                */
+
+               skb_reserve(skb, 1);
+
+               w = OMAP_DMA_CDAC_REG(omap_ir->rx_dma_channel);
+
+               if (cpu_is_omap16xx())
+                       w -= OMAP1_DMA_CDSA_L_REG(omap_ir->rx_dma_channel);
+               if (cpu_is_omap24xx())
+                       w -= OMAP2_DMA_CDSA_REG(omap_ir->rx_dma_channel);
+
+               if (!IS_FIR(omap_ir))
+                       /* Copy DMA buffer to skb */
+                       memcpy(skb_put(skb, w - 2), omap_ir->rx_buf_dma_virt,
+                                       w - 2);
+               else
+                       /* Copy DMA buffer to skb */
+                       memcpy(skb_put(skb, w - 4), omap_ir->rx_buf_dma_virt,
+                                       w - 4);
+
+               skb->dev = dev;
+               skb->mac.raw = skb->data;
+               skb->protocol = htons(ETH_P_IRDA);
+               omap_ir->stats.rx_packets++;
+               omap_ir->stats.rx_bytes += skb->len;
+               netif_receive_skb(skb); /* Send data to upper level */
+       }
+
+       /* Re-init RX DMA */
+       omap_irda_start_rx_dma(omap_ir);
+
+       dev->last_rx = jiffies;
+
+       return IRQ_HANDLED;
+}
+
+static int omap_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct omap_irda *omap_ir = netdev_priv(dev);
+       int speed = irda_get_next_speed(skb);
+       int mtt = irda_get_mtt(skb);
+       int xbofs = irda_get_next_xbofs(skb);
+
+
+       /*
+        * Does this packet contain a request to change the interface
+        * speed?  If so, remember it until we complete the transmission
+        * of this frame.
+        */
+       if (speed != omap_ir->speed && speed != -1)
+               omap_ir->newspeed = speed;
+
+       if (xbofs) /* Set number of addtional BOFS */
+               uart_reg_out(UART3_EBLR, xbofs + 1);
+
+       /*
+        * If this is an empty frame, we can bypass a lot.
+        */
+       if (skb->len == 0) {
+               if (omap_ir->newspeed) {
+                       omap_ir->newspeed = 0;
+                       omap_irda_set_speed(dev, speed);
+               }
+               dev_kfree_skb(skb);
+               return 0;
+       }
+
+       netif_stop_queue(dev);
+
+       /* Copy skb data to DMA buffer */
+       memcpy(omap_ir->tx_buf_dma_virt, skb->data, skb->len);
+
+       /* Copy skb data to DMA buffer */
+       omap_ir->stats.tx_bytes += skb->len;
+
+       /* Set frame length */
+       uart_reg_out(UART3_TXFLL, (skb->len & 0xff));
+       uart_reg_out(UART3_TXFLH, (skb->len >> 8));
+
+       if (mtt > 1000)
+               mdelay(mtt / 1000);
+       else
+               udelay(mtt);
+
+       /* Start TX DMA transfer */
+       omap_start_tx_dma(omap_ir, skb->len);
+
+       /* We can free skb now because it's already in DMA buffer */
+       dev_kfree_skb(skb);
+
+       dev->trans_start = jiffies;
+
+       return 0;
+}
+
+static int
+omap_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
+{
+       struct if_irda_req *rq = (struct if_irda_req *)ifreq;
+       struct omap_irda *omap_ir = netdev_priv(dev);
+       int ret = -EOPNOTSUPP;
+
+
+       switch (cmd) {
+       case SIOCSBANDWIDTH:
+               if (capable(CAP_NET_ADMIN)) {
+                       /*
+                        * We are unable to set the speed if the
+                        * device is not running.
+                        */
+                       if (omap_ir->open)
+                               ret = omap_irda_set_speed(dev,
+                                               rq->ifr_baudrate);
+                       else {
+                               printk(KERN_ERR "omap_ir: SIOCSBANDWIDTH:"
+                                               " !netif_running\n");
+                               ret = 0;
+                       }
+               }
+               break;
+
+       case SIOCSMEDIABUSY:
+               ret = -EPERM;
+               if (capable(CAP_NET_ADMIN)) {
+                       irda_device_set_media_busy(dev, TRUE);
+                       ret = 0;
+               }
+               break;
+
+       case SIOCGRECEIVING:
+               rq->ifr_receiving = 0;
+               break;
+
+       default:
+               break;
+       }
+
+       return ret;
+}
+
+static struct net_device_stats *omap_irda_stats(struct net_device *dev)
+{
+       struct omap_irda *omap_ir = netdev_priv(dev);
+       return &omap_ir->stats;
+}
+
+static int omap_irda_start(struct net_device *dev)
+{
+       struct omap_irda *omap_ir = netdev_priv(dev);
+       int err;
+
+       omap_ir->speed = 9600;
+
+       err = request_irq(dev->irq, omap_irda_irq, 0, dev->name, dev);
+       if (err)
+               goto err_irq;
+
+       /*
+        * The interrupt must remain disabled for now.
+        */
+       disable_irq(dev->irq);
+
+       /*  Request DMA channels for IrDA hardware */
+       if (omap_request_dma(omap_ir->pdata->rx_channel, "IrDA Rx DMA",
+                       (void *)omap_irda_rx_dma_callback,
+                       dev, &(omap_ir->rx_dma_channel))) {
+               printk(KERN_ERR "Failed to request IrDA Rx DMA\n");
+               goto err_irq;
+       }
+
+       if (omap_request_dma(omap_ir->pdata->tx_channel, "IrDA Tx DMA",
+                       (void *)omap_irda_tx_dma_callback,
+                       dev, &(omap_ir->tx_dma_channel))) {
+               printk(KERN_ERR "Failed to request IrDA Tx DMA\n");
+               goto err_irq;
+       }
+
+       /* Allocate TX and RX buffers for DMA channels */
+       omap_ir->rx_buf_dma_virt =
+               dma_alloc_coherent(NULL, IRDA_SKB_MAX_MTU,
+                               &(omap_ir->rx_buf_dma_phys),
+                               GFP_KERNEL);
+
+       if (!omap_ir->rx_buf_dma_virt) {
+               printk(KERN_ERR "Unable to allocate memory for rx_buf_dma\n");
+               goto err_irq;
+       }
+
+       omap_ir->tx_buf_dma_virt =
+               dma_alloc_coherent(NULL, IRDA_SIR_MAX_FRAME,
+                               &(omap_ir->tx_buf_dma_phys),
+                               GFP_KERNEL);
+
+       if (!omap_ir->tx_buf_dma_virt) {
+               printk(KERN_ERR "Unable to allocate memory for tx_buf_dma\n");
+               goto err_mem1;
+       }
+
+       /*
+        * Setup the serial port for the specified config.
+        */
+       if (omap_ir->pdata->select_irda)
+               omap_ir->pdata->select_irda(omap_ir->dev, IR_SEL);
+
+       err = omap_irda_startup(dev);
+
+       if (err)
+               goto err_startup;
+
+       omap_irda_set_speed(dev, omap_ir->speed = 9600);
+
+       /*
+        * Open a new IrLAP layer instance.
+        */
+       omap_ir->irlap = irlap_open(dev, &omap_ir->qos, "omap_sir");
+
+       err = -ENOMEM;
+       if (!omap_ir->irlap)
+               goto err_irlap;
+
+       /* Now enable the interrupt and start the queue */
+       omap_ir->open = 1;
+
+       /* Start RX DMA */
+       omap_irda_start_rx_dma(omap_ir);
+
+       enable_irq(dev->irq);
+       netif_start_queue(dev);
+
+       return 0;
+
+err_irlap:
+       omap_ir->open = 0;
+       omap_irda_shutdown(omap_ir);
+err_startup:
+       dma_free_coherent(NULL, IRDA_SIR_MAX_FRAME,
+                       omap_ir->tx_buf_dma_virt, omap_ir->tx_buf_dma_phys);
+err_mem1:
+       dma_free_coherent(NULL, IRDA_SKB_MAX_MTU,
+                       omap_ir->rx_buf_dma_virt, omap_ir->rx_buf_dma_phys);
+err_irq:
+       free_irq(dev->irq, dev);
+       return err;
+}
+
+static int omap_irda_stop(struct net_device *dev)
+{
+       struct omap_irda *omap_ir = netdev_priv(dev);
+
+       disable_irq(dev->irq);
+
+       netif_stop_queue(dev);
+
+       omap_free_dma(omap_ir->rx_dma_channel);
+       omap_free_dma(omap_ir->tx_dma_channel);
+
+       if (omap_ir->rx_buf_dma_virt)
+               dma_free_coherent(NULL, IRDA_SKB_MAX_MTU,
+                               omap_ir->rx_buf_dma_virt,
+                               omap_ir->rx_buf_dma_phys);
+       if (omap_ir->tx_buf_dma_virt)
+               dma_free_coherent(NULL, IRDA_SIR_MAX_FRAME,
+                               omap_ir->tx_buf_dma_virt,
+                               omap_ir->tx_buf_dma_phys);
+
+       omap_irda_shutdown(omap_ir);
+
+       /* Stop IrLAP */
+       if (omap_ir->irlap) {
+               irlap_close(omap_ir->irlap);
+               omap_ir->irlap = NULL;
+       }
+
+       omap_ir->open = 0;
+
+       /*
+        * Free resources
+        */
+       free_irq(dev->irq, dev);
+
+       return 0;
+}
+
+static int omap_irda_set_speed(struct net_device *dev, int speed)
+{
+       struct omap_irda *omap_ir = netdev_priv(dev);
+       int divisor;
+       unsigned long flags;
+
+       /* Set IrDA speed */
+       if (speed <= 115200) {
+
+               local_irq_save(flags);
+
+               /* SIR mode */
+               if (omap_ir->pdata->transceiver_mode)
+                       omap_ir->pdata->transceiver_mode(omap_ir->dev,
+                                                       IR_SIRMODE);
+
+               /* Set SIR mode */
+               uart_reg_out(UART3_MDR1, 1);
+               uart_reg_out(UART3_EBLR, 1);
+
+               divisor = 48000000 / (16 * speed);      /* Base clock 48 MHz */
+
+               uart_reg_out(UART3_LCR, UART3_LCR_DIVEN);
+               uart_reg_out(UART3_DLL, (divisor & 0xff));
+               uart_reg_out(UART3_DLH, (divisor >> 8));
+               uart_reg_out(UART3_LCR, 0x03);
+
+               uart_reg_out(UART3_MCR, 0);
+
+               local_irq_restore(flags);
+       } else if (speed <= 1152000) {
+
+               local_irq_save(flags);
+
+               /* Set MIR mode, auto SIP */
+               uart_reg_out(UART3_MDR1, UART3_MDR1_MIR |
+                               UART3_MDR1_SIP_AUTO);
+
+               uart_reg_out(UART3_EBLR, 2);
+
+               divisor = 48000000 / (41 * speed);      /* Base clock 48 MHz */
+
+               uart_reg_out(UART3_LCR, UART3_LCR_DIVEN);
+               uart_reg_out(UART3_DLL, (divisor & 0xff));
+               uart_reg_out(UART3_DLH, (divisor >> 8));
+               uart_reg_out(UART3_LCR, 0x03);
+
+               if (omap_ir->pdata->transceiver_mode)
+                       omap_ir->pdata->transceiver_mode(omap_ir->dev,
+                                                       IR_MIRMODE);
+
+               local_irq_restore(flags);
+       } else {
+               local_irq_save(flags);
+
+               /* FIR mode */
+               uart_reg_out(UART3_MDR1, UART3_MDR1_FIR |
+                               UART3_MDR1_SIP_AUTO);
+
+               if (omap_ir->pdata->transceiver_mode)
+                       omap_ir->pdata->transceiver_mode(omap_ir->dev,
+                                                       IR_FIRMODE);
+
+               local_irq_restore(flags);
+       }
+
+       omap_ir->speed = speed;
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+/*
+ * Suspend the IrDA interface.
+ */
+static int omap_irda_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+       struct omap_irda *omap_ir = netdev_priv(dev);
+
+       if (!dev)
+               return 0;
+
+       if (omap_ir->open) {
+               /*
+                * Stop the transmit queue
+                */
+               netif_device_detach(dev);
+               disable_irq(dev->irq);
+               omap_irda_shutdown(omap_ir);
+       }
+       return 0;
+}
+
+/*
+ * Resume the IrDA interface.
+ */
+static int omap_irda_resume(struct platform_device *pdev)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+       struct omap_irda *omap_ir= netdev_priv(dev);
+
+       if (!dev)
+               return 0;
+
+       if (omap_ir->open) {
+               /*
+                * If we missed a speed change, initialise at the new speed
+                * directly.  It is debatable whether this is actually
+                * required, but in the interests of continuing from where
+                * we left off it is desireable.  The converse argument is
+                * that we should re-negotiate at 9600 baud again.
+                */
+               if (omap_ir->newspeed) {
+                       omap_ir->speed = omap_ir->newspeed;
+                       omap_ir->newspeed = 0;
+               }
+
+               omap_irda_startup(dev);
+               omap_irda_set_speed(dev, omap_ir->speed);
+               enable_irq(dev->irq);
+
+               /*
+                * This automatically wakes up the queue
+                */
+               netif_device_attach(dev);
+       }
+
+       return 0;
+}
+#else
+#define omap_irda_suspend      NULL
+#define omap_irda_resume       NULL
+#endif
+
+static int omap_irda_probe(struct platform_device *pdev)
+{
+       struct net_device *dev;
+       struct omap_irda *omap_ir;
+       struct omap_irda_config *pdata = pdev->dev.platform_data;
+       unsigned int baudrate_mask;
+       int err = 0;
+       int irq = NO_IRQ;
+
+       if (!pdata) {
+               printk(KERN_ERR "IrDA Platform data not supplied\n");
+               return -ENOENT;
+       }
+
+       if (!pdata->rx_channel || !pdata->tx_channel) {
+               printk(KERN_ERR "IrDA invalid rx/tx channel value\n");
+               return -ENOENT;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0) {
+               printk(KERN_WARNING "no irq for IrDA\n");
+               return -ENOENT;
+       }
+
+       dev = alloc_irdadev(sizeof(struct omap_irda));
+       if (!dev)
+               goto err_mem_1;
+
+
+       omap_ir = netdev_priv(dev);
+       omap_ir->dev = &pdev->dev;
+       omap_ir->pdata = pdata;
+
+       dev->hard_start_xmit    = omap_irda_hard_xmit;
+       dev->open               = omap_irda_start;
+       dev->stop               = omap_irda_stop;
+       dev->do_ioctl           = omap_irda_ioctl;
+       dev->get_stats          = omap_irda_stats;
+       dev->irq                = irq;
+
+       irda_init_max_qos_capabilies(&omap_ir->qos);
+
+       baudrate_mask = 0;
+       if (omap_ir->pdata->transceiver_cap & IR_SIRMODE)
+               baudrate_mask |= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
+       if (omap_ir->pdata->transceiver_cap & IR_MIRMODE)
+               baudrate_mask |= IR_57600 | IR_1152000;
+       if (omap_ir->pdata->transceiver_cap & IR_FIRMODE)
+               baudrate_mask |= IR_4000000 << 8;
+
+       omap_ir->qos.baud_rate.bits &= baudrate_mask;
+       omap_ir->qos.min_turn_time.bits = 7;
+
+       irda_qos_bits_to_value(&omap_ir->qos);
+
+       /* Any better way to avoid this? No. */
+       if (machine_is_omap_h3() || machine_is_omap_h4())
+               INIT_DELAYED_WORK(&omap_ir->pdata->gpio_expa, NULL);
+
+       err = register_netdev(dev);
+       if (!err)
+               platform_set_drvdata(pdev, dev);
+       else
+               free_netdev(dev);
+
+err_mem_1:
+       return err;
+}
+
+static int omap_irda_remove(struct platform_device *pdev)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+
+       if (pdev) {
+               unregister_netdev(dev);
+               free_netdev(dev);
+       }
+       return 0;
+}
+
+static struct platform_driver omapir_driver = {
+       .probe          = omap_irda_probe,
+       .remove         = omap_irda_remove,
+       .suspend        = omap_irda_suspend,
+       .resume         = omap_irda_resume,
+       .driver         = {
+               .name   = "omapirda",
+       },
+};
+
+static char __initdata banner[] = KERN_INFO "OMAP IrDA driver initializing\n";
+
+static int __init omap_irda_init(void)
+{
+       printk(banner);
+       return platform_driver_register(&omapir_driver);
+}
+
+static void __exit omap_irda_exit(void)
+{
+       platform_driver_unregister(&omapir_driver);
+}
+
+module_init(omap_irda_init);
+module_exit(omap_irda_exit);
+
+MODULE_AUTHOR("MontaVista");
+MODULE_DESCRIPTION("OMAP IrDA Driver");
+MODULE_LICENSE("GPL");
+
index d59880d44fba26e3555c46d000c13a65e12d3ec4..9de8d67f4f8d8ac71bcbc4c198d4b496d8c4dc27 100644 (file)
@@ -417,13 +417,13 @@ static int __devinit omap_rtc_probe(struct platform_device *pdev)
                rtc_write(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG);
 
        /* handle periodic and alarm irqs */
-       if (request_irq(omap_rtc_timer, rtc_irq, SA_INTERRUPT,
+       if (request_irq(omap_rtc_timer, rtc_irq, IRQF_DISABLED,
                        rtc->class_dev.class_id, &rtc->class_dev)) {
                pr_debug("%s: RTC timer interrupt IRQ%d already claimed\n",
                        pdev->name, omap_rtc_timer);
                goto fail0;
        }
-       if (request_irq(omap_rtc_alarm, rtc_irq, SA_INTERRUPT,
+       if (request_irq(omap_rtc_alarm, rtc_irq, IRQF_DISABLED,
                        rtc->class_dev.class_id, &rtc->class_dev)) {
                pr_debug("%s: RTC alarm interrupt IRQ%d already claimed\n",
                        pdev->name, omap_rtc_alarm);
index d895a1adb428fbb10b32977e6a200a649766ec55..948a9dc79adbdbe0667a7919255134edb40c2982 100644 (file)
@@ -103,6 +103,20 @@ config SPI_S3C24XX_GPIO
          GPIO lines to provide the SPI bus. This can be used where
          the inbuilt hardware cannot provide the transfer mode, or
          where the board is using non hardware connected pins.
+
+config SPI_OMAP_UWIRE
+       tristate "OMAP MicroWire"
+       depends on SPI_MASTER && ARCH_OMAP
+       select SPI_BITBANG
+       help
+         This hooks up to the MicroWire controller on OMAP chips.
+
+config SPI_OMAP24XX
+       bool "McSPI driver for OMAP24xx"
+       depends on SPI_MASTER && ARCH_OMAP24XX
+       help
+         SPI master controller for OMAP24xx McSPI modules.
+
 #
 # Add new SPI master controllers in alphabetical order above this line
 #
@@ -121,7 +135,12 @@ config SPI_S3C24XX
 comment "SPI Protocol Masters"
        depends on SPI_MASTER
 
-
+config TSC2102
+       depends on SPI_MASTER
+       tristate "TSC2102 codec support"
+       ---help---
+         Say Y here if you want support for the TSC2102 chip.  It
+         will be needed for the touchscreen driver on some boards.
 #
 # Add new SPI protocol masters in alphabetical order above this line
 #
index 8f4cb67997b32afcc5207b49fb7ae2dfcb2654eb..83b3e70365f39ee0e9cfa306885089a48382f795 100644 (file)
@@ -17,9 +17,12 @@ obj-$(CONFIG_SPI_PXA2XX)             += pxa2xx_spi.o
 obj-$(CONFIG_SPI_MPC83xx)              += spi_mpc83xx.o
 obj-$(CONFIG_SPI_S3C24XX_GPIO)         += spi_s3c24xx_gpio.o
 obj-$(CONFIG_SPI_S3C24XX)              += spi_s3c24xx.o
+obj-$(CONFIG_SPI_OMAP24XX)             += omap2_mcspi.o
+obj-$(CONFIG_SPI_OMAP_UWIRE)           += omap_uwire.o
 #      ... add above this line ...
 
 # SPI protocol drivers (device/link on bus)
+obj-$(CONFIG_TSC2102)                  += tsc2102.o
 #      ... add above this line ...
 
 # SPI slave controller drivers (upstream link)
diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c
new file mode 100644 (file)
index 0000000..b8d0ec0
--- /dev/null
@@ -0,0 +1,925 @@
+/*
+ * OMAP2 McSPI controller driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation
+ * Author: Samuel Ortiz <samuel.ortiz@nokia.com> and
+ *         Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <linux/spi/spi.h>
+
+#include <asm/io.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/mcspi.h>
+
+#define OMAP2_MCSPI_MAX_FREQ           48000000
+
+#define OMAP2_MCSPI_REVISION           0x00
+#define OMAP2_MCSPI_SYSCONFIG          0x10
+#define OMAP2_MCSPI_SYSSTATUS          0x14
+#define OMAP2_MCSPI_IRQSTATUS          0x18
+#define OMAP2_MCSPI_IRQENABLE          0x1c
+#define OMAP2_MCSPI_WAKEUPENABLE       0x20
+#define OMAP2_MCSPI_SYST               0x24
+#define OMAP2_MCSPI_MODULCTRL          0x28
+#define OMAP2_MCSPI_CHCONF0            0x2c
+#define OMAP2_MCSPI_CHSTAT0            0x30
+#define OMAP2_MCSPI_CHCTRL0            0x34
+#define OMAP2_MCSPI_TX0                        0x38
+#define OMAP2_MCSPI_RX0                        0x3c
+
+#define OMAP2_MCSPI_SYSCONFIG_SOFTRESET        (1 << 1)
+
+#define OMAP2_MCSPI_SYSSTATUS_RESETDONE        (1 << 0)
+
+#define OMAP2_MCSPI_MODULCTRL_SINGLE   (1 << 0)
+#define OMAP2_MCSPI_MODULCTRL_MS       (1 << 2)
+#define OMAP2_MCSPI_MODULCTRL_STEST    (1 << 3)
+
+#define OMAP2_MCSPI_CHCONF_PHA         (1 << 0)
+#define OMAP2_MCSPI_CHCONF_POL         (1 << 1)
+#define OMAP2_MCSPI_CHCONF_CLKD_MASK   (0x0f << 2)
+#define OMAP2_MCSPI_CHCONF_EPOL                (1 << 6)
+#define OMAP2_MCSPI_CHCONF_WL_MASK     (0x1f << 7)
+#define OMAP2_MCSPI_CHCONF_TRM_RX_ONLY (0x01 << 12)
+#define OMAP2_MCSPI_CHCONF_TRM_TX_ONLY (0x02 << 12)
+#define OMAP2_MCSPI_CHCONF_TRM_MASK    (0x03 << 12)
+#define OMAP2_MCSPI_CHCONF_DMAW                (1 << 14)
+#define OMAP2_MCSPI_CHCONF_DMAR                (1 << 15)
+#define OMAP2_MCSPI_CHCONF_DPE0                (1 << 16)
+#define OMAP2_MCSPI_CHCONF_DPE1                (1 << 17)
+#define OMAP2_MCSPI_CHCONF_IS          (1 << 18)
+#define OMAP2_MCSPI_CHCONF_TURBO       (1 << 19)
+#define OMAP2_MCSPI_CHCONF_FORCE       (1 << 20)
+
+
+#define OMAP2_MCSPI_CHSTAT_RXS         (1 << 0)
+#define OMAP2_MCSPI_CHSTAT_TXS         (1 << 1)
+#define OMAP2_MCSPI_CHSTAT_EOT         (1 << 2)
+
+#define OMAP2_MCSPI_CHCTRL_EN          (1 << 0)
+
+/* We have 2 DMA channels per CS, one for RX and one for TX */
+struct omap2_mcspi_dma {
+       int dma_tx_channel;
+       int dma_rx_channel;
+
+       int dma_tx_sync_dev;
+       int dma_rx_sync_dev;
+
+       struct completion dma_tx_completion;
+       struct completion dma_rx_completion;
+};
+
+struct omap2_mcspi {
+       struct work_struct      work;
+       spinlock_t              lock;
+       struct list_head        msg_queue;
+       struct spi_master       *master;
+       struct clk              *ick;
+       struct clk              *fck;
+       /* Virtual base address of the controller */
+       unsigned long           base;
+       /* SPI1 has 4 channels, while SPI2 has 2 */
+       struct omap2_mcspi_dma  *dma_channels;
+};
+
+struct omap2_mcspi_cs {
+       u8 transmit_mode;
+       int word_len;
+};
+
+static struct workqueue_struct * omap2_mcspi_wq;
+
+#define MOD_REG_BIT(val, mask, set) do { \
+       if (set) \
+               val |= mask; \
+       else \
+               val &= ~mask; \
+} while(0)
+
+static inline void mcspi_write_reg(struct spi_master *master,
+                                  int idx, u32 val)
+{
+       struct omap2_mcspi * mcspi = class_get_devdata(&master->cdev);
+
+       __raw_writel(val, mcspi->base + idx);
+}
+
+static inline u32 mcspi_read_reg(struct spi_master *master,
+                                int idx)
+{
+       struct omap2_mcspi * mcspi = class_get_devdata(&master->cdev);
+
+       return __raw_readl(mcspi->base + idx);
+}
+
+static inline void mcspi_write_cs_reg(const struct spi_device *spi,
+                                     int idx, u32 val)
+{
+       struct omap2_mcspi * mcspi = class_get_devdata(&spi->master->cdev);
+
+       __raw_writel(val, mcspi->base + spi->chip_select * 0x14 + idx);
+}
+
+static inline u32 mcspi_read_cs_reg(const struct spi_device *spi,
+                                   int idx)
+{
+       struct omap2_mcspi * mcspi = class_get_devdata(&spi->master->cdev);
+
+       return __raw_readl(mcspi->base + spi->chip_select * 0x14 + idx);
+}
+
+static void omap2_mcspi_set_dma_req(const struct spi_device *spi,
+                                   int is_read, int enable)
+{
+       u32 l, rw;
+
+       l = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
+
+       if (is_read) /* 1 is read, 0 write */
+               rw = OMAP2_MCSPI_CHCONF_DMAR;
+       else
+               rw = OMAP2_MCSPI_CHCONF_DMAW;
+
+       MOD_REG_BIT(l, rw, enable);
+       mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, l);
+}
+
+static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable)
+{
+       u32 l;
+
+       l = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0);
+       MOD_REG_BIT(l, OMAP2_MCSPI_CHCTRL_EN, enable);
+       mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, l);
+}
+
+static void omap2_mcspi_force_cs(struct spi_device *spi, int cs_active)
+{
+       u32 l;
+
+       l = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
+       MOD_REG_BIT(l, OMAP2_MCSPI_CHCONF_FORCE, cs_active);
+       mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, l);
+}
+
+static void omap2_mcspi_set_master_mode(struct spi_device *spi, int single_channel)
+{
+       u32 l;
+
+       /* Need reset when switching from slave mode */
+       l = mcspi_read_reg(spi->master, OMAP2_MCSPI_MODULCTRL);
+       MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_STEST, 0);
+       MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_MS, 0);
+       MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_SINGLE, single_channel);
+       mcspi_write_reg(spi->master, OMAP2_MCSPI_MODULCTRL, l);
+}
+
+static void omap2_mcspi_txrx_dma(struct spi_device *spi,
+                                struct spi_transfer *xfer)
+{
+       struct omap2_mcspi      * mcspi;
+       struct omap2_mcspi_cs   * cs = spi->controller_state;
+       struct omap2_mcspi_dma  * mcspi_dma;
+       unsigned int            count, c;
+       unsigned long           base, tx_reg, rx_reg;
+       int                     word_len, data_type, element_count;
+       u8                      * rx;
+       const u8                * tx;
+       u32                     l;
+
+       mcspi = class_get_devdata(&spi->master->cdev);
+       mcspi_dma = &mcspi->dma_channels[spi->chip_select];
+
+       count = xfer->len;
+       c = count;
+       word_len = cs->word_len;
+
+       l = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
+       l &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
+       if (xfer->tx_buf == NULL)
+               l |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY;
+       else if (xfer->rx_buf == NULL)
+               l |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY;
+       mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, l);
+
+       omap2_mcspi_set_enable(spi, 1);
+
+       base = io_v2p(mcspi->base) + spi->chip_select * 0x14;
+       tx_reg = base + OMAP2_MCSPI_TX0;
+       rx_reg = base + OMAP2_MCSPI_RX0;
+       rx = xfer->rx_buf;
+       tx = xfer->tx_buf;
+
+       if (word_len <= 8) {
+               data_type = OMAP_DMA_DATA_TYPE_S8;
+               element_count = count;
+       } else if (word_len <= 16) {
+               data_type = OMAP_DMA_DATA_TYPE_S16;
+               element_count = count >> 1;
+       } else if (word_len <= 32) {
+               data_type = OMAP_DMA_DATA_TYPE_S32;
+               element_count = count >> 2;
+       } else
+               return;
+
+       /* RX_ONLY mode needs dummy data in TX reg */
+       if (tx == NULL)
+               __raw_writel(0, mcspi->base +
+                            spi->chip_select * 0x14 + OMAP2_MCSPI_TX0);
+
+       if (tx != NULL) {
+               xfer->tx_dma = dma_map_single(&spi->dev, (void *) tx, count,
+                                             DMA_TO_DEVICE);
+               if (dma_mapping_error(xfer->tx_dma)) {
+                       printk(KERN_ERR "%s(): Couldn't DMA map a %d bytes TX buffer\n",
+                              __FUNCTION__, count);
+                       return;
+               }
+
+               omap_set_dma_transfer_params(mcspi_dma->dma_tx_channel,
+                                            data_type, element_count, 1,
+                                            OMAP_DMA_SYNC_ELEMENT,
+                                            mcspi_dma->dma_tx_sync_dev, 0);
+
+               omap_set_dma_dest_params(mcspi_dma->dma_tx_channel, 0,
+                                        OMAP_DMA_AMODE_CONSTANT,
+                                        tx_reg, 0, 0);
+
+               omap_set_dma_src_params(mcspi_dma->dma_tx_channel, 0,
+                                       OMAP_DMA_AMODE_POST_INC,
+                                       xfer->tx_dma, 0, 0);
+       }
+
+       if (rx != NULL) {
+               xfer->rx_dma = dma_map_single(&spi->dev, rx, count,
+                                             DMA_FROM_DEVICE);
+               if (dma_mapping_error(xfer->rx_dma)) {
+                       printk(KERN_ERR "%s(): Couldn't DMA map a %d bytes RX buffer\n",
+                              __FUNCTION__, count);
+                       if (tx != NULL)
+                               dma_unmap_single(NULL, xfer->tx_dma,
+                                                count, DMA_TO_DEVICE);
+                       return;
+               }
+
+               omap_set_dma_transfer_params(mcspi_dma->dma_rx_channel,
+                                            data_type, element_count, 1,
+                                            OMAP_DMA_SYNC_ELEMENT,
+                                            mcspi_dma->dma_rx_sync_dev, 1);
+
+               omap_set_dma_src_params(mcspi_dma->dma_rx_channel, 0,
+                                       OMAP_DMA_AMODE_CONSTANT,
+                                       rx_reg, 0, 0);
+
+               omap_set_dma_dest_params(mcspi_dma->dma_rx_channel, 0,
+                                        OMAP_DMA_AMODE_POST_INC,
+                                        xfer->rx_dma, 0, 0);
+       }
+
+       if (tx != NULL) {
+               omap_start_dma(mcspi_dma->dma_tx_channel);
+               omap2_mcspi_set_dma_req(spi, 0, 1);
+       }
+
+       if (rx != NULL) {
+               omap_start_dma(mcspi_dma->dma_rx_channel);
+               omap2_mcspi_set_dma_req(spi, 1, 1);
+       }
+
+       if (tx != NULL) {
+               wait_for_completion(&mcspi_dma->dma_tx_completion);
+               dma_unmap_single(NULL, xfer->tx_dma, count, DMA_TO_DEVICE);
+       }
+
+       if (rx != NULL) {
+               wait_for_completion(&mcspi_dma->dma_rx_completion);
+               dma_unmap_single(NULL, xfer->rx_dma, count, DMA_FROM_DEVICE);
+       }
+
+       omap2_mcspi_set_enable(spi, 0);
+}
+
+static void omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
+{
+       struct omap2_mcspi * mcspi;
+       struct omap2_mcspi_cs *cs = spi->controller_state;
+       unsigned int            count, c;
+       u32                     l;
+       unsigned long           base, tx_reg, rx_reg, chstat_reg;
+       int                     word_len;
+
+       mcspi = class_get_devdata(&spi->master->cdev);
+       count = xfer->len;
+       c = count;
+       word_len = cs->word_len;
+
+       l = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
+       l &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
+       if (xfer->tx_buf == NULL)
+               l |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY;
+       else if (xfer->rx_buf == NULL)
+               l |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY;
+       mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, l);
+
+       omap2_mcspi_set_enable(spi, 1);
+
+       /* We store the pre-calculated register addresses on stack to speed
+        * up the transfer loop. */
+       base = mcspi->base + spi->chip_select * 0x14;
+       tx_reg          = base + OMAP2_MCSPI_TX0;
+       rx_reg          = base + OMAP2_MCSPI_RX0;
+       chstat_reg      = base + OMAP2_MCSPI_CHSTAT0;
+
+       /* RX_ONLY mode needs dummy data in TX reg */
+       if (xfer->tx_buf == NULL)
+               __raw_writel(0, tx_reg);
+
+       if (word_len <= 8) {
+               u8              *rx;
+               const u8        *tx;
+
+               rx = xfer->rx_buf;
+               tx = xfer->tx_buf;
+
+               while (c--) {
+                       if (tx != NULL) {
+                               while (!(__raw_readl(chstat_reg) & OMAP2_MCSPI_CHSTAT_TXS));
+#ifdef VERBOSE
+                               dev_dbg(&spi->dev, "write-%d %02x\n",
+                                               word_len, *tx);
+#endif
+                               __raw_writel(*tx, tx_reg);
+                       }
+                       if (rx != NULL) {
+                               while (!(__raw_readl(chstat_reg) & OMAP2_MCSPI_CHSTAT_RXS));
+                               if (c == 0 && tx == NULL)
+                                       omap2_mcspi_set_enable(spi, 0);
+                               *rx++ = __raw_readl(rx_reg);
+#ifdef VERBOSE
+                               dev_dbg(&spi->dev, "read-%d %02x\n",
+                                               word_len, *(rx - 1));
+#endif
+                       }
+               }
+       } else if (word_len <= 16) {
+               u16             *rx;
+               const u16       *tx;
+
+               rx = xfer->rx_buf;
+               tx = xfer->tx_buf;
+               c >>= 1;
+               while (c--) {
+                       if (tx != NULL) {
+                               while (!(__raw_readl(chstat_reg) & OMAP2_MCSPI_CHSTAT_TXS));
+#ifdef VERBOSE
+                               dev_dbg(&spi->dev, "write-%d %04x\n",
+                                               word_len, *tx);
+#endif
+                               __raw_writel(*tx++, tx_reg);
+                       }
+                       if (rx != NULL) {
+                               while (!(__raw_readl(chstat_reg) & OMAP2_MCSPI_CHSTAT_RXS));
+                               if (c == 0 && tx == NULL)
+                                       omap2_mcspi_set_enable(spi, 0);
+                               *rx++ = __raw_readl(rx_reg);
+#ifdef VERBOSE
+                               dev_dbg(&spi->dev, "read-%d %04x\n",
+                                               word_len, *(rx - 1));
+#endif
+                       }
+               }
+       } else if (word_len <= 32) {
+               u32             *rx;
+               const u32       *tx;
+
+               rx = xfer->rx_buf;
+               tx = xfer->tx_buf;
+               c >>= 2;
+               while (c--) {
+                       if (tx != NULL) {
+                               while (!(__raw_readl(chstat_reg) & OMAP2_MCSPI_CHSTAT_TXS));
+#ifdef VERBOSE
+                               dev_dbg(&spi->dev, "write-%d %04x\n",
+                                               word_len, *tx);
+#endif
+                               __raw_writel(*tx++, tx_reg);
+                       }
+                       if (rx != NULL) {
+                               while (!(__raw_readl(chstat_reg) & OMAP2_MCSPI_CHSTAT_RXS));
+                               if (c == 0 && tx == NULL)
+                                       omap2_mcspi_set_enable(spi, 0);
+                               *rx++ = __raw_readl(rx_reg);
+#ifdef VERBOSE
+                               dev_dbg(&spi->dev, "read-%d %04x\n",
+                                               word_len, *(rx - 1));
+#endif
+                       }
+               }
+       }
+
+       if (xfer->tx_buf != NULL) {
+               while (!(__raw_readl(chstat_reg) & OMAP2_MCSPI_CHSTAT_TXS));
+               while (!(__raw_readl(chstat_reg) & OMAP2_MCSPI_CHSTAT_EOT));
+               omap2_mcspi_set_enable(spi, 0);
+       }
+}
+
+static int omap2_mcspi_setup_transfer(struct spi_device *spi,
+                                     struct spi_transfer *t)
+{
+       struct omap2_mcspi_cs *cs = spi->controller_state;
+       struct omap2_mcspi_device_config *conf;
+       u32 l = 0, div = 0;
+       u8 word_len = spi->bits_per_word;
+
+       if (t != NULL && t->bits_per_word)
+               word_len = t->bits_per_word;
+       if (!word_len)
+               word_len = 8;
+
+       if (spi->bits_per_word > 32)
+               return -EINVAL;
+       cs->word_len = word_len;
+
+       conf = (struct omap2_mcspi_device_config *) spi->controller_data;
+
+       if (conf->single_channel == 1)
+               omap2_mcspi_set_master_mode(spi, 1);
+       else
+               omap2_mcspi_set_master_mode(spi, 0);
+
+       if (spi->max_speed_hz) {
+               while (div <= 15 && (OMAP2_MCSPI_MAX_FREQ / (1 << div)) > spi->max_speed_hz)
+                       div++;
+       } else
+               div = 15;
+
+       if (spi->chip_select > 3 ||
+           word_len < 4 || word_len > 32 ||
+           div > 15) {
+               dev_err(&spi->dev, "Invalid McSPI channel setting\n");
+               return -EINVAL;
+       }
+
+       l = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
+       l &= ~OMAP2_MCSPI_CHCONF_IS;
+       l &= ~OMAP2_MCSPI_CHCONF_DPE1;
+       l |= OMAP2_MCSPI_CHCONF_DPE0;
+       l &= ~OMAP2_MCSPI_CHCONF_WL_MASK;
+       l |= (word_len - 1) << 7;
+       if (!(spi->mode & SPI_CS_HIGH))
+               l |= OMAP2_MCSPI_CHCONF_EPOL;
+       else
+               l &= ~OMAP2_MCSPI_CHCONF_EPOL;
+       l &= ~OMAP2_MCSPI_CHCONF_CLKD_MASK;
+       l |= div << 2;
+       if (spi->mode & SPI_CPOL)
+               l |= OMAP2_MCSPI_CHCONF_POL;
+       else
+               l &= ~OMAP2_MCSPI_CHCONF_POL;
+       if (spi->mode & SPI_CPHA)
+               l &= ~OMAP2_MCSPI_CHCONF_PHA;
+       else
+               l |= OMAP2_MCSPI_CHCONF_PHA;
+       mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, l);
+
+       dev_dbg(&spi->dev, "setup: speed %d, sample %s edge, clk %s inverted\n",
+                       OMAP2_MCSPI_MAX_FREQ / (1 << div),
+                       (spi->mode & SPI_CPHA) ? "odd" : "even",
+                       (spi->mode & SPI_CPOL) ? "" : "not");
+
+       return 0;
+}
+
+static void omap2_mcspi_dma_rx_callback(int lch, u16 ch_status, void *data)
+{
+       struct spi_device * spi = (struct spi_device *)data;
+       struct omap2_mcspi * mcspi;
+       struct omap2_mcspi_dma * mcspi_dma;
+
+       mcspi = class_get_devdata(&spi->master->cdev);
+       mcspi_dma = &(mcspi->dma_channels[spi->chip_select]);
+
+       complete(&mcspi_dma->dma_rx_completion);
+
+       /* We must disable the DMA RX request */
+       omap2_mcspi_set_dma_req(spi, 1, 0);
+}
+
+static void omap2_mcspi_dma_tx_callback(int lch, u16 ch_status, void *data)
+{
+       struct spi_device * spi = (struct spi_device *)data;
+       struct omap2_mcspi * mcspi;
+       struct omap2_mcspi_dma * mcspi_dma;
+
+       mcspi = class_get_devdata(&spi->master->cdev);
+       mcspi_dma = &(mcspi->dma_channels[spi->chip_select]);
+
+       complete(&mcspi_dma->dma_tx_completion);
+
+       /* We must disable the DMA TX request */
+       omap2_mcspi_set_dma_req(spi, 0, 0);
+}
+
+static int omap2_mcspi_request_dma(struct spi_device *spi)
+{
+       int rx_dev_id, tx_dev_id;
+       struct spi_master *master = spi->master;
+       struct omap2_mcspi * mcspi;
+       struct omap2_mcspi_dma * mcspi_dma;
+
+       mcspi = class_get_devdata(&master->cdev);
+       mcspi_dma = &(mcspi->dma_channels[spi->chip_select]);
+
+       if (master->bus_num == 1) {
+               switch (spi->chip_select) {
+               case 0:
+                       rx_dev_id = OMAP24XX_DMA_SPI1_RX0;
+                       tx_dev_id = OMAP24XX_DMA_SPI1_TX0;
+                       break;
+               case 1:
+                       rx_dev_id = OMAP24XX_DMA_SPI1_RX1;
+                       tx_dev_id = OMAP24XX_DMA_SPI1_TX1;
+                       break;
+               case 2:
+                       rx_dev_id = OMAP24XX_DMA_SPI1_RX2;
+                       tx_dev_id = OMAP24XX_DMA_SPI1_TX2;
+                       break;
+               case 3:
+                       rx_dev_id = OMAP24XX_DMA_SPI1_RX3;
+                       tx_dev_id = OMAP24XX_DMA_SPI1_TX3;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       } else if (master->bus_num == 2) {
+               /* McSPI 2 has 1 chipselect */
+               switch (spi->chip_select) {
+               case 0:
+                       rx_dev_id = OMAP24XX_DMA_SPI2_RX0;
+                       tx_dev_id = OMAP24XX_DMA_SPI2_TX0;
+                       break;
+               case 1:
+                       rx_dev_id = OMAP24XX_DMA_SPI2_RX1;
+                       tx_dev_id = OMAP24XX_DMA_SPI2_TX1;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       } else
+               return -EINVAL;
+
+
+       if (omap_request_dma(rx_dev_id, "McSPI RX",
+                            omap2_mcspi_dma_rx_callback, spi,
+                            &mcspi_dma->dma_rx_channel)) {
+               printk(KERN_ERR "Unable to request DMA channel for McSPI RX\n");
+               return -EAGAIN;
+       }
+       
+       if (omap_request_dma(tx_dev_id, "McSPI TX",
+                            omap2_mcspi_dma_tx_callback, spi,
+                            &mcspi_dma->dma_tx_channel)) {
+               omap_free_dma(mcspi_dma->dma_rx_channel);
+               mcspi_dma->dma_rx_channel = -1;
+               printk(KERN_ERR "Unable to request DMA channel for McSPI TX\n");
+               return -EAGAIN;
+       }
+       
+       mcspi_dma->dma_rx_sync_dev = rx_dev_id;
+       mcspi_dma->dma_tx_sync_dev = tx_dev_id;
+
+       init_completion(&mcspi_dma->dma_rx_completion);
+       init_completion(&mcspi_dma->dma_tx_completion);
+       
+       return 0;
+}
+
+static int omap2_mcspi_setup(struct spi_device *spi)
+{
+       int ret;
+       struct omap2_mcspi * mcspi;
+       struct omap2_mcspi_dma * mcspi_dma;
+       struct omap2_mcspi_cs *cs = spi->controller_state;
+
+       mcspi = class_get_devdata(&spi->master->cdev);
+       mcspi_dma = &mcspi->dma_channels[spi->chip_select];
+
+       if (!cs) {
+               cs = kzalloc(sizeof *cs, GFP_KERNEL);
+               if (!cs)
+                       return -ENOMEM;
+               spi->controller_state = cs;
+       }
+       
+       if (mcspi_dma->dma_rx_channel == -1 ||
+           mcspi_dma->dma_tx_channel == -1) {
+               ret = omap2_mcspi_request_dma(spi);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return omap2_mcspi_setup_transfer(spi, NULL);
+}
+
+static void omap2_mcspi_cleanup(const struct spi_device *spi)
+{
+       struct omap2_mcspi * mcspi;
+       struct omap2_mcspi_dma * mcspi_dma;
+
+       mcspi = class_get_devdata(&spi->master->cdev);
+       mcspi_dma = &mcspi->dma_channels[spi->chip_select];
+
+       if (spi->controller_state != NULL)
+               kfree(spi->controller_state);
+
+       if (mcspi_dma->dma_rx_channel != -1 &&
+           mcspi_dma->dma_tx_channel != -1) {
+               omap_free_dma(mcspi_dma->dma_tx_channel);
+               omap_free_dma(mcspi_dma->dma_rx_channel);
+       }
+}
+
+
+static void omap2_mcspi_work(struct work_struct *work)
+{
+       struct omap2_mcspi      *mcspi = container_of(work, struct omap2_mcspi, work);
+       unsigned long           flags;
+
+       spin_lock_irqsave(&mcspi->lock, flags);
+       while (!list_empty(&mcspi->msg_queue)) {
+               struct spi_message              *m;
+               struct spi_device               *spi;
+               struct spi_transfer             *t = NULL;
+               int                             cs_active = 0;
+               struct omap2_mcspi_device_config *conf;
+               struct omap2_mcspi_cs           *cs;
+               int                             par_override = 0;
+               int status = 0;
+
+               m = container_of(mcspi->msg_queue.next, struct spi_message,
+                                queue);
+
+               list_del_init(&m->queue);
+               spin_unlock_irqrestore(&mcspi->lock, flags);
+
+               spi = m->spi;
+               conf = (struct omap2_mcspi_device_config *) spi->controller_data;
+               cs = (struct omap2_mcspi_cs *) spi->controller_state;
+
+               list_for_each_entry(t, &m->transfers, transfer_list) {
+                       if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
+                               status = -EINVAL;
+                               break;
+                       }
+                       if (par_override || t->speed_hz || t->bits_per_word) {
+                               par_override = 1;
+                               status = omap2_mcspi_setup_transfer(spi, t);
+                               if (status < 0)
+                                       break;
+                               if (!t->speed_hz && !t->bits_per_word)
+                                       par_override = 0;
+                       }
+
+                       if (!cs_active) {
+                               omap2_mcspi_force_cs(spi, 1);
+                               cs_active = 1;
+                       }
+
+                       if (m->is_dma_mapped &&
+                           (t->tx_dma != 0 || t->rx_dma != 0))
+                               omap2_mcspi_txrx_dma(spi, t);
+                       else
+                               omap2_mcspi_txrx_pio(spi, t);
+
+                       if (t->cs_change) {
+                               /* In the last transfer entry the flag means
+                                * _leave_ CS on */
+                               if (t->transfer_list.next != &m->transfers)
+                                       omap2_mcspi_force_cs(spi, 0);
+                               cs_active = 0;
+                       }
+               }
+
+               /* Restore defaults they are overriden */
+               if (par_override) {
+                       par_override = 0;
+                       status = omap2_mcspi_setup_transfer(spi, NULL);
+               }
+
+               if (cs_active)
+                       omap2_mcspi_force_cs(spi, 0);
+
+               m->status = status;
+               m->complete(m->context);
+
+               spin_lock_irqsave(&mcspi->lock, flags);
+       }
+       spin_unlock_irqrestore(&mcspi->lock, flags);
+}
+
+static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m)
+{
+       struct omap2_mcspi      *mcspi;
+       unsigned long           flags;
+
+       m->actual_length = 0;
+       m->status = 0;
+
+       mcspi = class_get_devdata(&spi->master->cdev);
+
+       spin_lock_irqsave(&mcspi->lock, flags);
+       list_add_tail(&m->queue, &mcspi->msg_queue);
+       spin_unlock_irqrestore(&mcspi->lock, flags);
+
+       queue_work(omap2_mcspi_wq, &mcspi->work);
+
+       return 0;
+}
+
+static int __devinit omap2_mcspi_reset(struct spi_master *master)
+{
+#if 0
+       mcspi_write_reg(master, OMAP2_MCSPI_SYSCONFIG,
+                       OMAP2_MCSPI_SYSCONFIG_SOFTRESET);
+       while (!(mcspi_read_reg(master, OMAP2_MCSPI_SYSSTATUS) & OMAP2_MCSPI_SYSSTATUS_RESETDONE));
+#else
+       return 0;
+#endif
+}
+
+static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
+{
+       struct spi_master               *master;
+       struct omap2_mcspi_platform_config *pdata = pdev->dev.platform_data;
+       struct omap2_mcspi              *mcspi;
+       struct resource                 *r;
+       int                             status = 0, i;
+               
+       if (!pdata)
+               return -EINVAL;
+
+       master = spi_alloc_master(&pdev->dev, sizeof *mcspi);
+       if (master == NULL) {
+               dev_err(&pdev->dev, "master allocation failed\n");
+               return -ENOMEM;
+       }
+
+       if (pdev->id != -1)
+               master->bus_num = pdev->id;
+
+       master->setup = omap2_mcspi_setup;
+       master->transfer = omap2_mcspi_transfer;
+       master->cleanup = omap2_mcspi_cleanup;
+       master->num_chipselect = pdata->num_cs;
+
+       if (class_device_get(&master->cdev) == NULL) {
+               dev_err(&pdev->dev, "no master->cdev");
+               status = -ENOMEM;
+               goto err0;
+       }
+
+       dev_set_drvdata(&pdev->dev, master);
+
+       mcspi = class_get_devdata(&master->cdev);
+       mcspi->master = master;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (r == NULL) {
+               status = -ENODEV;
+               goto err1;
+       }
+       
+       mcspi->base = io_p2v(r->start);
+
+       INIT_WORK(&mcspi->work, omap2_mcspi_work);
+
+       spin_lock_init(&mcspi->lock);
+       INIT_LIST_HEAD(&mcspi->msg_queue);
+
+       mcspi->ick = clk_get(&pdev->dev, "mcspi_ick");
+       if (IS_ERR(mcspi->ick)) {
+               dev_err(&pdev->dev, "can't get mcspi_ick\n");
+               status = PTR_ERR(mcspi->ick);
+               goto err1;
+       }
+       clk_enable(mcspi->ick);
+       mcspi->fck = clk_get(&pdev->dev, "mcspi_fck");
+       if (IS_ERR(mcspi->fck)) {
+               dev_err(&pdev->dev, "can't get mcspi_fck\n");
+               status = PTR_ERR(mcspi->fck);
+               goto err2;
+       }
+       clk_enable(mcspi->fck);
+
+       mcspi->dma_channels = 
+               (struct omap2_mcspi_dma *)kzalloc(master->num_chipselect *
+                                                 sizeof(struct omap2_mcspi_dma),
+                                                 GFP_KERNEL);
+       
+       if (mcspi->dma_channels == NULL)
+               goto err3;
+
+       for (i = 0; i < master->num_chipselect; i++) {
+               mcspi->dma_channels[i].dma_rx_channel = -1;
+               mcspi->dma_channels[i].dma_tx_channel = -1;
+       }
+
+       if (omap2_mcspi_reset(master) < 0)
+                goto err4;
+
+       status = spi_register_master(master);
+       if (status < 0)
+               goto err4;
+
+       return status;
+
+err4:
+       kfree(mcspi->dma_channels);
+err3:
+       clk_disable(mcspi->fck);
+       clk_put(mcspi->fck);
+err2:
+       clk_disable(mcspi->ick);
+       clk_put(mcspi->ick);
+err1:
+       class_device_put(&master->cdev);
+err0:
+       return status;
+}
+
+static int __devexit omap2_mcspi_remove(struct platform_device *pdev)
+{
+       struct spi_master               *master;
+       struct omap2_mcspi              *mcspi;
+
+       master = dev_get_drvdata(&pdev->dev);
+
+       spi_unregister_master(master);
+       mcspi = class_get_devdata(&master->cdev);
+       clk_disable(mcspi->fck);
+       clk_put(mcspi->fck);
+       clk_disable(mcspi->ick);
+       clk_put(mcspi->ick);
+       class_device_put(&master->cdev);
+       kfree(mcspi->dma_channels);
+
+       return 0;
+}
+
+struct platform_driver omap2_mcspi_driver = {
+       .driver = {
+               .name =         "omap2_mcspi",
+               .owner =        THIS_MODULE,
+       },
+       .probe =        omap2_mcspi_probe,
+       .remove =       __devexit_p(omap2_mcspi_remove),
+};
+EXPORT_SYMBOL_GPL(omap2_mcspi_driver);
+
+
+static int __init omap2_mcspi_init(void)
+{
+       printk(KERN_INFO "OMAP24xx McSPI driver initializing\n");
+       omap2_mcspi_wq = create_workqueue("OMAP McSPI");
+       if (omap2_mcspi_wq == NULL)
+               return -1;
+       return platform_driver_register(&omap2_mcspi_driver);
+}
+subsys_initcall(omap2_mcspi_init);
+
+static void __exit omap2_mcspi_exit(void)
+{
+       platform_driver_unregister(&omap2_mcspi_driver);
+}
+module_exit(omap2_mcspi_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/omap_uwire.c b/drivers/spi/omap_uwire.c
new file mode 100644 (file)
index 0000000..b5a4d62
--- /dev/null
@@ -0,0 +1,567 @@
+/*
+ * omap_uwire.c -- MicroWire interface driver for OMAP
+ *
+ * Copyright 2003 MontaVista Software Inc. <source@mvista.com>
+ *
+ * Ported to 2.6 OMAP uwire interface.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * Generalization patches by Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * Copyright (C) 2005 David Brownell (ported to 2.6 SPI interface)
+ *
+ * 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 SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/mux.h>
+#include <asm/arch/omap730.h>  /* OMAP730_IO_CONF registers */
+
+
+/* FIXME address is now a platform device resource,
+ * and irqs should show there too...
+ */
+#define UWIRE_BASE_PHYS                0xFFFB3000
+#define UWIRE_BASE             ((void *__iomem)IO_ADDRESS(UWIRE_BASE_PHYS))
+
+/* uWire Registers: */
+#define UWIRE_IO_SIZE 0x20
+#define UWIRE_TDR     0x00
+#define UWIRE_RDR     0x00
+#define UWIRE_CSR     0x01
+#define UWIRE_SR1     0x02
+#define UWIRE_SR2     0x03
+#define UWIRE_SR3     0x04
+#define UWIRE_SR4     0x05
+#define UWIRE_SR5     0x06
+
+/* CSR bits */
+#define        RDRB    (1 << 15)
+#define        CSRB    (1 << 14)
+#define        START   (1 << 13)
+#define        CS_CMD  (1 << 12)
+
+/* SR1 or SR2 bits */
+#define UWIRE_READ_FALLING_EDGE                0x0001
+#define UWIRE_READ_RISING_EDGE         0x0000
+#define UWIRE_WRITE_FALLING_EDGE       0x0000
+#define UWIRE_WRITE_RISING_EDGE                0x0002
+#define UWIRE_CS_ACTIVE_LOW            0x0000
+#define UWIRE_CS_ACTIVE_HIGH           0x0004
+#define UWIRE_FREQ_DIV_2               0x0000
+#define UWIRE_FREQ_DIV_4               0x0008
+#define UWIRE_FREQ_DIV_8               0x0010
+#define UWIRE_CHK_READY                        0x0020
+#define UWIRE_CLK_INVERTED             0x0040
+
+
+struct uwire_spi {
+       struct spi_bitbang      bitbang;
+       struct clk              *ck;
+};
+
+struct uwire_state {
+       unsigned        bits_per_word;
+       unsigned        div1_idx;
+};
+
+/* REVISIT compile time constant for idx_shift? */
+static unsigned int uwire_idx_shift;
+
+static inline void uwire_write_reg(int idx, u16 val)
+{
+       __raw_writew(val, UWIRE_BASE + (idx << uwire_idx_shift));
+}
+
+static inline u16 uwire_read_reg(int idx)
+{
+       return __raw_readw(UWIRE_BASE + (idx << uwire_idx_shift));
+}
+
+static inline void omap_uwire_configure_mode(u8 cs, unsigned long flags)
+{
+       u16     w, val = 0;
+       int     shift, reg;
+
+       if (flags & UWIRE_CLK_INVERTED)
+               val ^= 0x03;
+       val = flags & 0x3f;
+       if (cs & 1)
+               shift = 6;
+       else
+               shift = 0;
+       if (cs <= 1)
+               reg = UWIRE_SR1;
+       else
+               reg = UWIRE_SR2;
+
+       w = uwire_read_reg(reg);
+       w &= ~(0x3f << shift);
+       w |= val << shift;
+       uwire_write_reg(reg, w);
+}
+
+static int wait_uwire_csr_flag(u16 mask, u16 val, int might_not_catch)
+{
+       u16 w;
+       int c = 0;
+       unsigned long max_jiffies = jiffies + HZ;
+
+       for (;;) {
+               w = uwire_read_reg(UWIRE_CSR);
+               if ((w & mask) == val)
+                       break;
+               if (time_after(jiffies, max_jiffies)) {
+                       printk(KERN_ERR "%s: timeout. reg=%#06x "
+                                       "mask=%#06x val=%#06x\n",
+                              __FUNCTION__, w, mask, val);
+                       return -1;
+               }
+               c++;
+               if (might_not_catch && c > 64)
+                       break;
+       }
+       return 0;
+}
+
+static void uwire_set_clk1_div(int div1_idx)
+{
+       u16 w;
+
+       w = uwire_read_reg(UWIRE_SR3);
+       w &= ~(0x03 << 1);
+       w |= div1_idx << 1;
+       uwire_write_reg(UWIRE_SR3, w);
+}
+
+static void uwire_chipselect(struct spi_device *spi, int value)
+{
+       struct  uwire_state *ust = spi->controller_state;
+       u16     w;
+       int     old_cs;
+
+
+       BUG_ON(wait_uwire_csr_flag(CSRB, 0, 0));
+
+       w = uwire_read_reg(UWIRE_CSR);
+       old_cs = (w >> 10) & 0x03;
+       if (value == BITBANG_CS_INACTIVE || old_cs != spi->chip_select) {
+               /* Deselect this CS, or the previous CS */
+               w &= ~CS_CMD;
+               uwire_write_reg(UWIRE_CSR, w);
+       }
+       /* activate specfied chipselect */
+       if (value == BITBANG_CS_ACTIVE) {
+               uwire_set_clk1_div(ust->div1_idx);
+               /* invert clock? */
+               if (spi->mode & SPI_CPOL)
+                       uwire_write_reg(UWIRE_SR4, 1);
+               else
+                       uwire_write_reg(UWIRE_SR4, 0);
+
+               w = spi->chip_select << 10;
+               w |= CS_CMD;
+               uwire_write_reg(UWIRE_CSR, w);
+       }
+}
+
+static int uwire_txrx(struct spi_device *spi, struct spi_transfer *t)
+{
+       struct uwire_state *ust = spi->controller_state;
+       unsigned        len = t->len;
+       unsigned        bits = ust->bits_per_word;
+       unsigned        bytes;
+       u16             val, w;
+       int             status = 0;;
+
+       if (!t->tx_buf && !t->rx_buf)
+               return 0;
+
+       /* Microwire doesn't read and write concurrently */
+       if (t->tx_buf && t->rx_buf)
+               return -EPERM;
+
+       w = spi->chip_select << 10;
+       w |= CS_CMD;
+
+       if (t->tx_buf) {
+               const u8        *buf = t->tx_buf;
+
+               /* NOTE:  DMA could be used for TX transfers */
+
+               /* write one or two bytes at a time */
+               while (len >= 1) {
+                       /* tx bit 15 is first sent; we byteswap multibyte words
+                        * (msb-first) on the way out from memory.
+                        */
+                       val = *buf++;
+                       if (bits > 8) {
+                               bytes = 2;
+                               val |= *buf++ << 8;
+                       } else
+                               bytes = 1;
+                       val <<= 16 - bits;
+
+#ifdef VERBOSE
+                       pr_debug("%s: write-%d =%04x\n",
+                                       spi->dev.bus_id, bits, val);
+#endif
+                       if (wait_uwire_csr_flag(CSRB, 0, 0))
+                               goto eio;
+
+                       uwire_write_reg(UWIRE_TDR, val);
+
+                       /* start write */
+                       val = START | w | (bits << 5);
+
+                       uwire_write_reg(UWIRE_CSR, val);
+                       len -= bytes;
+
+                       /* Wait till write actually starts.
+                        * This is needed with MPU clock 60+ MHz.
+                        * REVISIT: we may not have time to catch it...
+                        */
+                       if (wait_uwire_csr_flag(CSRB, CSRB, 1))
+                               goto eio;
+
+                       status += bytes;
+               }
+
+               /* REVISIT:  save this for later to get more i/o overlap */
+               if (wait_uwire_csr_flag(CSRB, 0, 0))
+                       goto eio;
+
+       } else if (t->rx_buf) {
+               u8              *buf = t->rx_buf;
+
+               /* read one or two bytes at a time */
+               while (len) {
+                       if (bits > 8) {
+                               bytes = 2;
+                       } else
+                               bytes = 1;
+
+                       /* start read */
+                       val = START | w | (bits << 0);
+                       uwire_write_reg(UWIRE_CSR, val);
+                       len -= bytes;
+
+                       /* Wait till read actually starts */
+                       (void) wait_uwire_csr_flag(CSRB, CSRB, 1);
+
+                       if (wait_uwire_csr_flag(RDRB | CSRB,
+                                               RDRB, 0))
+                               goto eio;
+
+                       /* rx bit 0 is last received; multibyte words will
+                        * be properly byteswapped on the way to memory.
+                        */
+                       val = uwire_read_reg(UWIRE_RDR);
+                       val &= (1 << bits) - 1;
+                       *buf++ = (u8) val;
+                       if (bytes == 2)
+                               *buf++ = val >> 8;
+                       status += bytes;
+#ifdef VERBOSE
+                       pr_debug("%s: read-%d =%04x\n",
+                                       spi->dev.bus_id, bits, val);
+#endif
+
+               }
+       }
+       return status;
+eio:
+       return -EIO;
+}
+
+static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
+{
+       struct uwire_state      *ust = spi->controller_state;
+       struct uwire_spi        *uwire;
+       unsigned                flags = 0;
+       unsigned                bits;
+       unsigned                hz;
+       unsigned long           rate;
+       int                     div1_idx;
+       int                     div1;
+       int                     div2;
+       int                     status;
+
+       uwire = spi_master_get_devdata(spi->master);
+
+       if (spi->chip_select > 3) {
+               pr_debug("%s: cs%d?\n", spi->dev.bus_id, spi->chip_select);
+               status = -ENODEV;
+               goto done;
+       }
+
+       bits = spi->bits_per_word;
+       if (t != NULL && t->bits_per_word)
+               bits = t->bits_per_word;
+       if (!bits)
+               bits = 8;
+
+       if (bits > 16) {
+               pr_debug("%s: wordsize %d?\n", spi->dev.bus_id, bits);
+               status = -ENODEV;
+               goto done;
+       }
+       ust->bits_per_word = bits;
+
+       /* mode 0..3, clock inverted separately;
+        * standard nCS signaling;
+        * don't treat DI=high as "not ready"
+        */
+       if (spi->mode & SPI_CS_HIGH)
+               flags |= UWIRE_CS_ACTIVE_HIGH;
+
+       if (spi->mode & SPI_CPOL)
+               flags |= UWIRE_CLK_INVERTED;
+
+       switch (spi->mode & (SPI_CPOL | SPI_CPHA)) {
+       case SPI_MODE_0:
+       case SPI_MODE_3:
+               flags |= UWIRE_WRITE_RISING_EDGE | UWIRE_READ_FALLING_EDGE;
+               break;
+       case SPI_MODE_1:
+       case SPI_MODE_2:
+               flags |= UWIRE_WRITE_FALLING_EDGE | UWIRE_READ_RISING_EDGE;
+               break;
+       }
+
+       /* assume it's already enabled */
+       rate = clk_get_rate(uwire->ck);
+
+       hz = spi->max_speed_hz;
+       if (t != NULL && t->speed_hz)
+               hz = t->speed_hz;
+
+       if (!hz) {
+               pr_debug("%s: zero speed?\n", spi->dev.bus_id);
+               status = -EINVAL;
+               goto done;
+       }
+
+       /* F_INT = mpu_xor_clk / DIV1 */
+       for (div1_idx = 0; div1_idx < 4; div1_idx++) {
+               switch (div1_idx) {
+               case 0:
+                       div1 = 2;
+                       break;
+               case 1:
+                       div1 = 4;
+                       break;
+               case 2:
+                       div1 = 7;
+                       break;
+               default:
+               case 3:
+                       div1 = 10;
+                       break;
+               }
+               div2 = (rate / div1 + hz - 1) / hz;
+               if (div2 <= 8)
+                       break;
+       }
+       if (div1_idx == 4) {
+               pr_debug("%s: lowest clock %ld, need %d\n",
+                       spi->dev.bus_id, rate / 10 / 8, hz);
+                       status = -EDOM;
+                       goto done;
+       }
+
+       /* we have to cache this and reset in uwire_chipselect as this is a
+        * global parameter and another uwire device can change it under
+        * us */
+       ust->div1_idx = div1_idx;
+       uwire_set_clk1_div(div1_idx);
+
+       rate /= div1;
+
+       switch (div2) {
+       case 0:
+       case 1:
+       case 2:
+               flags |= UWIRE_FREQ_DIV_2;
+               rate /= 2;
+               break;
+       case 3:
+       case 4:
+               flags |= UWIRE_FREQ_DIV_4;
+               rate /= 4;
+               break;
+       case 5:
+       case 6:
+       case 7:
+       case 8:
+               flags |= UWIRE_FREQ_DIV_8;
+               rate /= 8;
+               break;
+       }
+       omap_uwire_configure_mode(spi->chip_select, flags);
+       pr_debug("%s: uwire flags %02x, armxor %lu KHz, SCK %lu KHz\n",
+                       __FUNCTION__, flags,
+                       clk_get_rate(uwire->ck) / 1000,
+                       rate / 1000);
+       status = 0;
+done:
+       return status;
+}
+
+static int uwire_setup(struct spi_device *spi)
+{
+       struct uwire_state *ust = spi->controller_state;
+
+       if (ust == NULL) {
+               ust = kzalloc(sizeof(*ust), GFP_KERNEL);
+               if (ust == NULL)
+                       return -ENOMEM;
+               spi->controller_state = ust;
+       }
+
+       return uwire_setup_transfer(spi, NULL);
+}
+
+static void uwire_cleanup(const struct spi_device *spi)
+{
+       kfree(spi->controller_state);
+}
+
+static void uwire_off(struct uwire_spi *uwire)
+{
+       uwire_write_reg(UWIRE_SR3, 0);
+       clk_disable(uwire->ck);
+       clk_put(uwire->ck);
+       spi_master_put(uwire->bitbang.master);
+}
+
+static int uwire_probe(struct platform_device *pdev)
+{
+       struct spi_master       *master;
+       struct uwire_spi        *uwire;
+       int                     status;
+
+       master = spi_alloc_master(&pdev->dev, sizeof *uwire);
+       if (!master)
+               return -ENODEV;
+
+       uwire = spi_master_get_devdata(master);
+       dev_set_drvdata(&pdev->dev, uwire);
+
+       uwire->ck = clk_get(&pdev->dev, "armxor_ck");
+       if (!uwire->ck || IS_ERR(uwire->ck)) {
+               dev_dbg(&pdev->dev, "no mpu_xor_clk ?\n");
+               spi_master_put(master);
+               return -ENODEV;
+       }
+       clk_enable(uwire->ck);
+
+       if (cpu_is_omap730())
+               uwire_idx_shift = 1;
+       else
+               uwire_idx_shift = 2;
+
+       uwire_write_reg(UWIRE_SR3, 1);
+
+       master->bus_num = 2;    /* "official" */
+       master->num_chipselect = 4;
+       master->setup = uwire_setup;
+       master->cleanup = uwire_cleanup;
+
+       uwire->bitbang.master = master;
+       uwire->bitbang.chipselect = uwire_chipselect;
+       uwire->bitbang.setup_transfer = uwire_setup_transfer;
+       uwire->bitbang.txrx_bufs = uwire_txrx;
+
+       status = spi_bitbang_start(&uwire->bitbang);
+       if (status < 0)
+               uwire_off(uwire);
+       return status;
+}
+
+static int uwire_remove(struct platform_device *pdev)
+{
+       struct uwire_spi        *uwire = dev_get_drvdata(&pdev->dev);
+       int                     status;
+
+       // FIXME remove all child devices, somewhere ...
+
+       status = spi_bitbang_stop(&uwire->bitbang);
+       uwire_off(uwire);
+       return status;
+}
+
+static struct platform_driver uwire_driver = {
+       .driver = {
+               .name           = "omap_uwire",
+               .bus            = &platform_bus_type,
+               .owner          = THIS_MODULE,
+       },
+       .probe          = uwire_probe,
+       .remove         = uwire_remove,
+       // suspend ... unuse ck
+       // resume ... use ck
+};
+
+static int __init omap_uwire_init(void)
+{
+       /* FIXME move these into the relevant board init code. also, include
+        * H3 support; it uses tsc2101 like H2 (on a different chipselect).
+        */
+
+       if (machine_is_omap_h2()) {
+               /* defaults: W21 SDO, U18 SDI, V19 SCL */
+               omap_cfg_reg(N14_1610_UWIRE_CS0);
+               omap_cfg_reg(N15_1610_UWIRE_CS1);
+       }
+       if (machine_is_omap_perseus2()) {
+               /* configure pins: MPU_UW_nSCS1, MPU_UW_SDO, MPU_UW_SCLK */
+               int val = omap_readl(OMAP730_IO_CONF_9) & ~0x00EEE000;
+               omap_writel(val | 0x00AAA000, OMAP730_IO_CONF_9);
+       }
+
+       return platform_driver_register(&uwire_driver);
+}
+
+static void __exit omap_uwire_exit(void)
+{
+       platform_driver_unregister(&uwire_driver);
+}
+
+subsys_initcall(omap_uwire_init);
+module_exit(omap_uwire_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/tsc2102.c b/drivers/spi/tsc2102.c
new file mode 100644 (file)
index 0000000..130b1c2
--- /dev/null
@@ -0,0 +1,1198 @@
+/*
+ * drivers/spi/tsc2102.c
+ *
+ * TSC2102 interface driver.
+ *
+ * Copyright (c) 2005 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This package 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 package 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 package; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/suspend.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc2102.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+
+#ifdef CONFIG_APM
+#include <asm/apm.h>
+#endif
+
+/* Bit field definitions for chip registers */
+#define TSC2102_ADC_TS_CONTROL         0x8bf4
+#define TSC2102_ADC_SCAN_CONTROL       0x2ff4
+#define TSC2102_ADC_T1_CONTROL         0x2bf4
+#define TSC2102_ADC_T2_CONTROL         0x33f4
+#define TSC2102_ADC_DAV                        0x4000
+#define TSC2102_ADC_INT_REF            0x0016
+#define TSC2102_ADC_EXT_REF            0x0002
+#define TSC2102_CONFIG_TIMES           0x0008
+#define TSC2102_RESET                  0xbb00
+#define TSC2102_ADC_PSTCM              (1 << 15)
+#define TSC2102_ADC_ADST               (1 << 14)
+#define TSC2102_TS_DAV                 0x0780
+#define TSC2102_PS_DAV                 0x0078
+#define TSC2102_T1_DAV                 0x0004
+#define TSC2102_T2_DAV                 0x0002
+#define TSC2102_DAC_ON                 0x3ba0
+#define TSC2102_DAC_OFF                        0xafa0
+#define TSC2102_FS44K                  (1 << 13)
+#define TSC2102_PLL1_OFF               0x0000
+#define TSC2102_PLL1_44K               0x811c
+#define TSC2102_PLL1_48K               0x8120
+#define TSC2102_PLL2_44K               (5462 << 2)
+#define TSC2102_PLL2_48K               (1920 << 2)
+#define TSC2102_SLVMS                  (1 << 11)
+#define TSC2102_DEEMPF                 (1 << 0)
+#define TSC2102_BASSBC                 (1 << 1)
+#define TSC2102_KEYCLICK_OFF           0x0000
+
+#define CS_CHANGE(val)                 0
+
+struct tsc2102_spi_req {
+       struct spi_device *dev;
+       uint16_t command;
+       uint16_t data;
+       struct spi_transfer *transfer;
+       struct spi_message message;
+};
+
+struct tsc2102_dev {
+       struct tsc2102_config *pdata;
+       spinlock_t lock, lock_sync;
+       struct clk *bclk_ck;
+
+       int state;                      /* 0: TS, 1: Portscan, 2-3: Temps */
+       struct timer_list ts_timer;     /* Busy-wait for PEN UP */
+       struct timer_list mode_timer;   /* Change .state every some time */
+       int pendown;
+       int data_pending;
+       uint16_t status, adc_status, adc_data[4];
+       tsc2102_touch_t touch_cb;
+       tsc2102_coords_t coords_cb;
+       tsc2102_ports_t ports_cb;
+       tsc2102_temp_t temp1_cb;
+       tsc2102_temp_t temp2_cb;
+       unsigned int ts_msecs;          /* Interval for .ts_timer */
+       unsigned int mode_msecs;        /* Interval for .mode_timer */
+
+       struct spi_device *spi;
+       struct spi_transfer *transfers;
+       struct tsc2102_spi_req req_adc;
+       struct tsc2102_spi_req req_status;
+       struct tsc2102_spi_req req_pressure;
+       struct tsc2102_spi_req req_stopadc;
+       struct tsc2102_spi_req req_mode;
+
+       int bat[2], aux[1], temp[2];
+       struct class_device *hwmondev;
+};
+
+static struct tsc2102_dev tsc;
+
+module_param_named(touch_check_msecs, tsc.ts_msecs, uint, 0);
+MODULE_PARM_DESC(touch_check_msecs, "Pen-up polling interval in msecs");
+
+module_param_named(sensor_scan_msecs, tsc.mode_msecs, uint, 0);
+MODULE_PARM_DESC(sensor_scan_msecs, "Temperature & battery scan interval");
+
+void tsc2102_write_sync(int page, u8 address, u16 data)
+{
+       static struct tsc2102_spi_req req;
+       static struct spi_transfer transfer[2];
+       int ret;
+
+       spi_message_init(&req.message);
+       req.transfer = transfer;
+
+       /* Address */
+       req.command = (page << 11) | (address << 5);
+       req.transfer[0].tx_buf = &req.command;
+       req.transfer[0].rx_buf = 0;
+       req.transfer[0].len = 2;
+       spi_message_add_tail(&req.transfer[0], &req.message);
+
+       /* Data */
+       req.transfer[1].tx_buf = &data;
+       req.transfer[1].rx_buf = 0;
+       req.transfer[1].len = 2;
+       req.transfer[1].cs_change = CS_CHANGE(1);
+       spi_message_add_tail(&req.transfer[1], &req.message);
+
+       ret = spi_sync(tsc.spi, &req.message);
+       if (!ret && req.message.status)
+               ret = req.message.status;
+
+       if (ret)
+               printk(KERN_ERR "%s: error %i in SPI request\n",
+                               __FUNCTION__, ret);
+}
+
+void tsc2102_reads_sync(int page, u8 startaddress, u16 *data, int numregs)
+{
+       static struct tsc2102_spi_req req;
+       static struct spi_transfer transfer[6];
+       int ret, i, j;
+
+       BUG_ON(numregs + 1 > ARRAY_SIZE(transfer));
+
+       spi_message_init(&req.message);
+       req.transfer = transfer;
+       i = 0;
+       j = 0;
+
+       /* Address */
+       req.command = 0x8000 | (page << 11) | (startaddress << 5);
+       req.transfer[i].tx_buf = &req.command;
+       req.transfer[i].rx_buf = 0;
+       req.transfer[i].len = 2;
+       spi_message_add_tail(&req.transfer[i ++], &req.message);
+
+       /* Data */
+       while (j < numregs) {
+               req.transfer[i].tx_buf = 0;
+               req.transfer[i].rx_buf = &data[j ++];
+               req.transfer[i].len = 2;
+               req.transfer[i].cs_change = CS_CHANGE(j == numregs);
+               spi_message_add_tail(&req.transfer[i ++], &req.message);
+       }
+
+       ret = spi_sync(tsc.spi, &req.message);
+       if (!ret && req.message.status)
+               ret = req.message.status;
+
+       if (ret)
+               printk(KERN_ERR "%s: error %i in SPI request\n",
+                               __FUNCTION__, ret);
+}
+
+u16 tsc2102_read_sync(int page, u8 address)
+{
+       u16 ret;
+       tsc2102_reads_sync(page, address, &ret, 1);
+       return ret;
+}
+
+static void tsc2102_write_async(
+               struct tsc2102_spi_req *spi, int page, u8 address, u16 data,
+               void (*complete)(struct tsc2102_dev *context))
+{
+       int ret;
+
+       spi_message_init(&spi->message);
+       spi->message.complete = (void (*)(void *)) complete;
+       spi->message.context = &tsc;
+
+       /* Address */
+       spi->command = (page << 11) | (address << 5);
+       spi->transfer[0].tx_buf = &spi->command;
+       spi->transfer[0].rx_buf = 0;
+       spi->transfer[0].len = 2;
+       spi_message_add_tail(&spi->transfer[0], &spi->message);
+
+       /* Data */
+       spi->data = data;
+       spi->transfer[1].tx_buf = &spi->data;
+       spi->transfer[1].rx_buf = 0;
+       spi->transfer[1].len = 2;
+       spi->transfer[1].cs_change = CS_CHANGE(1);
+       spi_message_add_tail(&spi->transfer[1], &spi->message);
+
+       ret = spi_async(spi->dev, &spi->message);
+       if (ret)
+               printk(KERN_ERR "%s: error %i in SPI request\n",
+                               __FUNCTION__, ret);
+}
+
+static void tsc2102_reads_async(struct tsc2102_spi_req *spi,
+               int page, u8 startaddress, u16 *data, int numregs,
+               void (*complete)(struct tsc2102_dev *context))
+{
+       int ret, i, j;
+
+       spi_message_init(&spi->message);
+       spi->message.complete = (void (*)(void *)) complete;
+       spi->message.context = &tsc;
+       i = 0;
+       j = 0;
+
+       /* Address */
+       spi->command = 0x8000 | (page << 11) | (startaddress << 5);
+       spi->transfer[i].tx_buf = &spi->command;
+       spi->transfer[i].rx_buf = 0;
+       spi->transfer[i].len = 2;
+       spi_message_add_tail(&spi->transfer[i ++], &spi->message);
+
+       /* Data */
+       while (j < numregs) {
+               spi->transfer[i].tx_buf = 0;
+               spi->transfer[i].rx_buf = &data[j ++];
+               spi->transfer[i].len = 2;
+               spi->transfer[i].cs_change = CS_CHANGE(j == numregs);
+               spi_message_add_tail(&spi->transfer[i ++], &spi->message);
+       }
+
+       ret = spi_async(spi->dev, &spi->message);
+       if (ret)
+               printk(KERN_ERR "%s: error %i in SPI request\n",
+                               __FUNCTION__, ret);
+}
+
+static void tsc2102_read_async(struct tsc2102_spi_req *spi,
+               int page, u8 address, u16 *ret,
+               void (*complete)(struct tsc2102_dev *context))
+{
+       tsc2102_reads_async(spi, page, address, ret, 1, complete);
+}
+
+static void tsc2102_request_alloc(struct tsc2102_dev *dev,
+               struct tsc2102_spi_req *spi, int direction, int numregs,
+               struct spi_transfer **buffer)
+{
+       spi->dev = dev->spi;
+
+       if (direction == 1)     /* Write */
+               numregs = 2;
+       else                    /* Read */
+               numregs += 1;
+
+       spi->transfer = *buffer;
+       *buffer += numregs;
+}
+
+#define tsc2102_cb_register_func(cb, cb_t)     \
+int tsc2102_ ## cb(cb_t handler)       \
+{      \
+       spin_lock(&tsc.lock);   \
+       \
+       /* Lock the module */   \
+       if (handler && !tsc.cb) \
+               if (!try_module_get(THIS_MODULE)) {     \
+                       printk(KERN_INFO "Failed to get TSC module\n"); \
+               }       \
+       if (!handler && tsc.cb) \
+               module_put(THIS_MODULE);        \
+       \
+       tsc.cb = handler;       \
+       \
+       spin_unlock(&tsc.lock); \
+       return 0;       \
+}
+
+tsc2102_cb_register_func(touch_cb, tsc2102_touch_t)
+tsc2102_cb_register_func(coords_cb, tsc2102_coords_t)
+tsc2102_cb_register_func(ports_cb, tsc2102_ports_t)
+tsc2102_cb_register_func(temp1_cb, tsc2102_temp_t)
+tsc2102_cb_register_func(temp2_cb, tsc2102_temp_t)
+
+#ifdef DEBUG
+static void tsc2102_print_dav(void)
+{
+       u16 status = tsc2102_read_sync(TSC2102_TS_STATUS_CTRL);
+       if (status & 0x0fff)
+               printk("TSC2102: data in");
+       if (status & 0x0400)
+               printk(" X");
+       if (status & 0x0200)
+               printk(" Y");
+       if (status & 0x0100)
+               printk(" Z1");
+       if (status & 0x0080)
+               printk(" Z2");
+       if (status & 0x0040)
+               printk(" BAT1");
+       if (status & 0x0020)
+               printk(" BAT2");
+       if (status & 0x0010)
+               printk(" AUX1");
+       if (status & 0x0008)
+               printk(" AUX2");
+       if (status & 0x0004)
+               printk(" TEMP1");
+       if (status & 0x0002)
+               printk(" TEMP2");
+       if (status & 0x0001)
+               printk(" KP");
+       if (status & 0x0fff)
+               printk(".\n");
+}
+#endif
+
+static void tsc2102_complete_dummy(struct tsc2102_dev *dev)
+{
+}
+
+static inline void tsc2102_touchscreen_mode(struct tsc2102_dev *dev)
+{
+       /* Scan X, Y, Z1, Z2, chip controlled, 12-bit, 16 samples, 500 usec */
+       tsc2102_write_async(&dev->req_mode,
+                       TSC2102_TS_ADC_CTRL, TSC2102_ADC_TS_CONTROL,
+                       tsc2102_complete_dummy);
+}
+
+static inline void tsc2102_portscan_mode(struct tsc2102_dev *dev)
+{
+       /* Scan BAT1, BAT2, AUX, 12-bit, 16 samples, 500 usec */
+       tsc2102_write_async(&dev->req_mode,
+                       TSC2102_TS_ADC_CTRL, TSC2102_ADC_SCAN_CONTROL,
+                       tsc2102_complete_dummy);
+}
+
+static inline void tsc2102_temp1_mode(struct tsc2102_dev *dev)
+{
+       /* Scan TEMP1, 12-bit, 16 samples, 500 usec */
+       tsc2102_write_async(&dev->req_mode,
+                       TSC2102_TS_ADC_CTRL, TSC2102_ADC_T1_CONTROL,
+                       tsc2102_complete_dummy);
+}
+
+static inline void tsc2102_temp2_mode(struct tsc2102_dev *dev)
+{
+       /* Scan TEMP2, 12-bit, 16 samples, 500 usec */
+       tsc2102_write_async(&dev->req_mode,
+                       TSC2102_TS_ADC_CTRL, TSC2102_ADC_T2_CONTROL,
+                       tsc2102_complete_dummy);
+}
+
+static void tsc2102_mode(struct tsc2102_dev *dev)
+{
+       switch (dev->state) {
+       case 0:
+               tsc2102_touchscreen_mode(dev);
+               break;
+       case 1:
+               tsc2102_portscan_mode(dev);
+               break;
+       case 2:
+               tsc2102_temp1_mode(dev);
+               break;
+       case 3:
+               tsc2102_temp2_mode(dev);
+               break;
+       default:
+               dev->state = 0;
+               tsc2102_touchscreen_mode(dev);
+               break;
+       }
+}
+
+/* Lock is held when this is called.  */
+static void tsc2102_new_mode(struct tsc2102_dev *dev)
+{
+       /* Abort current conversion if any */
+       tsc2102_write_async(&dev->req_stopadc,
+                       TSC2102_TS_ADC_CTRL, TSC2102_ADC_ADST,
+                       tsc2102_complete_dummy);
+
+       dev->state ++;
+       tsc2102_mode(dev);
+}
+
+static void tsc2102_check_status(struct tsc2102_dev *dev);
+
+/* TSC has new data for us availiable.  */
+static irqreturn_t tsc2102_handler(int irq, void *dev_id)
+{
+       struct tsc2102_dev *dev = (struct tsc2102_dev *) dev_id;
+       spin_lock_irq(&dev->lock);
+
+       if (!dev->data_pending)
+               tsc2102_check_status(dev);
+
+       dev->data_pending ++;
+
+       spin_unlock_irq(&dev->lock);
+       return IRQ_HANDLED;
+}
+
+static void tsc2102_data_report(struct tsc2102_dev *dev)
+{
+       if (dev->status & TSC2102_TS_DAV) {
+               if (dev->coords_cb)
+                       dev->coords_cb(
+                                       dev->adc_data[0], dev->adc_data[1],
+                                       dev->adc_data[2], dev->adc_data[3]);
+       }
+
+       if (dev->status & TSC2102_PS_DAV) {
+               if (dev->ports_cb)
+                       dev->ports_cb(dev->adc_data[0],
+                                       dev->adc_data[1], dev->adc_data[2]);
+               dev->bat[0] = dev->adc_data[0];
+               dev->bat[1] = dev->adc_data[1];
+               dev->aux[0] = dev->adc_data[2];
+       }
+
+       if (dev->status & TSC2102_T1_DAV) {
+               if (dev->temp1_cb)
+                       dev->temp1_cb(*dev->adc_data);
+               dev->temp[0] = *dev->adc_data;
+       }
+
+       if (dev->status & TSC2102_T2_DAV) {
+               if (dev->temp2_cb)
+                       dev->temp2_cb(*dev->adc_data);
+               dev->temp[1] = *dev->adc_data;
+       }
+
+       spin_lock_irq(&dev->lock);
+
+       dev->data_pending --;
+
+       /*
+        * This may happen if the registers were successfully read and a
+        * new conversion was started and completed by the TSC before the
+        * completion for SPI read was called.
+        */
+       if (dev->data_pending)
+               tsc2102_check_status(dev);
+
+       if (dev->status & (TSC2102_PS_DAV | TSC2102_T1_DAV | TSC2102_T2_DAV))
+               tsc2102_new_mode(dev);
+
+       spin_unlock_irq(&dev->lock);
+}
+
+static void tsc2102_status_report(struct tsc2102_dev *dev)
+{
+       /*
+        * Read all converted data from corresponding registers
+        * so that the ADC can move on to a new conversion.
+        */
+       if (dev->status & TSC2102_TS_DAV) {
+               tsc2102_reads_async(&dev->req_adc, TSC2102_TS_X,
+                               dev->adc_data, 4, tsc2102_data_report);
+               if (!dev->pendown) {
+                       dev->pendown = 1;
+                       if (dev->touch_cb)
+                               dev->touch_cb(1);
+
+                       mod_timer(&dev->ts_timer, jiffies +
+                               msecs_to_jiffies(dev->ts_msecs));
+               }
+       }
+
+       if (dev->status & TSC2102_PS_DAV) {
+               tsc2102_reads_async(&dev->req_adc, TSC2102_TS_BAT1,
+                               dev->adc_data, 3, tsc2102_data_report);
+       }
+
+       if (dev->status & TSC2102_T1_DAV) {
+               tsc2102_read_async(&dev->req_adc, TSC2102_TS_TEMP1,
+                               dev->adc_data, tsc2102_data_report);
+       }
+
+       if (dev->status & TSC2102_T2_DAV) {
+               tsc2102_read_async(&dev->req_adc, TSC2102_TS_TEMP2,
+                               dev->adc_data, tsc2102_data_report);
+       }
+
+       if (!(dev->status & (TSC2102_TS_DAV | TSC2102_PS_DAV |
+                                       TSC2102_T1_DAV | TSC2102_T2_DAV))) {
+               spin_lock_irq(&dev->lock);
+               dev->data_pending --;
+               spin_unlock_irq(&dev->lock);
+
+               WARN_ON(!dev->state);
+       }
+}
+
+static void tsc2102_check_status(struct tsc2102_dev *dev)
+{
+       tsc2102_read_async(&dev->req_status, TSC2102_TS_STATUS_CTRL,
+                       &dev->status, tsc2102_status_report);
+}
+
+static void tsc2102_mode_timer(unsigned long data)
+{
+       struct tsc2102_dev *dev = (struct tsc2102_dev *) data;
+       spin_lock_irq(&dev->lock);
+
+       BUG_ON(dev->state);
+
+       tsc2102_new_mode(dev);
+
+       mod_timer(&dev->mode_timer, jiffies +
+                       msecs_to_jiffies(dev->mode_msecs));
+       spin_unlock_irq(&dev->lock);
+}
+
+/*
+ * There are at least three ways to check for pen-up:
+ *     - the PINT/DAV pin state,
+ *     - reading PSTCM bit in ADC Control register (D15, offset 0x00),
+ *     - reading ADST bit in ADC Control register (D14, offset 0x00),
+ *             ADC idle would indicate no screen touch.
+ * Unfortunately none of them seems to be 100% accurate and you will
+ * find they are totally inconsistent, i.e. you get to see any arbitrary
+ * combination of values in these three bits.  So we will busy-wait
+ * for a moment when all three indicate a pen-up, using a timer, before
+ * we report a pen-up.
+ */
+static void tsc2102_pressure_report(struct tsc2102_dev *dev)
+{
+       if (!dev->pendown)
+               return;
+
+       if (dev->state ||
+                       (dev->adc_status & TSC2102_ADC_PSTCM) ||
+                       !(dev->adc_status & TSC2102_ADC_ADST)) {
+               mod_timer(&dev->ts_timer, jiffies +
+                               msecs_to_jiffies(dev->ts_msecs));
+       } else {
+               dev->pendown = 0;
+               if (dev->touch_cb)
+                       dev->touch_cb(0);
+       }
+}
+
+static void tsc2102_pressure(unsigned long data)
+{
+       struct tsc2102_dev *dev = (struct tsc2102_dev *) data;
+
+       BUG_ON(!dev->pendown);
+
+       tsc2102_read_async(&dev->req_pressure, TSC2102_TS_ADC_CTRL,
+                       &dev->adc_status, tsc2102_pressure_report);
+}
+
+#ifdef CONFIG_SOUND
+/*
+ * Volume level values should be in the range [0, 127].
+ * Higher values mean lower volume.
+ */
+void tsc2102_set_volume(uint8_t left_ch, uint8_t right_ch)
+{
+       u16 val;
+       if (left_ch == 0x00 || left_ch == 0x7f) /* All 0's or all 1's */
+               left_ch ^= 0x7f;
+       if (right_ch == 0x00 || right_ch == 0x7f)
+               right_ch ^= 0x7f;
+
+       spin_lock(&tsc.lock_sync);
+
+       val = tsc2102_read_sync(TSC2102_DAC_GAIN_CTRL);
+
+       val &= 0x8080;  /* Preserve mute-bits */
+       val |= (left_ch << 8) | right_ch;
+
+       tsc2102_write_sync(TSC2102_DAC_GAIN_CTRL, val);
+
+       spin_unlock(&tsc.lock_sync);
+}
+
+void tsc2102_set_mute(int left_ch, int right_ch)
+{
+       u16 val;
+       spin_lock(&tsc.lock_sync);
+
+       val = tsc2102_read_sync(TSC2102_DAC_GAIN_CTRL);
+
+       val &= 0x7f7f;  /* Preserve volume settings */
+       val |= (left_ch << 15) | (right_ch << 7);
+
+       tsc2102_write_sync(TSC2102_DAC_GAIN_CTRL, val);
+
+       spin_unlock(&tsc.lock_sync);
+}
+
+void tsc2102_get_mute(int *left_ch, int *right_ch)
+{
+       u16 val;
+       spin_lock(&tsc.lock_sync);
+
+       val = tsc2102_read_sync(TSC2102_DAC_GAIN_CTRL);
+
+       spin_unlock(&tsc.lock_sync);
+
+       *left_ch = !!(val & (1 << 15));
+       *right_ch = !!(val & (1 << 7));
+}
+
+void tsc2102_set_deemphasis(int enable)
+{
+       u16 val;
+       spin_lock(&tsc.lock_sync);
+       val = tsc2102_read_sync(TSC2102_DAC_POWER_CTRL);
+
+       if (enable)
+               val &= ~TSC2102_DEEMPF;
+       else
+               val |= TSC2102_DEEMPF;
+
+       tsc2102_write_sync(TSC2102_DAC_POWER_CTRL, val);
+       spin_unlock(&tsc.lock_sync);
+}
+
+void tsc2102_set_bassboost(int enable)
+{
+       u16 val;
+       spin_lock(&tsc.lock_sync);
+       val = tsc2102_read_sync(TSC2102_DAC_POWER_CTRL);
+
+       if (enable)
+               val &= ~TSC2102_BASSBC;
+       else
+               val |= TSC2102_BASSBC;
+
+       tsc2102_write_sync(TSC2102_DAC_POWER_CTRL, val);
+       spin_unlock(&tsc.lock_sync);
+}
+
+/*     {rate, dsor, fsref}     */
+static const struct tsc2102_rate_info_s tsc2102_rates[] = {
+       /* Fsref / 6.0 */
+       {7350,  63,     1},
+       {8000,  63,     0},
+       /* Fsref / 6.0 */
+       {7350,  54,     1},
+       {8000,  54,     0},
+       /* Fsref / 5.0 */
+       {8820,  45,     1},
+       {9600,  45,     0},
+       /* Fsref / 4.0 */
+       {11025, 36,     1},
+       {12000, 36,     0},
+       /* Fsref / 3.0 */
+       {14700, 27,     1},
+       {16000, 27,     0},
+       /* Fsref / 2.0 */
+       {22050, 18,     1},
+       {24000, 18,     0},
+       /* Fsref / 1.5 */
+       {29400, 9,      1},
+       {32000, 9,      0},
+       /* Fsref */
+       {44100, 0,      1},
+       {48000, 0,      0},
+
+       {0,     0,      0},
+};
+
+int tsc2102_set_rate(int rate)
+{
+       int i;
+       uint16_t val;
+
+       for (i = 0; tsc2102_rates[i].sample_rate; i ++)
+               if (tsc2102_rates[i].sample_rate == rate)
+                       break;
+       if (tsc2102_rates[i].sample_rate == 0) {
+               printk(KERN_ERR "Unknown sampling rate %i.0 Hz\n", rate);
+               return -EINVAL;
+       }
+
+       spin_lock(&tsc.lock_sync);
+
+       tsc2102_write_sync(TSC2102_AUDIO1_CTRL, tsc2102_rates[i].divisor);
+
+       val = tsc2102_read_sync(TSC2102_AUDIO3_CTRL);
+
+       if (tsc2102_rates[i].fs_44k) {
+               tsc2102_write_sync(TSC2102_AUDIO3_CTRL, val | TSC2102_FS44K);
+               /* Enable Phase-locked-loop, set up clock dividers */
+               tsc2102_write_sync(TSC2102_PLL1_CTRL, TSC2102_PLL1_44K);
+               tsc2102_write_sync(TSC2102_PLL2_CTRL, TSC2102_PLL2_44K);
+       } else {
+               tsc2102_write_sync(TSC2102_AUDIO3_CTRL, val & ~TSC2102_FS44K);
+               /* Enable Phase-locked-loop, set up clock dividers */
+               tsc2102_write_sync(TSC2102_PLL1_CTRL, TSC2102_PLL1_48K);
+               tsc2102_write_sync(TSC2102_PLL2_CTRL, TSC2102_PLL2_48K);
+       }
+
+       spin_unlock(&tsc.lock_sync);
+       return 0;
+}
+
+/*
+ * Perform basic set-up with default values and power the DAC on.
+ */
+void tsc2102_dac_power(int state)
+{
+       spin_lock(&tsc.lock_sync);
+
+       if (state) {
+               /* 16-bit words, DSP mode, sample at Fsref */
+               tsc2102_write_sync(TSC2102_AUDIO1_CTRL, 0x0100);
+               /* Keyclicks off, soft-stepping at normal rate */
+               tsc2102_write_sync(TSC2102_AUDIO2_CTRL, TSC2102_KEYCLICK_OFF);
+               /* 44.1 kHz Fsref, continuous transfer mode, master DAC */
+               tsc2102_write_sync(TSC2102_AUDIO3_CTRL, 0x2800);
+               /* Soft-stepping enabled */
+               tsc2102_write_sync(TSC2102_AUDIO4_CTRL, 0x0000);
+
+               /* PLL generates 44.1 kHz */
+               tsc2102_write_sync(TSC2102_PLL1_CTRL, TSC2102_PLL1_44K);
+               tsc2102_write_sync(TSC2102_PLL2_CTRL, TSC2102_PLL2_44K);
+
+               /* Codec & DAC power up, virtual ground disabled */
+               tsc2102_write_sync(TSC2102_DAC_POWER_CTRL, TSC2102_DAC_ON);
+       } else {
+               /* All off */
+               tsc2102_write_sync(TSC2102_AUDIO4_CTRL, TSC2102_KEYCLICK_OFF);
+               tsc2102_write_sync(TSC2102_PLL1_CTRL, TSC2102_PLL1_OFF);
+       }
+
+       spin_unlock(&tsc.lock_sync);
+}
+
+void tsc2102_set_i2s_master(int state)
+{
+       uint16_t val;
+       spin_lock(&tsc.lock_sync);
+
+       val = tsc2102_read_sync(TSC2102_AUDIO3_CTRL);
+
+       if (state)
+               tsc2102_write_sync(TSC2102_AUDIO3_CTRL, val | TSC2102_SLVMS);
+       else
+               tsc2102_write_sync(TSC2102_AUDIO3_CTRL, val & ~TSC2102_SLVMS);
+
+       spin_unlock(&tsc.lock_sync);
+}
+#endif /* CONFIG_SOUND */
+
+static int tsc2102_configure(struct tsc2102_dev *dev)
+{
+       /* Reset the chip */
+       tsc2102_write_sync(TSC2102_TS_RESET_CTRL, TSC2102_RESET);
+
+       /* Reference mode, 100 usec delay, 1.25 V reference */
+       if (dev->pdata->use_internal)
+               tsc2102_write_sync(TSC2102_TS_REF_CTRL, TSC2102_ADC_INT_REF);
+       else
+               tsc2102_write_sync(TSC2102_TS_REF_CTRL, TSC2102_ADC_EXT_REF);
+
+       /* 84 usec precharge time, 32 usec sense time */
+       tsc2102_write_sync(TSC2102_TS_CONFIG_CTRL, TSC2102_CONFIG_TIMES);
+
+       /* PINT/DAV acts as DAV */
+       tsc2102_write_sync(TSC2102_TS_STATUS_CTRL, TSC2102_ADC_DAV);
+
+       tsc2102_mode(dev);
+       mod_timer(&dev->mode_timer, jiffies +
+                       msecs_to_jiffies(dev->mode_msecs));
+       return 0;
+}
+
+/*
+ * Retrieves chip revision.  Should be always 1.
+ */
+int tsc2102_get_revision(void)
+{
+       return tsc2102_read_sync(TSC2102_AUDIO3_CTRL) & 7;
+}
+
+/*
+ * Emit a short keyclick typically in order to give feedback to
+ * user on specific events.
+ *
+ * amplitude must be between 0 (lowest) and 2 (highest).
+ * freq must be between 0 (corresponds to 62.5 Hz) and 7 (8 kHz).
+ * length should be between 2 and 32 periods.
+ *
+ * This function sleeps but doesn't sleep until the sound has
+ * finished.
+ */
+void tsc2102_keyclick(int amplitude, int freq, int length)
+{
+       u16 val;
+       spin_lock(&tsc.lock_sync);
+       val = tsc2102_read_sync(TSC2102_AUDIO2_CTRL);
+       val &= 0x800f;
+
+       /* Set amplitude */
+       switch (amplitude) {
+       case 1:
+               val |= 4 << 12;
+               break;
+       case 2:
+               val |= 7 << 12;
+               break;
+       default:
+               break;
+       }
+
+       /* Frequency */
+       val |= (freq & 0x7) << 8;
+
+       /* Round to nearest supported length */
+       if (length > 20)
+               val |= 4 << 4;
+       else if (length > 6)
+               val |= 3 << 4;
+       else if (length > 4)
+               val |= 2 << 4;
+       else if (length > 2)
+               val |= 1 << 4;
+
+       /* Enable keyclick */
+       val |= 0x8000;
+
+       tsc2102_write_sync(TSC2102_AUDIO2_CTRL, val);
+       spin_unlock(&tsc.lock_sync);
+}
+
+#ifdef CONFIG_HWMON
+#define TSC2102_INPUT(devname, field)  \
+static ssize_t show_ ## devname(struct device *dev,    \
+               struct device_attribute *devattr, char *buf)    \
+{      \
+       struct tsc2102_dev *devhwmon = dev_get_drvdata(dev);    \
+       int value = devhwmon->field;    \
+       return sprintf(buf, "%i\n", value);     \
+}      \
+static DEVICE_ATTR(devname ## _input, S_IRUGO, show_ ## devname, NULL);
+
+TSC2102_INPUT(in0, bat[0])
+TSC2102_INPUT(in1, bat[1])
+TSC2102_INPUT(in2, aux[0])
+TSC2102_INPUT(in3, temp[0])
+TSC2102_INPUT(in4, temp[1])
+
+static ssize_t show_temp1(struct device *dev,
+               struct device_attribute *devattr, char *buf)
+{
+       struct tsc2102_dev *devhwmon = dev_get_drvdata(dev);
+       int t1, t2;
+       int value, diff;
+
+       t1 = devhwmon->temp[0];
+       t2 = devhwmon->temp[1];
+
+       /*
+        * Use method #2 (differential) to calculate current temperature.
+        * The difference between TEMP2 and TEMP1 input values is
+        * multiplied by a constant to obtain current temperature.
+        * To find this constant we use the values measured at 25 C as
+        * thermometer calibration data.
+        *
+        * 298150 is 25 degrees Celcius represented in Kelvins and
+        * multiplied by 1000 for fixed point precision (273.15 + 25).
+        * 273150 is zero degrees Celcius.
+        */
+       diff = devhwmon->pdata->temp_at25c[1] - devhwmon->pdata->temp_at25c[0];
+       BUG_ON(diff == 0);
+       value = (t2 - t1) * 298150 / diff;      /* This is in Kelvins now */
+
+       t1 = value - 273150;                    /* Celcius millidegree */
+       return sprintf(buf, "%i\n", t1);
+}
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1, NULL);
+#endif /* CONFIG_HWMON */
+
+#ifdef CONFIG_APM
+static void tsc2102_get_power_status(struct apm_power_info *info)
+{
+       tsc.pdata->apm_report(info, tsc.bat);
+}
+#endif
+
+#ifdef CONFIG_PM
+/*
+ * Suspend the chip.
+ */
+static int
+tsc2102_suspend(struct spi_device *spi, pm_message_t state)
+{
+       struct tsc2102_dev *dev = dev_get_drvdata(&spi->dev);
+
+       if (!dev)
+               return 0;
+
+       spin_lock(&dev->lock_sync);
+
+       del_timer(&dev->mode_timer);
+       del_timer(&dev->ts_timer);
+
+       if (dev->pendown && dev->touch_cb)
+               dev->touch_cb(0);
+
+       /* Abort current conversion and power down the ADC */
+       tsc2102_write_sync(TSC2102_TS_ADC_CTRL, TSC2102_ADC_ADST);
+
+       dev->spi->dev.power.power_state = state;
+
+       spin_unlock(&dev->lock_sync);
+       return 0;
+}
+
+/*
+ * Resume chip operation.
+ */
+static int tsc2102_resume(struct spi_device *spi)
+{
+       struct tsc2102_dev *dev = dev_get_drvdata(&spi->dev);
+       int err;
+
+       if (!dev)
+               return 0;
+
+       spin_lock(&dev->lock_sync);
+
+       dev->spi->dev.power.power_state = PMSG_ON;
+
+       dev->state = 0;
+       dev->pendown = 0;
+
+       err = tsc2102_configure(dev);
+
+       spin_unlock(&dev->lock_sync);
+       return err;
+}
+#else
+#define tsc2102_suspend        NULL
+#define tsc2102_resume NULL
+#endif
+
+static struct platform_device tsc2102_ts_device = {
+       .name           = "tsc2102-ts",
+       .id             = -1,
+};
+
+static struct platform_device tsc2102_alsa_device = {
+       .name           = "tsc2102-alsa",
+       .id             = -1,
+};
+
+static int tsc2102_probe(struct spi_device *spi)
+{
+       struct tsc2102_config *pdata = spi->dev.platform_data;
+       struct spi_transfer *spi_buffer;
+       int err = 0;
+
+       if (!pdata) {
+               printk(KERN_ERR "TSC2102: Platform data not supplied\n");
+               return -ENOENT;
+       }
+
+       if (!spi->irq) {
+               printk(KERN_ERR "TSC2102: Invalid irq value\n");
+               return -ENOENT;
+       }
+
+       tsc.pdata = pdata;
+       tsc.state = 0;
+       tsc.pendown = 0;
+       tsc.data_pending = 0;
+       tsc.ts_msecs = 20;
+       tsc.mode_msecs = 1000;
+       tsc.spi = spi;
+
+       /* Allocate enough struct spi_transfer's for all requests */
+       spi_buffer = kzalloc(sizeof(struct spi_transfer) * 16, GFP_KERNEL);
+       if (!spi_buffer) {
+               printk(KERN_ERR "TSC2102: No memory for SPI buffers\n");
+               return -ENOMEM;
+       }
+
+       tsc.transfers = spi_buffer;
+       tsc2102_request_alloc(&tsc, &tsc.req_adc, 0, 4, &spi_buffer);
+       tsc2102_request_alloc(&tsc, &tsc.req_status, 0, 1, &spi_buffer);
+       tsc2102_request_alloc(&tsc, &tsc.req_pressure, 0, 1, &spi_buffer);
+       tsc2102_request_alloc(&tsc, &tsc.req_stopadc, 1, 1, &spi_buffer);
+       tsc2102_request_alloc(&tsc, &tsc.req_mode, 1, 1, &spi_buffer);
+
+       spin_lock_init(&tsc.lock);
+       spin_lock(&tsc.lock_sync);
+
+       /* Get the BCLK - assuming the rate is at 12000000 */
+       tsc.bclk_ck = clk_get(0, "bclk");
+       if (!tsc.bclk_ck) {
+               printk(KERN_ERR "Unable to get the clock BCLK\n");
+               err = -EPERM;
+               goto done;
+       }
+
+       clk_enable(tsc.bclk_ck);
+
+       if (request_irq(spi->irq, tsc2102_handler, IRQF_SAMPLE_RANDOM |
+                               IRQF_TRIGGER_FALLING, "tsc2102", &tsc)) {
+               printk(KERN_ERR "Could not allocate touchscreen IRQ!\n");
+               err = -EINVAL;
+               goto err_clk;
+       }
+
+       setup_timer(&tsc.ts_timer,
+                       tsc2102_pressure, (unsigned long) &tsc);
+       setup_timer(&tsc.mode_timer,
+                       tsc2102_mode_timer, (unsigned long) &tsc);
+
+       /* Set up the communication bus */
+       dev_set_drvdata(&spi->dev, &tsc);
+       spi->dev.power.power_state = PMSG_ON;
+       spi->mode = SPI_MODE_1;
+       spi->bits_per_word = 16;
+       err = spi_setup(spi);
+       if (err)
+               goto err_timer;
+
+       /* Now try to detect the chip, make first contact */
+       if (tsc2102_get_revision() != 0x1) {
+               printk(KERN_ERR "No TI TSC2102 chip found!\n");
+               goto err_timer;
+       }
+
+       err = tsc2102_configure(&tsc);
+       if (err)
+               goto err_timer;
+
+       /* Register devices controlled by TSC 2102 */
+       tsc2102_ts_device.dev.platform_data = pdata;
+       tsc2102_ts_device.dev.parent = &spi->dev;
+       err = platform_device_register(&tsc2102_ts_device);
+       if (err)
+               goto err_timer;
+
+       tsc2102_alsa_device.dev.platform_data = pdata->alsa_config;
+       tsc2102_alsa_device.dev.parent = &spi->dev;
+       err = platform_device_register(&tsc2102_alsa_device);
+       if (err)
+               goto err_ts;
+
+#ifdef CONFIG_HWMON
+       tsc.hwmondev = hwmon_device_register(&spi->dev);
+       if (IS_ERR(tsc.hwmondev)) {
+               printk(KERN_ERR "tsc2102_hwmon: Device registration failed\n");
+               err = PTR_ERR(tsc.hwmondev);
+               goto err_alsa;
+       }
+
+       if (pdata->monitor & TSC_BAT1)
+               err |= device_create_file(&spi->dev, &dev_attr_in0_input);
+       if (pdata->monitor & TSC_BAT2)
+               err |= device_create_file(&spi->dev, &dev_attr_in1_input);
+       if (pdata->monitor & TSC_AUX)
+               err |= device_create_file(&spi->dev, &dev_attr_in2_input);
+       if (pdata->monitor & TSC_TEMP) {
+               err |= device_create_file(&spi->dev, &dev_attr_temp1_input);
+               err |= device_create_file(&spi->dev, &dev_attr_in3_input);
+               err |= device_create_file(&spi->dev, &dev_attr_in4_input);
+       }
+
+       if (err)
+               printk(KERN_ERR "tsc2102_hwmon: Creating one or more "
+                               "attribute files failed\n");
+       err = 0;        /* Not fatal */
+#endif
+
+#ifdef CONFIG_APM
+       if (pdata->apm_report)
+               apm_get_power_status = tsc2102_get_power_status;
+#endif
+
+       if (!err)
+               goto done;
+
+err_alsa:
+       platform_device_unregister(&tsc2102_alsa_device);
+err_ts:
+       platform_device_unregister(&tsc2102_ts_device);
+err_timer:
+       del_timer(&tsc.ts_timer);
+       del_timer(&tsc.mode_timer);
+       dev_set_drvdata(&spi->dev, NULL);
+err_clk:
+       clk_disable(tsc.bclk_ck);
+       clk_put(tsc.bclk_ck);
+done:
+       spin_unlock(&tsc.lock_sync);
+       return err;
+}
+
+static int tsc2102_remove(struct spi_device *spi)
+{
+       struct tsc2102_dev *dev = dev_get_drvdata(&spi->dev);
+
+       spin_lock(&dev->lock_sync);
+
+       platform_device_unregister(&tsc2102_ts_device);
+       platform_device_unregister(&tsc2102_alsa_device);
+
+       dev_set_drvdata(&spi->dev, NULL);
+
+       /* Release the BCLK */
+       clk_disable(dev->bclk_ck);
+       clk_put(dev->bclk_ck);
+
+       del_timer(&tsc.mode_timer);
+       del_timer(&tsc.ts_timer);
+
+       kfree(tsc.transfers);
+
+#ifdef CONFIG_HWMON
+       hwmon_device_unregister(dev->hwmondev);
+#endif
+
+#ifdef CONFIG_APM
+       apm_get_power_status = 0;
+#endif
+
+       spin_unlock(&dev->lock_sync);
+
+       return 0;
+}
+
+static struct spi_driver tsc2102_driver = {
+       .probe          = tsc2102_probe,
+       .remove         = tsc2102_remove,
+       .suspend        = tsc2102_suspend,
+       .resume         = tsc2102_resume,
+       .driver         = {
+               .name   = "tsc2102",
+               .owner  = THIS_MODULE,
+               .bus    = &spi_bus_type,
+       },
+};
+
+static char __initdata banner[] = KERN_INFO "TI TSC2102 driver initializing\n";
+
+static int __init tsc2102_init(void)
+{
+       printk(banner);
+       return spi_register_driver(&tsc2102_driver);
+}
+
+static void __exit tsc2102_exit(void)
+{
+       spi_unregister_driver(&tsc2102_driver);
+}
+
+module_init(tsc2102_init);
+module_exit(tsc2102_exit);
+
+EXPORT_SYMBOL(tsc2102_read_sync);
+EXPORT_SYMBOL(tsc2102_reads_sync);
+EXPORT_SYMBOL(tsc2102_write_sync);
+EXPORT_SYMBOL(tsc2102_keyclick);
+
+MODULE_AUTHOR("Andrzej Zaborowski");
+MODULE_DESCRIPTION("Interface driver for TI TSC2102 chips.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ssi/Kconfig b/drivers/ssi/Kconfig
new file mode 100644 (file)
index 0000000..e84f9d2
--- /dev/null
@@ -0,0 +1,18 @@
+menu "Synchronous Serial Interfaces (SSI)"
+
+config OMAP_UWIRE
+       depends on ARCH_OMAP1
+       tristate "MicroWire support on OMAP"
+       ---help---
+         Say Y here if you want support for the MicroWire interface
+         on an OMAP processor.
+
+config OMAP_TSC2101
+       depends on ARCH_OMAP1 || ARCH_OMAP24XX
+       tristate "TSC2101 codec support for Touchscreen and audio"
+       select OMAP_UWIRE if MACH_OMAP_H3 || MACH_OMAP_H2
+       select GPIOEXPANDER_OMAP if MACH_OMAP_H3
+       ---help---
+         Say Y here if you want support for the TSC2101 codec.  It is
+         needed for touchscreen and audio on OMAP1610 and 1710.
+endmenu
diff --git a/drivers/ssi/Makefile b/drivers/ssi/Makefile
new file mode 100644 (file)
index 0000000..c63cf2b
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# Makefile for the SSI drivers
+#
+
+obj-$(CONFIG_OMAP_UWIRE)        += omap-uwire.o
+obj-$(CONFIG_OMAP_TSC2101)      += omap-tsc2101.o
diff --git a/drivers/ssi/omap-tsc2101.c b/drivers/ssi/omap-tsc2101.c
new file mode 100644 (file)
index 0000000..5dfe994
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * linux/drivers/ssi/omap-tsc2101.c
+ *
+ * TSC2101 codec interface driver for the OMAP platform
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * This package 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.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ * 2004/11/07   Nishanth Menon - Modified for common hooks for Audio and Touchscreen
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+
+#include <asm/arch/mux.h>
+#include <asm/arch/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/hardware/tsc2101.h>
+#include <asm/arch/gpioexpander.h>
+
+#include "omap-tsc2101.h"
+
+#if CONFIG_ARCH_OMAP16XX
+#include <../drivers/ssi/omap-uwire.h>
+#else
+#error "Unsupported configuration"
+#endif
+
+#define SPIO 1
+
+static int count;
+static spinlock_t tsc2101_lock = SPIN_LOCK_UNLOCKED;
+static struct clk  * tsc2101_mclk_ck;
+
+static int omap_tsc2101_configure(void);
+
+/* FIXME: add driver model usage to powerdown the tsc2101 on suspend */
+/* Clock  -Hard coding for the time being */
+#define CLK_SOFT_REQ_REG_BASE  (0xFFFE0800+0x34)
+#define SOFT_COM_MCK0_REQ_MASK (0x1<<6)
+
+int omap_tsc2101_enable(void)
+{
+       int ret = 0;
+
+       spin_lock(&tsc2101_lock);
+       if (count++ == 0) {
+               int ret = 0;
+               /* set the Mux to provide MCLK to TSC2101 */
+               if (machine_is_omap_h3()) {
+                       ret = omap_cfg_reg(V5_1710_MCLK_ON);
+               } else {
+                       if (machine_is_omap_h2()) {
+                               ret = omap_cfg_reg(R10_1610_MCLK_ON);
+                       }
+               }
+
+               /* Get the MCLK */
+               tsc2101_mclk_ck = clk_get(NULL, "mclk");
+               if (NULL == tsc2101_mclk_ck) {
+                       printk(KERN_ERR "Unable to get the clock MCLK!!!\n");;
+                       ret = -EPERM;
+                       goto done;
+               }
+               if (clk_set_rate(tsc2101_mclk_ck, 12000000)) {
+                       printk(KERN_ERR "Unable to set rate to the MCLK!!!\n");;
+                       ret = -EPERM;
+                       goto done;
+               }
+               clk_enable(tsc2101_mclk_ck);
+
+               ret = omap_tsc2101_configure();
+
+               /* Lock the module */
+               if (!ret && !try_module_get(THIS_MODULE)) {
+                       printk(KERN_CRIT "Failed to get TSC module\n");
+                       ret = -ESTALE;
+               }
+       }
+
+done:
+       spin_unlock(&tsc2101_lock);
+       return ret;
+}
+
+void omap_tsc2101_disable(void)
+{
+       spin_lock(&tsc2101_lock);
+       if (--count == 0) {
+               int ret = 0;
+               /* Remove the Mux to Stop MCLK to TSC2101 */
+               if (machine_is_omap_h3()) {
+                       ret = omap_cfg_reg(V5_1710_MCLK_OFF);
+               } else {
+                       if (machine_is_omap_h2()) {
+                               ret = omap_cfg_reg(R10_1610_MCLK_OFF);
+                       }
+               }
+
+               /* Release the MCLK */
+               clk_disable(tsc2101_mclk_ck);
+               clk_put(tsc2101_mclk_ck);
+               tsc2101_mclk_ck = NULL;
+
+               module_put(THIS_MODULE);
+       }
+       spin_unlock(&tsc2101_lock);
+}
+
+void omap_tsc2101_write(int page, u8 address, u16 data)
+{
+
+       int ret = 0;
+
+       if (machine_is_omap_h2()) {
+               ret =
+                   omap_uwire_data_transfer(1, 
+                                            (((page) << 11) | (address << 5)),
+                                            16, 0, NULL, 1);
+               if (ret) {
+                       printk(KERN_ERR
+                              "uwire-write returned error for address %x\n",
+                              address);
+                       return;
+               }
+               ret = omap_uwire_data_transfer(1, data, 16, 0, NULL, 0);
+               if (ret) {
+                       printk(KERN_ERR
+                              "uwire-write returned error for address %x\n",
+                              address);
+                       return;
+               }
+       }
+       if (machine_is_omap_h3()) {
+
+               ret =
+                   omap_uwire_data_transfer(0, ((page << 11) | (address << 5)),
+                                            16, 0, NULL, 1);
+               if (ret) {
+                       printk(KERN_ERR
+                              "uwire-write returned error for address %x\n",
+                              address);
+                       return;
+               }
+               ret = omap_uwire_data_transfer(0, data, 16, 0, NULL, 0);
+               if (ret) {
+                       printk(KERN_ERR
+                              "uwire-write returned error for address %x\n",
+                              address);
+                       return;
+               }
+       }
+
+}
+
+void omap_tsc2101_reads(int page, u8 startaddress, u16 * data, int numregs)
+{
+       int cs = 0, i;
+       if (machine_is_omap_h2()) {
+               cs = 1;
+       }
+       if (machine_is_omap_h3()) {
+               cs = 0;
+       }
+       (void)omap_uwire_data_transfer(cs, (0x8000 | (page << 11)
+                                           | (startaddress << 5)),
+                                      16, 0, NULL, 1);
+       for (i = 0; i < (numregs - 1); i++, data++) {
+               omap_uwire_data_transfer(cs, 0, 0, 16, data, 1);
+       }
+       omap_uwire_data_transfer(cs, 0, 0, 16, data, 0);
+}
+
+u16 omap_tsc2101_read(int page, u8 address)
+{
+       u16 ret;
+       omap_tsc2101_reads(page, address, &ret, 1);
+       return ret;
+}
+
+/* FIXME: adapt clock divisors for uwire to current ARM xor clock rate */
+static int omap_tsc2101_configure(void)
+{
+       unsigned long uwire_flags = 0;
+
+#ifdef CONFIG_MACH_OMAP_H3
+       int err = 0;
+       u8 ioExpanderVal = 0;
+
+       if ((err = read_gpio_expa(&ioExpanderVal, 0x24))) {
+               printk(" Error reading from I/O EXPANDER \n");
+               return err;
+       }
+       ioExpanderVal |= 0x8;
+
+       if ((err = write_gpio_expa(ioExpanderVal, 0x24))) {
+               printk(KERN_ERR ": Error writing to I/O EXPANDER \n");
+               return err;
+       }
+#endif
+
+       if (machine_is_omap_h2()) {
+               uwire_flags = UWIRE_READ_RISING_EDGE | UWIRE_WRITE_RISING_EDGE;
+               omap_cfg_reg(N15_1610_UWIRE_CS1);
+               omap_uwire_configure_mode(1, uwire_flags);
+       }
+       if (machine_is_omap_h3()) {
+               uwire_flags = UWIRE_READ_RISING_EDGE | UWIRE_WRITE_RISING_EDGE;
+               omap_cfg_reg(N14_1610_UWIRE_CS0);
+               omap_uwire_configure_mode(0, uwire_flags);
+       }
+
+       /* Configure MCLK enable */
+       omap_writel(omap_readl(PU_PD_SEL_2) | (1 << 22), PU_PD_SEL_2);  
+
+       return 0;
+}
+
+EXPORT_SYMBOL(omap_tsc2101_enable);
+EXPORT_SYMBOL(omap_tsc2101_read);
+EXPORT_SYMBOL(omap_tsc2101_reads);
+EXPORT_SYMBOL(omap_tsc2101_write);
+EXPORT_SYMBOL(omap_tsc2101_disable);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION
+    ("Glue audio driver for the TI OMAP1610/OMAP1710 TSC2101 codec.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ssi/omap-tsc2101.h b/drivers/ssi/omap-tsc2101.h
new file mode 100644 (file)
index 0000000..f6b40b8
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * linux/drivers/ssi/omap-tsc2101.h
+ *
+ * TSC2101 codec interface driver for the OMAP platform
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * This package 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.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ * 2004/11/07   Nishanth Menon - Provided common hooks for Audio and Touchscreen
+ */
+
+#ifndef __OMAP_TSC2101_H
+#define __OMAP_TSC2101_H
+
+extern u16 omap_tsc2101_read(int page, u8 address);
+extern void omap_tsc2101_reads(int page, u8 startaddress, u16 * data,
+                              int numregs);
+extern void omap_tsc2101_write(int page, u8 address, u16 data);
+
+extern void omap_tsc2101_disable(void);
+extern int omap_tsc2101_enable(void);
+
+#endif
diff --git a/drivers/ssi/omap-uwire.c b/drivers/ssi/omap-uwire.c
new file mode 100644 (file)
index 0000000..61b3ca1
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ *
+ *     uWire interface driver for the OMAP Platform
+ *
+ * Copyright 2003 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *        source@mvista.com
+ *
+ * Ported to 2.6 uwire interface.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * Generalization patches by Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ *  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  SOFTWARE  IS PROVIDED          ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,          INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED          TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN         CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/omap730.h>  /* OMAP730_IO_CONF registers */
+
+#include "omap-uwire.h"
+
+/* uWire Registers: */
+#define UWIRE_BASE    0xFFFB3000
+#define UWIRE_IO_SIZE 0x20
+#define UWIRE_TDR     0x00
+#define UWIRE_RDR     0x00
+#define UWIRE_CSR     0x01
+#define UWIRE_SR1     0x02
+#define UWIRE_SR2     0x03
+#define UWIRE_SR3     0x04
+#define UWIRE_SR4     0x05
+#define UWIRE_SR5     0x06
+
+static unsigned short uwire_flags[4];
+static unsigned long uwire_base = io_p2v(UWIRE_BASE);
+static spinlock_t uwire_lock;
+static unsigned int uwire_idx_shift;
+
+static inline void uwire_write_reg(int idx, u16 val)
+{
+       __raw_writew(val, uwire_base + (idx << uwire_idx_shift));
+}
+
+static inline u16 uwire_read_reg(int idx)
+{
+       return __raw_readw(uwire_base + (idx << uwire_idx_shift));
+}
+
+void omap_uwire_configure_mode(int cs, unsigned long flags)
+{
+       u16 w, val = 0;
+       int shift, reg;
+
+       BUG_ON(cs > 3);
+
+       val = flags & 0x3f;
+       if (flags & UWIRE_CLK_INVERTED)
+               val ^= 0x03;
+       if (cs & 1)
+               shift = 6;
+       else
+               shift = 0;
+       if (cs <= 1)
+               reg = UWIRE_SR1;
+       else
+               reg = UWIRE_SR2;
+       spin_lock(&uwire_lock);
+       w = uwire_read_reg(reg);
+       w &= ~(0x3f << shift);
+       w |= val << shift;
+       uwire_write_reg(reg, w);
+       spin_unlock(&uwire_lock);
+
+       uwire_flags[cs] = flags;
+}
+
+static int wait_uwire_csr_flag(u16 mask, u16 val, int might_not_catch)
+{
+       u16 w;
+       int c = 0;
+       unsigned long max_jiffies = jiffies + HZ;
+
+       for (;;) {
+               w = uwire_read_reg(UWIRE_CSR);
+               if ((w & mask) == val)
+                       break;
+               if (time_after(jiffies, max_jiffies)) {
+                       printk(KERN_ERR "%s: timeout. reg=%#06x mask=%#06x val=%#06x\n",
+                              __FUNCTION__, w, mask, val);
+                       return -1;
+               }
+               c++;
+               if (might_not_catch && c > 64)
+                       break;
+       }
+       return 0;
+}
+
+int omap_uwire_data_transfer(int cs, u16 tx_data, int tx_size, int rx_size,
+                            u16 *rx_buf, int leave_cs_active)
+{
+       u16 ret = -1, w;
+       u16 mask;
+
+       BUG_ON(cs > 3);
+       BUG_ON(rx_size && !rx_buf);
+
+       spin_lock(&uwire_lock);
+
+       if (wait_uwire_csr_flag(1 << 14, 0, 0))
+               goto exit;
+
+       if (uwire_flags[cs] & UWIRE_CLK_INVERTED)
+               uwire_write_reg(UWIRE_SR4, 1);
+       else
+               uwire_write_reg(UWIRE_SR4, 0);
+
+       w = cs << 10;
+       w |= 1 << 12;                           /* CS_CMD : activate CS */
+       uwire_write_reg(UWIRE_CSR, w);
+
+       /* Shift data to 16bit MSb and place it in TX register. */
+       uwire_write_reg(UWIRE_TDR, tx_data << (16 - tx_size));
+
+       if (wait_uwire_csr_flag(1 << 14, 0, 0))
+               goto exit;
+
+       w = rx_size | (tx_size << 5) | (cs << 10);
+       w |= (1 << 12) | (1 << 13);
+       /* Start uWire read/write */
+       uwire_write_reg(UWIRE_CSR, w);
+
+       /* Wait till read/write actually starts.
+        * This is needed at high (>=60MHz) MPU frequencies
+        * REVISIT: But occasionally we won't have time to catch it
+        */
+       if (wait_uwire_csr_flag(1 << 14, 1 << 14, 1))
+               goto exit;
+
+       /* Wait for both transfers to be completed */
+       mask = 1 << 14;                 /* CSRB : reg busy */
+       w = 0;
+       if (rx_size) {
+               mask |= 1 << 15;        /* RDRB : reg busy */
+               w |= 1 << 15;
+       }
+
+       if (wait_uwire_csr_flag(mask, w, 0))
+               goto exit;
+
+       if (rx_size)
+               *rx_buf = uwire_read_reg(UWIRE_RDR);
+
+       if (!leave_cs_active)
+               uwire_write_reg(UWIRE_CSR, cs << 10);
+
+       ret = 0;
+
+exit:
+       spin_unlock(&uwire_lock);
+       return ret;
+}
+
+static int __init omap_uwire_init(void)
+{
+       spin_lock_init(&uwire_lock);
+       if (cpu_is_omap730())
+               uwire_idx_shift = 1;
+       else
+               uwire_idx_shift = 2;
+
+       uwire_write_reg(UWIRE_SR3, 1);
+       if (machine_is_omap_h2()) {
+               /* defaults: W21 SDO, U18 SDI, V19 SCL */
+               omap_cfg_reg(N14_1610_UWIRE_CS0);
+               omap_cfg_reg(N15_1610_UWIRE_CS1);
+       }
+       if (machine_is_omap_osk()) {
+               /* this is the standard expansion connector usage, with
+                * the other chipselect pins for MPUIO2 and MPUIO4.
+                */
+               omap_cfg_reg(N14_1610_UWIRE_CS0);
+               omap_cfg_reg(P15_1610_UWIRE_CS3);
+       }
+       if (machine_is_omap_perseus2()) {
+               /* configure pins: MPU_UW_nSCS1, MPU_UW_SDO, MPU_UW_SCLK */
+               int val = omap_readl(OMAP730_IO_CONF_9) & ~0x00EEE000;
+               omap_writel(val | 0x00AAA000, OMAP730_IO_CONF_9);
+       }
+       return 0;
+}
+
+static void __exit omap_uwire_exit(void)
+{
+}
+
+subsys_initcall(omap_uwire_init);
+module_exit(omap_uwire_exit);
+
+EXPORT_SYMBOL(omap_uwire_configure_mode);
+EXPORT_SYMBOL(omap_uwire_data_transfer);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/ssi/omap-uwire.h b/drivers/ssi/omap-uwire.h
new file mode 100644 (file)
index 0000000..a0d24bc
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef __ARCH_OMAP_UWIRE_H
+#define __ARCH_OMAP_UWIRE_H
+
+#define UWIRE_READ_FALLING_EDGE                0x0000
+#define UWIRE_READ_RISING_EDGE         0x0001
+#define UWIRE_WRITE_FALLING_EDGE       0x0000
+#define UWIRE_WRITE_RISING_EDGE                0x0002
+#define UWIRE_CS_ACTIVE_LOW            0x0000
+#define UWIRE_CS_ACTIVE_HIGH           0x0004
+#define UWIRE_FREQ_DIV_2               0x0000
+#define UWIRE_FREQ_DIV_4               0x0008
+#define UWIRE_FREQ_DIV_8               0x0010
+#define UWIRE_CHK_READY                        0x0020
+#define UWIRE_CLK_INVERTED             0x0040
+
+/*
+ * uWire for OMAP declarations
+ */
+extern void omap_uwire_configure_mode(int cs, unsigned long flags);
+
+/* NOTE: Make sure you don't call this from an interrupt handler! */
+extern int omap_uwire_data_transfer(int cs, u16 tx_data, int tx_size,
+                                   int rx_size, u16 *rx_buf,
+                                   int leave_cs_active);
+
+#endif
index 9980a4ddfed934617a7726c6c612a24edebb4d27..b3d850399b49f63aa718552206459fbc7fda1ad4 100644 (file)
@@ -81,6 +81,8 @@ source "drivers/usb/core/Kconfig"
 
 source "drivers/usb/host/Kconfig"
 
+source "drivers/usb/musb/Kconfig"
+
 source "drivers/usb/class/Kconfig"
 
 source "drivers/usb/storage/Kconfig"
index 4097a86c4b5e125c5de26dc6905259d52ab13657..2f9f1612559bcf96f7a4cea02616ecc5c85282c0 100644 (file)
@@ -155,10 +155,20 @@ config USB_LH7A40X
        select USB_GADGET_SELECTED
 
 
+# built in ../musb along with host support
+config USB_GADGET_MUSB_HDRC
+       boolean "Inventra HDRC USB Peripheral (TI, ...)"
+       depends on USB_MUSB_HDRC && (USB_MUSB_PERIPHERAL || USB_MUSB_OTG)
+       select USB_GADGET_DUALSPEED
+       select USB_GADGET_SELECTED
+       help
+         This OTG-capable silicon IP is used in dual designs including
+         the TI DaVinci, OMAP 243x, OMAP 343x, and TUSB 6010.
+
 config USB_GADGET_OMAP
        boolean "OMAP USB Device Controller"
        depends on ARCH_OMAP
-       select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
+       select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG
        help
           Many Texas Instruments OMAP processors have flexible full
           speed USB device controllers, with support for up to 30
index cdcfd42843d46053deda8fe3863a67004079877a..91b3bb098d9f4f618b0eb6a60f47adb3b480463c 100644 (file)
@@ -2580,7 +2580,9 @@ omap_ep_setup(char *name, u8 addr, u8 type,
                 * and ignored for PIO-IN on newer chips
                 * (for more reliable behavior)
                 */
-               if (!use_dma || cpu_is_omap15xx() || cpu_is_omap24xx())
+               if ((!use_dma && (addr & USB_DIR_IN))
+                               || machine_is_omap_apollon()
+                               || cpu_is_omap15xx())
                        dbuf = 0;
 
                switch (maxp) {
index 27be1f9368853925da47e2b64cd18fb3ec59088e..b3da18b7b8a594a9751390cb7789dbeba73669c3 100644 (file)
@@ -227,7 +227,7 @@ static int ohci_omap_init(struct usb_hcd *hcd)
 
        omap_ohci_clock_power(1);
 
-       if (cpu_is_omap1510()) {
+       if (cpu_is_omap15xx()) {
                omap_1510_local_bus_power(1);
                omap_1510_local_bus_init();
        }
@@ -315,7 +315,7 @@ static int usb_hcd_omap_probe (const struct hc_driver *driver,
        if (IS_ERR(usb_host_ck))
                return PTR_ERR(usb_host_ck);
 
-       if (!cpu_is_omap1510())
+       if (!cpu_is_omap15xx())
                usb_dc_ck = clk_get(0, "usb_dc_ck");
        else
                usb_dc_ck = clk_get(0, "lb_ck");
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
new file mode 100644 (file)
index 0000000..a9bcd7e
--- /dev/null
@@ -0,0 +1,176 @@
+#
+# USB Dual Role (OTG-ready) Controller Drivers
+# for silicon based on Mentor Graphics INVENTRA designs
+#
+
+comment "Enable Host or Gadget support to see Inventra options"
+       depends on !USB && USB_GADGET=n
+
+# (M)HDRC = (Multipoint) Highspeed Dual-Role Controller
+config USB_MUSB_HDRC
+       depends on USB || USB_GADGET
+       tristate 'Inventra Highspeed Dual Role Controller (TI, ...)'
+       help
+         Say Y here if your system has a dual role high speed USB
+         controller based on the Mentor Graphics silicon IP.  Then
+         configure options to match your silicon and the board
+         it's being used with, including the USB peripheral role,
+         or the USB host role, or both.
+
+         Texas Instruments parts using this IP include DaVinci 644x,
+         OMAP 243x, OMAP 343x, and TUSB 6010.
+
+         If you do not know what this is, please say N.
+
+         To compile this driver as a module, choose M here; the
+         module will be called "musb_hdrc".
+
+config USB_MUSB_SOC
+       boolean
+       depends on USB_MUSB_HDRC
+       default y if ARCH_DAVINCI
+       default y if ARCH_OMAP2430
+       default y if ARCH_OMAP343X
+       help
+         Use a static <asm/arch/hdrc_cnf.h> file to describe how the
+         controller is configured (endpoints, mechanisms, etc) on the
+         current iteration of a given system-on-chip.
+
+comment "DaVinci 644x USB support"
+       depends on USB_MUSB_HDRC && ARCH_DAVINCI
+
+comment "OMAP 243x high speed USB support"
+       depends on USB_MUSB_HDRC && ARCH_OMAP2430
+
+comment "OMAP 343x high speed USB support"
+       depends on USB_MUSB_HDRC && ARCH_OMAP343X
+
+config USB_TUSB6010
+       boolean "TUSB 6010 support"
+       depends on USB_MUSB_HDRC && !USB_MUSB_SOC
+       default y
+       help
+         The TUSB 6010 chip, from Texas Instruments, connects a discrete
+         HDRC core using a 16-bit parallel bus (NOR flash style) or VLYNQ
+         (a high speed serial link).  It can use system-specific external
+         DMA controllers.
+
+choice
+       prompt "Driver Mode"
+       depends on USB_MUSB_HDRC
+       help
+         Dual-Role devices can support both host and peripheral roles,
+         as well as a the special "OTG Device" role which can switch
+         between both roles as needed.
+
+# use USB_MUSB_HDRC_HCD not USB_MUSB_HOST to #ifdef host side support;
+# OTG needs both roles, not just USB_MUSB_HOST.
+config USB_MUSB_HOST
+       depends on USB
+       bool "USB Host"
+       help
+         Say Y here if your system supports the USB host role.
+         If it has a USB "A" (rectangular), "Mini-A" (uncommon),
+         or "Mini-AB" connector, it supports the host role.
+         (With a "Mini-AB" connector, you should enable USB OTG.)
+
+# use USB_GADGET_MUSB_HDRC not USB_MUSB_PERIPHERAL to #ifdef peripheral
+# side support ... OTG needs both roles
+config USB_MUSB_PERIPHERAL
+       depends on USB_GADGET
+       bool "USB Peripheral (gadget stack)"
+       select USB_GADGET_MUSB_HDRC
+       help
+         Say Y here if your system supports the USB peripheral role.
+         If it has a USB "B" (squarish), "Mini-B", or "Mini-AB"
+         connector, it supports the peripheral role.
+         (With a "Mini-AB" connector, you should enable USB OTG.)
+
+config USB_MUSB_OTG
+       depends on USB && USB_GADGET && EXPERIMENTAL
+       bool "Both host and peripheral:  USB OTG (On The Go) Device"
+       select USB_GADGET_MUSB_HDRC
+       select USB_OTG
+       select PM
+       help
+          The most notable feature of USB OTG is support for a
+          "Dual-Role" device, which can act as either a device
+          or a host.  The initial role choice can be changed
+          later, when two dual-role devices talk to each other.
+
+          At this writing, the OTG support in this driver is incomplete,
+          omitting the mandatory HNP or SRP protocols.  However, some
+          of the cable based role switching works.  (That is, grounding
+          the ID pin switches the controller to host mode, while leaving
+          it floating leaves it in peripheral mode.)
+
+          Select this if your system has a Mini-AB connector, or
+          to simplify certain kinds of configuration.
+
+          To implement your OTG Targeted Peripherals List (TPL), enable
+          USB_OTG_WHITELIST and update "drivers/usb/core/otg_whitelist.h"
+          to match your requirements.
+
+endchoice
+
+# enable peripheral support (including with OTG)
+config USB_GADGET_MUSB_HDRC
+       bool
+       depends on USB_MUSB_HDRC && (USB_MUSB_PERIPHERAL || USB_MUSB_OTG)
+#      default y
+#      select USB_GADGET_DUALSPEED
+#      select USB_GADGET_SELECTED
+
+# enables host support (including with OTG)
+config USB_MUSB_HDRC_HCD
+       bool
+       depends on USB_MUSB_HDRC && (USB_MUSB_HOST || USB_MUSB_OTG)
+       select USB_OTG if USB_GADGET_MUSB_HDRC
+       default y
+
+
+config USB_INVENTRA_FIFO
+       bool 'Disable DMA (always use PIO)'
+       depends on USB_MUSB_HDRC
+       default y if USB_TUSB6010
+       help
+         All data is copied between memory and FIFO by the CPU.
+         DMA controllers are ignored.
+
+         Do not select 'n' here unless DMA support for your SOC or board
+         is unavailable (or unstable).  When DMA is enabled at compile time,
+         you can still disable it at run time using the "use_dma=n" module
+         parameter.
+
+config USB_INVENTRA_DMA
+       bool
+       depends on USB_MUSB_HDRC && !USB_INVENTRA_FIFO
+       default ARCH_OMAP2430 || ARCH_OMAP343X
+       help
+         Enable DMA transfers using Mentor's engine.
+
+config USB_TI_CPPI_DMA
+       bool
+       depends on USB_MUSB_HDRC && !USB_INVENTRA_FIFO
+       default ARCH_DAVINCI
+       help
+         Enable DMA transfers when TI CPPI DMA is available.
+
+config USB_TUSB_OMAP_DMA
+       bool
+       depends on USB_MUSB_HDRC && !USB_INVENTRA_FIFO
+       depends on USB_TUSB6010
+       depends on ARCH_OMAP
+       default y
+       help
+         Enable DMA transfers on TUSB 6010 when OMAP DMA is available.
+
+config USB_INVENTRA_HCD_LOGGING
+       depends on USB_MUSB_HDRC
+       int  'Logging Level (0 - none / 3 - annoying / ... )'
+       default 0
+       help
+         Set the logging level. 0 disables the debugging altogether,
+         although when USB_DEBUG is set the value is at least 1.
+         Starting at level 3, per-transfer (urb, usb_request, packet,
+         or dma transfer) tracing may kick in.
diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
new file mode 100644 (file)
index 0000000..535ba40
--- /dev/null
@@ -0,0 +1,82 @@
+#
+# for USB OTG silicon based on Mentor Graphics INVENTRA designs
+#
+
+musb_hdrc-objs := plat_uds.o
+
+obj-$(CONFIG_USB_MUSB_HDRC)    += musb_hdrc.o
+
+ifeq ($(CONFIG_ARCH_DAVINCI),y)
+       musb_hdrc-objs  += davinci.o
+endif
+
+ifeq ($(CONFIG_USB_TUSB6010),y)
+       musb_hdrc-objs  += tusb6010.o
+endif
+
+ifeq ($(CONFIG_ARCH_OMAP2430),y)
+       musb_hdrc-objs  += omap2430.o
+endif
+
+ifeq ($(CONFIG_USB_GADGET_MUSB_HDRC),y)
+       musb_hdrc-objs          += g_ep0.o musb_gadget.o
+endif
+
+ifeq ($(CONFIG_USB_MUSB_HDRC_HCD),y)
+       musb_hdrc-objs          += virthub.o musb_host.o
+endif
+
+# the kconfig must guarantee that only one of the
+# possible I/O schemes will be enabled at a time ...
+# PIO (INVENTRA_FIFO), or DMA (several potential schemes).
+# though PIO is always there to back up DMA, and for ep0
+
+ifneq ($(CONFIG_USB_INVENTRA_FIFO),y)
+
+  ifeq ($(CONFIG_USB_INVENTRA_DMA),y)
+    musb_hdrc-objs             += musbhsdma.o
+
+  else
+    ifeq ($(CONFIG_USB_TI_CPPI_DMA),y)
+      musb_hdrc-objs           += cppi_dma.o
+
+    else
+      ifeq ($(CONFIG_USB_TUSB_OMAP_DMA),y)
+        musb_hdrc-objs         += tusb6010_omap.o
+
+      endif
+    endif
+  endif
+endif
+
+
+################################################################################
+
+# FIXME remove all these extra "-DMUSB_* things, stick to CONFIG_*
+
+ifeq ($(CONFIG_USB_INVENTRA_MUSB_HAS_AHB_ID),y)
+       EXTRA_CFLAGS += -DMUSB_AHB_ID
+endif
+
+# Debugging
+
+MUSB_DEBUG:=$(CONFIG_USB_INVENTRA_HCD_LOGGING)
+
+ifeq ("$(strip $(MUSB_DEBUG))","")
+    ifdef CONFIG_USB_DEBUG
+       MUSB_DEBUG:=1
+    else
+       MUSB_DEBUG:=0
+    endif
+endif
+
+ifneq ($(MUSB_DEBUG),0)
+    EXTRA_CFLAGS += -DDEBUG
+
+    ifeq ($(CONFIG_PROC_FS),y)
+       musb_hdrc-objs          += musb_procfs.o
+    endif
+
+endif
+
+EXTRA_CFLAGS += -DMUSB_DEBUG=$(MUSB_DEBUG)
diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
new file mode 100644 (file)
index 0000000..673b4cf
--- /dev/null
@@ -0,0 +1,1567 @@
+/*
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file implements a DMA  interface using TI's CPPI DMA.
+ * For now it's DaVinci-only, but CPPI isn't specific to DaVinci or USB.
+ * TUSB 6010 over VLYNQ has CPPI that looks much like DaVinci.
+ */
+
+#include <linux/usb.h>
+
+#include "musbdefs.h"
+#include "cppi_dma.h"
+
+
+/* CPPI DMA status 7-mar:
+ *
+ * - See musb_{host,gadget}.c for more info
+ *
+ * - Correct RX DMA generally forces the engine into irq-per-packet mode,
+ *   which can easily saturate the CPU under non-mass-storage loads.
+ *
+ * NOTES 24-aug (2.6.18-rc4):
+ *
+ * - peripheral RXDMA wedged in a test with packets of length 512/512/1.
+ *   evidently after the 1 byte packet was received and acked, the queue
+ *   of BDs got garbaged so it wouldn't empty the fifo.  (rxcsr 0x2003,
+ *   and RX DMA0: 4 left, 80000000 8feff880, 8feff860 8feff860; 8f321401
+ *   004001ff 00000001 .. 8feff860)  Host was just getting NAKed on tx
+ *   of its next (512 byte) packet.  IRQ issues?
+ *
+ * REVISIT:  the "transfer DMA" glue between CPPI and USB fifos will
+ * evidently also directly update the RX and TX CSRs ... so audit all
+ * host and peripheral side DMA code to avoid CSR access after DMA has
+ * been started.
+ */
+
+/* REVISIT now we can avoid preallocating these descriptors; or
+ * more simply, switch to a global freelist not per-channel ones.
+ * Note: at full speed, 64 descriptors == 4K bulk data.
+ */
+#define NUM_TXCHAN_BD       64
+#define NUM_RXCHAN_BD       64
+
+static inline void cpu_drain_writebuffer(void)
+{
+       wmb();
+#ifdef CONFIG_CPU_ARM926T
+       /* REVISIT this "should not be needed",
+        * but lack of it sure seemed to hurt ...
+        */
+       asm("mcr p15, 0, r0, c7, c10, 4 @ drain write buffer\n");
+#endif
+}
+
+static inline struct cppi_descriptor *
+cppi_bd_alloc(struct cppi_channel *c)
+{
+       struct cppi_descriptor  *bd = c->bdPoolHead;
+
+       if (bd)
+               c->bdPoolHead = bd->next;
+       return bd;
+}
+
+static inline void
+cppi_bd_free(struct cppi_channel *c, struct cppi_descriptor *bd)
+{
+       if (!bd)
+               return;
+       bd->next = c->bdPoolHead;
+       c->bdPoolHead = bd;
+}
+
+/*
+ *  Start Dma controller
+ *
+ *  Initialize the Dma Controller as necessary.
+ */
+
+#define        CAST (void *__force __iomem)
+
+/* zero out entire rx state RAM entry for the channel */
+static void cppi_reset_rx(struct cppi_rx_stateram *__iomem rx)
+{
+       musb_writel(CAST &rx->buffOffset, 0, 0);
+       musb_writel(CAST &rx->headPtr, 0, 0);
+       musb_writel(CAST &rx->sopDescPtr, 0, 0);
+       musb_writel(CAST &rx->currDescPtr, 0, 0);
+       musb_writel(CAST &rx->currBuffPtr, 0, 0);
+       musb_writel(CAST &rx->pktLength, 0, 0);
+       musb_writel(CAST &rx->byteCount, 0, 0);
+}
+
+static void __init cppi_pool_init(struct cppi *cppi, struct cppi_channel *c)
+{
+       int     j;
+
+       /* initialize channel fields */
+       c->activeQueueHead = NULL;
+       c->activeQueueTail = NULL;
+       c->lastHwBDProcessed = NULL;
+       c->Channel.bStatus = MGC_DMA_STATUS_UNKNOWN;
+       c->pController = cppi;
+       c->bLastModeRndis = 0;
+       c->Channel.pPrivateData = c;
+       c->bdPoolHead = NULL;
+
+       /* build the BD Free list for the channel */
+       for (j = 0; j < NUM_TXCHAN_BD + 1; j++) {
+               struct cppi_descriptor  *bd;
+               dma_addr_t              dma;
+
+               bd = dma_pool_alloc(cppi->pool, GFP_KERNEL, &dma);
+               bd->dma = dma;
+               cppi_bd_free(c, bd);
+       }
+}
+
+static int cppi_channel_abort(struct dma_channel *);
+
+static void cppi_pool_free(struct cppi_channel *c)
+{
+       struct cppi             *cppi = c->pController;
+       struct cppi_descriptor  *bd;
+
+       (void) cppi_channel_abort(&c->Channel);
+       c->Channel.bStatus = MGC_DMA_STATUS_UNKNOWN;
+       c->pController = NULL;
+
+       /* free all its bds */
+       bd = c->lastHwBDProcessed;
+       do {
+               if (bd)
+                       dma_pool_free(cppi->pool, bd, bd->dma);
+               bd = cppi_bd_alloc(c);
+       } while (bd);
+       c->lastHwBDProcessed = NULL;
+}
+
+static int __init cppi_controller_start(struct dma_controller *c)
+{
+       struct cppi     *pController;
+       void            *__iomem regBase;
+       int             i;
+
+       pController = container_of(c, struct cppi, Controller);
+
+       /* do whatever is necessary to start controller */
+       for (i = 0; i < ARRAY_SIZE(pController->txCppi); i++) {
+               pController->txCppi[i].bTransmit = TRUE;
+               pController->txCppi[i].chNo = i;
+       }
+       for (i = 0; i < ARRAY_SIZE(pController->rxCppi); i++) {
+               pController->rxCppi[i].bTransmit = FALSE;
+               pController->rxCppi[i].chNo = i;
+       }
+
+       /* setup BD list on a per channel basis */
+       for (i = 0; i < ARRAY_SIZE(pController->txCppi); i++)
+               cppi_pool_init(pController, pController->txCppi + i);
+       for (i = 0; i < ARRAY_SIZE(pController->rxCppi); i++)
+               cppi_pool_init(pController, pController->rxCppi + i);
+
+       /* Do Necessary configuartion in H/w to get started */
+       regBase =  pController->pCoreBase - DAVINCI_BASE_OFFSET;
+
+       INIT_LIST_HEAD(&pController->tx_complete);
+
+       /* initialise tx/rx channel head pointers to zero */
+       for (i = 0; i < ARRAY_SIZE(pController->txCppi); i++) {
+               struct cppi_channel     *txChannel = pController->txCppi + i;
+               struct cppi_tx_stateram *__iomem txState;
+
+               INIT_LIST_HEAD(&txChannel->tx_complete);
+
+               txState = regBase + DAVINCI_TXCPPI_STATERAM_OFFSET(i);
+               txChannel->stateRam = txState;
+               /* zero out entire state RAM entry for the channel */
+               txState->headPtr = 0;
+               txState->sopDescPtr = 0;
+               txState->currDescPtr = 0;
+               txState->currBuffPtr = 0;
+               txState->flags = 0;
+               txState->remLength = 0;
+               /*txState->dummy = 0; */
+               txState->completionPtr = 0;
+
+       }
+       for (i = 0; i < ARRAY_SIZE(pController->rxCppi); i++) {
+               struct cppi_channel     *rxChannel = pController->rxCppi + i;
+               struct cppi_rx_stateram *__iomem rxState;
+
+               INIT_LIST_HEAD(&rxChannel->tx_complete);
+
+               rxState = regBase + DAVINCI_RXCPPI_STATERAM_OFFSET(i);
+               rxChannel->stateRam = rxState;
+               cppi_reset_rx(rxChannel->stateRam);
+       }
+
+       /* enable individual cppi channels */
+       musb_writel(regBase, DAVINCI_TXCPPI_INTENAB_REG,
+                       DAVINCI_DMA_ALL_CHANNELS_ENABLE);
+       musb_writel(regBase, DAVINCI_RXCPPI_INTENAB_REG,
+                       DAVINCI_DMA_ALL_CHANNELS_ENABLE);
+
+       /* enable tx/rx CPPI control */
+       musb_writel(regBase, DAVINCI_TXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_ENABLE);
+       musb_writel(regBase, DAVINCI_RXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_ENABLE);
+
+       /* disable RNDIS mode, also host rx RNDIS autorequest */
+       musb_writel(regBase, DAVINCI_RNDIS_REG, 0);
+       musb_writel(regBase, DAVINCI_AUTOREQ_REG, 0);
+
+       return 0;
+}
+
+/*
+ *  Stop Dma controller
+ *
+ *  De-Init the Dma Controller as necessary.
+ */
+
+static int cppi_controller_stop(struct dma_controller *c)
+{
+       struct cppi             *pController;
+       void __iomem            *regBase;
+       int                     i;
+
+       pController = container_of(c, struct cppi, Controller);
+
+       regBase = pController->pCoreBase - DAVINCI_BASE_OFFSET;
+       /* DISABLE INDIVIDUAL CHANNEL Interrupts */
+       musb_writel(regBase, DAVINCI_TXCPPI_INTCLR_REG,
+                       DAVINCI_DMA_ALL_CHANNELS_ENABLE);
+       musb_writel(regBase, DAVINCI_RXCPPI_INTCLR_REG,
+                       DAVINCI_DMA_ALL_CHANNELS_ENABLE);
+
+       DBG(1, "Tearing down RX and TX Channels\n");
+       for (i = 0; i < ARRAY_SIZE(pController->txCppi); i++) {
+               /* FIXME restructure of txdma to use bds like rxdma */
+               pController->txCppi[i].lastHwBDProcessed = NULL;
+               cppi_pool_free(pController->txCppi + i);
+       }
+       for (i = 0; i < ARRAY_SIZE(pController->rxCppi); i++)
+               cppi_pool_free(pController->rxCppi + i);
+
+       /* in Tx Case proper teardown is supported. We resort to disabling
+        * Tx/Rx CPPI after cleanup of Tx channels. Before TX teardown is
+        * complete TX CPPI cannot be disabled.
+        */
+       /*disable tx/rx cppi */
+       musb_writel(regBase, DAVINCI_TXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE);
+       musb_writel(regBase, DAVINCI_RXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE);
+
+       return 0;
+}
+
+/* While dma channel is allocated, we only want the core irqs active
+ * for fault reports, otherwise we'd get irqs that we don't care about.
+ * Except for TX irqs, where dma done != fifo empty and reusable ...
+ *
+ * NOTE: docs don't say either way, but irq masking **enables** irqs.
+ *
+ * REVISIT same issue applies to pure PIO usage too, and non-cppi dma...
+ */
+static inline void core_rxirq_disable(void __iomem *tibase, unsigned epnum)
+{
+       musb_writel(tibase, DAVINCI_USB_INT_MASK_CLR_REG, 1 << (epnum + 8));
+}
+
+static inline void core_rxirq_enable(void __iomem *tibase, unsigned epnum)
+{
+       musb_writel(tibase, DAVINCI_USB_INT_MASK_SET_REG, 1 << (epnum + 8));
+}
+
+
+/*
+ * Allocate a CPPI Channel for DMA.  With CPPI, channels are bound to
+ * each transfer direction of a non-control endpoint, so allocating
+ * (and deallocating) is mostly a way to notice bad housekeeping on
+ * the software side.  We assume the irqs are always active.
+ */
+static struct dma_channel *
+cppi_channel_allocate(struct dma_controller *c,
+               struct musb_hw_ep *ep,
+               u8 bTransmit)
+{
+       struct cppi             *pController;
+       u8                      chNum;
+       struct cppi_channel     *otgCh;
+       void __iomem            *tibase;
+       int                     local_end = ep->bLocalEnd;
+
+       pController = container_of(c, struct cppi, Controller);
+       tibase = pController->pCoreBase - DAVINCI_BASE_OFFSET;
+
+       /* remember local_end: 1..Max_EndPt, and cppi ChNum:0..Max_EndPt-1 */
+       chNum = local_end - 1;
+
+       /* return the corresponding CPPI Channel Handle, and
+        * probably disable the non-CPPI irq until we need it.
+        */
+       if (bTransmit) {
+               if (local_end > ARRAY_SIZE(pController->txCppi)) {
+                       DBG(1, "no %cX DMA channel for ep%d\n", 'T', local_end);
+                       return NULL;
+               }
+               otgCh = pController->txCppi + chNum;
+       } else {
+               if (local_end > ARRAY_SIZE(pController->rxCppi)) {
+                       DBG(1, "no %cX DMA channel for ep%d\n", 'R', local_end);
+                       return NULL;
+               }
+               otgCh = pController->rxCppi + chNum;
+               core_rxirq_disable(tibase, local_end);
+       }
+
+       /* REVISIT make this an error later once the same driver code works
+        * with the Mentor DMA engine too
+        */
+       if (otgCh->pEndPt)
+               DBG(1, "re-allocating DMA%d %cX channel %p\n",
+                               chNum, bTransmit ? 'T' : 'R', otgCh);
+       otgCh->pEndPt = ep;
+       otgCh->Channel.bStatus = MGC_DMA_STATUS_FREE;
+
+       DBG(4, "Allocate CPPI%d %cX\n", chNum, bTransmit ? 'T' : 'R');
+       otgCh->Channel.pPrivateData = otgCh;
+       return &otgCh->Channel;
+}
+
+/* Release a CPPI Channel.  */
+static void cppi_channel_release(struct dma_channel *channel)
+{
+       struct cppi_channel     *c;
+       void __iomem            *tibase;
+       unsigned                epnum;
+
+       /* REVISIT:  for paranoia, check state and abort if needed... */
+
+       c = container_of(channel, struct cppi_channel, Channel);
+       epnum = c->chNo + 1;
+       tibase = c->pController->pCoreBase - DAVINCI_BASE_OFFSET;
+       if (!c->pEndPt)
+               DBG(1, "releasing idle DMA channel %p\n", c);
+       else if (!c->bTransmit)
+               core_rxirq_enable(tibase, epnum);
+
+       /* for now, leave its cppi IRQ enabled (we won't trigger it) */
+       c->pEndPt = NULL;
+       channel->bStatus = MGC_DMA_STATUS_UNKNOWN;
+}
+
+/* Context: controller irqlocked */
+static void
+cppi_dump_rx(int level, struct cppi_channel *c, const char *tag)
+{
+       void    *__iomem base = c->pController->pCoreBase;
+
+       MGC_SelectEnd(base, c->chNo + 1);
+
+       DBG(level, "RX DMA%d%s: %d left, csr %04x, "
+                       "%08x H%08x S%08x C%08x, "
+                       "B%08x L%08x %08x .. %08x"
+                       "\n",
+               c->chNo, tag,
+               musb_readl(base - DAVINCI_BASE_OFFSET,
+                       DAVINCI_RXCPPI_BUFCNT0_REG + 4 *c->chNo),
+               musb_readw(c->pEndPt->regs, MGC_O_HDRC_RXCSR),
+
+               musb_readl(c->stateRam, 0 * 4), /* buf offset */
+               musb_readl(c->stateRam, 1 * 4), /* head ptr */
+               musb_readl(c->stateRam, 2 * 4), /* sop bd */
+               musb_readl(c->stateRam, 3 * 4), /* current bd */
+
+               musb_readl(c->stateRam, 4 * 4), /* current buf */
+               musb_readl(c->stateRam, 5 * 4), /* pkt len */
+               musb_readl(c->stateRam, 6 * 4), /* byte cnt */
+               musb_readl(c->stateRam, 7 * 4)  /* completion */
+               );
+}
+
+/* Context: controller irqlocked */
+static void
+cppi_dump_tx(int level, struct cppi_channel *c, const char *tag)
+{
+       void    *__iomem base = c->pController->pCoreBase;
+
+       MGC_SelectEnd(base, c->chNo + 1);
+
+       DBG(level, "TX DMA%d%s: csr %04x, "
+                       "H%08x S%08x C%08x %08x, "
+                       "F%08x L%08x .. %08x"
+                       "\n",
+               c->chNo, tag,
+               musb_readw(c->pEndPt->regs, MGC_O_HDRC_TXCSR),
+
+               musb_readl(c->stateRam, 0 * 4), /* head ptr */
+               musb_readl(c->stateRam, 1 * 4), /* sop bd */
+               musb_readl(c->stateRam, 2 * 4), /* current bd */
+               musb_readl(c->stateRam, 3 * 4), /* buf offset */
+
+               musb_readl(c->stateRam, 4 * 4), /* flags */
+               musb_readl(c->stateRam, 5 * 4), /* len */
+               // dummy/unused word 6
+               musb_readl(c->stateRam, 7 * 4)  /* completion */
+               );
+}
+
+/* Context: controller irqlocked */
+static inline void
+cppi_rndis_update(struct cppi_channel *c, int is_rx,
+               void *__iomem tibase, int is_rndis)
+{
+       /* we may need to change the rndis flag for this cppi channel */
+       if (c->bLastModeRndis != is_rndis) {
+               u32     regVal = musb_readl(tibase, DAVINCI_RNDIS_REG);
+               u32     temp = 1 << (c->chNo);
+
+               if (is_rx)
+                       temp <<= 16;
+               if (is_rndis)
+                       regVal |= temp;
+               else
+                       regVal &= ~temp;
+               musb_writel(tibase, DAVINCI_RNDIS_REG, regVal);
+               c->bLastModeRndis = is_rndis;
+       }
+}
+
+static void cppi_dump_rxbd(const char *tag, struct cppi_descriptor *bd)
+{
+       pr_debug("RXBD/%s %08x: "
+                       "nxt %08x buf %08x off.blen %08x opt.plen %08x\n",
+                       tag, bd->dma,
+                       bd->hNext, bd->buffPtr, bd->bOffBLen, bd->hOptions);
+}
+
+static void cppi_dump_rxq(int level, const char *tag, struct cppi_channel *rx)
+{
+#if MUSB_DEBUG > 0
+       struct cppi_descriptor  *bd;
+
+       if (!_dbg_level(level))
+               return;
+       cppi_dump_rx(level, rx, tag);
+       if (rx->lastHwBDProcessed)
+               cppi_dump_rxbd("last", rx->lastHwBDProcessed);
+       for (bd = rx->activeQueueHead; bd; bd = bd->next)
+               cppi_dump_rxbd("active", bd);
+#endif
+}
+
+
+/* NOTE:  DaVinci autoreq is ignored except for host side "RNDIS" mode RX;
+ * so we won't ever use it (see "CPPI RX Woes" below).
+ */
+static inline int cppi_autoreq_update(struct cppi_channel *rx,
+               void *__iomem tibase, int onepacket, unsigned n_bds)
+{
+       u32     val;
+
+#ifdef RNDIS_RX_IS_USABLE
+       u32     tmp;
+       /* assert(is_host_active(musb)) */
+
+       /* start from "AutoReq never" */
+       tmp = musb_readl(tibase, DAVINCI_AUTOREQ_REG);
+       val = tmp & ~((0x3) << (rx->chNo * 2));
+
+       /* HCD arranged reqpkt for packet #1.  we arrange int
+        * for all but the last one, maybe in two segments.
+        */
+       if (!onepacket) {
+#if 0
+               /* use two segments, autoreq "all" then the last "never" */
+               val |= ((0x3) << (rx->chNo * 2));
+               n_bds--;
+#else
+               /* one segment, autoreq "all-but-last" */
+               val |= ((0x1) << (rx->chNo * 2));
+#endif
+       }
+
+       if (val != tmp) {
+               int n = 100;
+
+               /* make sure that autoreq is updated before continuing */
+               musb_writel(tibase, DAVINCI_AUTOREQ_REG, val);
+               do {
+                       tmp = musb_readl(tibase, DAVINCI_AUTOREQ_REG);
+                       if (tmp == val)
+                               break;
+                       cpu_relax();
+               } while (n-- > 0);
+       }
+#endif
+
+       /* REQPKT is turned off after each segment */
+       if (n_bds && rx->actualLen) {
+               void            *__iomem regs = rx->pEndPt->regs;
+
+               val = musb_readw(regs, MGC_O_HDRC_RXCSR);
+               if (!(val & MGC_M_RXCSR_H_REQPKT)) {
+                       val |= MGC_M_RXCSR_H_REQPKT | MGC_M_RXCSR_H_WZC_BITS;
+                       musb_writew(regs, MGC_O_HDRC_RXCSR, val);
+                       /* flush writebufer */
+                       val = musb_readw(regs, MGC_O_HDRC_RXCSR);
+               }
+       }
+       return n_bds;
+}
+
+
+/* Buffer enqueuing Logic:
+ *
+ *  - RX builds new queues each time, to help handle routine "early
+ *    termination" cases (faults, including errors and short reads)
+ *    more correctly.
+ *
+ *  - for now, TX reuses the same queue of BDs every time
+ *
+ * REVISIT long term, we want a normal dynamic model.
+ * ... the goal will be to append to the
+ * existing queue, processing completed "dma buffers" (segments) on the fly.
+ *
+ * Otherwise we force an IRQ latency between requests, which slows us a lot
+ * (especially in "transparent" dma).  Unfortunately that model seems to be
+ * inherent in the DMA model from the Mentor code, except in the rare case
+ * of transfers big enough (~128+ KB) that we could append "middle" segments
+ * in the TX paths.  (RX can't do this, see below.)
+ *
+ * That's true even in the CPPI- friendly iso case, where most urbs have
+ * several small segments provided in a group and where the "packet at a time"
+ * "transparent" DMA model is always correct, even on the RX side.
+ */
+
+/*
+ * CPPI TX:
+ * ========
+ * TX is a lot more reasonable than RX; it doesn't need to run in
+ * irq-per-packet mode very often.  RNDIS mode seems to behave too
+ * (other how it handles the exactly-N-packets case).  Building a
+ * txdma queue with multiple requests (urb or usb_request) looks
+ * like it would work ... but fault handling would need much testing.
+ *
+ * The main issue with TX mode RNDIS relates to transfer lengths that
+ * are an exact multiple of the packet length.  It appears that there's
+ * a hiccup in that case (maybe the DMA completes before the ZLP gets
+ * written?) boiling down to not being able to rely on CPPI writing any
+ * terminating zero length packet before the next transfer is written.
+ * So that's punted to PIO; better yet, gadget drivers can avoid it.
+ *
+ * Plus, there's allegedly an undocumented constraint that rndis transfer
+ * length be a multiple of 64 bytes ... but the chip doesn't act that
+ * way, and we really don't _want_ that behavior anyway.
+ *
+ * On TX, "transparent" mode works ... although experiments have shown
+ * problems trying to use the SOP/EOP bits in different USB packets.
+ *
+ * REVISIT try to handle terminating zero length packets using CPPI
+ * instead of doing it by PIO after an IRQ.  (Meanwhile, make Ethernet
+ * links avoid that issue by forcing them to avoid zlps.)
+ */
+static void
+cppi_next_tx_segment(struct musb *musb, struct cppi_channel *tx)
+{
+       unsigned                maxpacket = tx->pktSize;
+       dma_addr_t              addr = tx->startAddr + tx->currOffset;
+       size_t                  length = tx->transferSize - tx->currOffset;
+       struct cppi_descriptor  *bd;
+       unsigned                n_bds;
+       unsigned                i;
+       struct cppi_tx_stateram *txState = tx->stateRam;
+       int                     rndis;
+
+       /* TX can use the CPPI "rndis" mode, where we can probably fit this
+        * transfer in one BD and one IRQ.  The only time we would NOT want
+        * to use it is when hardware constraints prevent it, or if we'd
+        * trigger the "send a ZLP?" confusion.
+        */
+       rndis = (maxpacket & 0x3f) == 0
+               && length < 0xffff
+               && (length % maxpacket) != 0;
+
+       if (rndis) {
+               maxpacket = length;
+               n_bds = 1;
+       } else {
+               n_bds = length / maxpacket;
+               if (!length || (length % maxpacket))
+                       n_bds++;
+               n_bds = min(n_bds, (unsigned) NUM_TXCHAN_BD);
+               length = min(n_bds * maxpacket, length);
+       }
+
+       DBG(4, "TX DMA%d, pktSz %d %s bds %d dma 0x%x len %u\n",
+                       tx->chNo,
+                       maxpacket,
+                       rndis ? "rndis" : "transparent",
+                       n_bds,
+                       addr, length);
+
+       cppi_rndis_update(tx, 0, musb->ctrl_base, rndis);
+
+       /* assuming here that channel_program is called during
+        * transfer initiation ... current code maintains state
+        * for one outstanding request only (no queues, not even
+        * the implicit ones of an iso urb).
+        */
+
+       bd = tx->bdPoolHead;
+       tx->activeQueueHead = tx->bdPoolHead;
+       tx->lastHwBDProcessed = NULL;
+
+
+       /* Prepare queue of BDs first, then hand it to hardware.
+        * All BDs except maybe the last should be of full packet
+        * size; for RNDIS there _is_ only that last packet.
+        */
+       for (i = 0; i < n_bds; ) {
+               if (++i < n_bds && bd->next)
+                       bd->hNext = bd->next->dma;
+               else
+                       bd->hNext = 0;
+
+               bd->buffPtr = tx->startAddr
+                       + tx->currOffset;
+
+               /* FIXME set EOP only on the last packet,
+                * SOP only on the first ... avoid IRQs
+                */
+               if ((tx->currOffset + maxpacket)
+                               <= tx->transferSize) {
+                       tx->currOffset += maxpacket;
+                       bd->bOffBLen = maxpacket;
+                       bd->hOptions = CPPI_SOP_SET | CPPI_EOP_SET
+                               | CPPI_OWN_SET | maxpacket;
+               } else {
+                       /* only this one may be a partial USB Packet */
+                       u32 buffSz;
+
+                       buffSz = tx->transferSize - tx->currOffset;
+                       tx->currOffset = tx->transferSize;
+                       bd->bOffBLen = buffSz;
+
+                       bd->hOptions = CPPI_SOP_SET | CPPI_EOP_SET
+                               | CPPI_OWN_SET | buffSz;
+                       if (buffSz == 0)
+                               bd->hOptions |= CPPI_ZERO_SET;
+               }
+
+               DBG(5, "TXBD %p: nxt %08x buf %08x len %04x opt %08x\n",
+                               bd, bd->hNext, bd->buffPtr,
+                               bd->bOffBLen, bd->hOptions);
+
+               /* update the last BD enqueued to the list */
+               tx->activeQueueTail = bd;
+               bd = bd->next;
+       }
+
+       /* BDs live in DMA-coherent memory, but writes might be pending */
+       cpu_drain_writebuffer();
+
+       /* Write to the HeadPtr in StateRam to trigger */
+       txState->headPtr = (u32)tx->bdPoolHead->dma;
+
+       cppi_dump_tx(5, tx, "/S");
+}
+
+/*
+ * CPPI RX Woes:
+ * =============
+ * Consider a 1KB bulk RX buffer in two scenarios:  (a) it's fed two 300 byte
+ * packets back-to-back, and (b) it's fed two 512 byte packets back-to-back.
+ * (Full speed transfers have similar scenarios.)
+ *
+ * The correct behavior for Linux is that (a) fills the buffer with 300 bytes,
+ * and the next packet goes into a buffer that's queued later; while (b) fills
+ * the buffer with 1024 bytes.  How to do that with CPPI?
+ *
+ * - RX queues in "rndis" mode -- one single BD -- handle (a) correctly, but
+ *   (b) loses **BADLY** because nothing (!) happens when that second packet
+ *   fills the buffer, much less when a third one arrives.  (Which makes this
+ *   not a "true" RNDIS mode.  In the RNDIS protocol short-packet termination
+ *   is optional, and it's fine if peripherals -- not hosts! -- pad messages
+ *   out to end-of-buffer.  Standard PCI host controller DMA descriptors
+ *   implement that mode by default ... which is no accident.)
+ *
+ * - RX queues in "transparent" mode -- two BDs with 512 bytes each -- have
+ *   converse problems:  (b) is handled right, but (a) loses badly.  CPPI RX
+ *   ignores SOP/EOP markings and processes both of those BDs; so both packets
+ *   are loaded into the buffer (with a 212 byte gap between them), and the next
+ *   buffer queued will NOT get its 300 bytes of data. (It seems like SOP/EOP
+ *   are intended as outputs for RX queues, not inputs...)
+ *
+ * - A variant of "transparent" mode -- one BD at a time -- is the only way to
+ *   reliably make both cases work, with software handling both cases correctly
+ *   and at the significant penalty of needing an IRQ per packet.  (The lack of
+ *   I/O overlap can be slightly ameliorated by enabling double buffering.)
+ *
+ * So how to get rid of IRQ-per-packet?  The transparent multi-BD case could
+ * be used in special cases like mass storage, which sets URB_SHORT_NOT_OK
+ * (or maybe its peripheral side counterpart) to flag (a) scenarios as errors
+ * with guaranteed driver level fault recovery and scrubbing out what's left
+ * of that garbaged datastream.
+ *
+ * But there seems to be no way to identify the cases where CPPI RNDIS mode
+ * is appropriate -- which do NOT include RNDIS host drivers, but do include
+ * the CDC Ethernet driver! -- and the documentation is incomplete/wrong.
+ * So we can't _ever_ use RX RNDIS mode ... except by using a heuristic
+ * that applies best on the peripheral side (and which could fail rudely).
+ *
+ * Leaving only "transparent" mode; we avoid multi-bd modes in almost all
+ * cases other than mass storage class.  Otherwise we're correct but slow,
+ * since CPPI penalizes our need for a "true RNDIS" default mode.
+ */
+
+
+/* Heuristic, intended to kick in for ethernet/rndis peripheral ONLY
+ *
+ * IFF
+ *  (a)        peripheral mode ... since rndis peripherals could pad their
+ *     writes to hosts, causing i/o failure; or we'd have to cope with
+ *     a largely unknowable variety of host side protocol variants
+ *  (b)        and short reads are NOT errors ... since full reads would
+ *     cause those same i/o failures
+ *  (c)        and read length is
+ *     - less than 64KB (max per cppi descriptor)
+ *     - not a multiple of 4096 (g_zero default, full reads typical)
+ *     - N (>1) packets long, ditto (full reads not EXPECTED)
+ * THEN
+ *   try rx rndis mode
+ *
+ * Cost of heuristic failing:  RXDMA wedges at the end of transfers that
+ * fill out the whole buffer.  Buggy host side usb network drivers could
+ * trigger that, but "in the field" such bugs seem to be all but unknown.
+ *
+ * So this module parameter lets the heuristic be disabled.  When using
+ * gadgetfs, the heuristic will probably need to be disabled.
+ */
+static int cppi_rx_rndis = 1;
+
+module_param(cppi_rx_rndis, bool, 0);
+MODULE_PARM_DESC(cppi_rx_rndis, "enable/disable RX RNDIS heuristic");
+
+
+/**
+ * cppi_next_rx_segment - dma read for the next chunk of a buffer
+ * @musb: the controller
+ * @rx: dma channel
+ * @onepacket: true unless caller treats short reads as errors, and
+ *     performs fault recovery above usbcore.
+ * Context: controller irqlocked
+ *
+ * See above notes about why we can't use multi-BD RX queues except in
+ * rare cases (mass storage class), and can never use the hardware "rndis"
+ * mode (since it's not a "true" RNDIS mode) with complete safety..
+ *
+ * It's ESSENTIAL that callers specify "onepacket" mode unless they kick in
+ * code to recover from corrupted datastreams after each short transfer.
+ */
+static void
+cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)
+{
+       unsigned                maxpacket = rx->pktSize;
+       dma_addr_t              addr = rx->startAddr + rx->currOffset;
+       size_t                  length = rx->transferSize - rx->currOffset;
+       struct cppi_descriptor  *bd, *tail;
+       unsigned                n_bds;
+       unsigned                i;
+       void                    *__iomem tibase = musb->ctrl_base;
+       int                     is_rndis = 0;
+
+       if (onepacket) {
+               /* almost every USB driver, host or peripheral side */
+               n_bds = 1;
+
+               /* maybe apply the heuristic above */
+               if (cppi_rx_rndis
+                               && is_peripheral_active(musb)
+                               && length > maxpacket
+                               && (length & ~0xffff) == 0
+                               && (length & 0x0fff) != 0
+                               && (length & (maxpacket - 1)) == 0) {
+                       maxpacket = length;
+                       is_rndis = 1;
+               }
+       } else {
+               /* virtually nothing except mass storage class */
+               if (length > 0xffff) {
+                       n_bds = 0xffff / maxpacket;
+                       length = n_bds * maxpacket;
+               } else {
+                       n_bds = length / maxpacket;
+                       if (length % maxpacket)
+                               n_bds++;
+               }
+               if (n_bds == 1)
+                       onepacket = 1;
+               else
+                       n_bds = min(n_bds, (unsigned) NUM_RXCHAN_BD);
+       }
+
+       /* In host mode, autorequest logic can generate some IN tokens; it's
+        * tricky since we can't leave REQPKT set in RXCSR after the transfer
+        * finishes. So:  multipacket transfers involve two or more segments.
+        * And always at least two IRQs ... RNDIS mode is not an option.
+        */
+       if (is_host_active(musb))
+               n_bds = cppi_autoreq_update(rx, tibase, onepacket, n_bds);
+
+       cppi_rndis_update(rx, 1, musb->ctrl_base, is_rndis);
+
+       length = min(n_bds * maxpacket, length);
+
+       DBG(4, "RX DMA%d seg, maxp %d %s bds %d (cnt %d) "
+                       "dma 0x%x len %u %u/%u\n",
+                       rx->chNo, maxpacket,
+                       onepacket
+                               ? (is_rndis ? "rndis" : "onepacket")
+                               : "multipacket",
+                       n_bds,
+                       musb_readl(tibase,
+                               DAVINCI_RXCPPI_BUFCNT0_REG + (rx->chNo * 4))
+                                       & 0xffff,
+                       addr, length, rx->actualLen, rx->transferSize);
+
+       /* only queue one segment at a time, since the hardware prevents
+        * correct queue shutdown after unexpected short packets
+        */
+       bd = cppi_bd_alloc(rx);
+       rx->activeQueueHead = bd;
+
+       /* Build BDs for all packets in this segment */
+       for (i = 0, tail = NULL; bd && i < n_bds; i++, tail = bd) {
+               u32     buffSz;
+
+               if (i) {
+                       bd = cppi_bd_alloc(rx);
+                       if (!bd)
+                               break;
+                       tail->next = bd;
+                       tail->hNext = bd->dma;
+               }
+               bd->hNext = 0;
+
+               /* all but the last packet will be maxpacket size */
+               if (maxpacket < length)
+                       buffSz = maxpacket;
+               else
+                       buffSz = length;
+
+               bd->buffPtr = addr;
+               addr += buffSz;
+               rx->currOffset += buffSz;
+
+               bd->bOffBLen = (0 /*offset*/ << 16) + buffSz;
+               bd->enqBuffLen = buffSz;
+
+               bd->hOptions = CPPI_OWN_SET | (i == 0 ? length : 0);
+               length -= buffSz;
+       }
+
+       /* we always expect at least one reusable BD! */
+       if (!tail) {
+               WARN("rx dma%d -- no BDs? need %d\n", rx->chNo, n_bds);
+               return;
+       } else if (i < n_bds)
+               WARN("rx dma%d -- only %d of %d BDs\n", rx->chNo, i, n_bds);
+
+       tail->next = NULL;
+       tail->hNext = 0;
+
+       bd = rx->activeQueueHead;
+       rx->activeQueueTail = tail;
+
+       /* short reads and other faults should terminate this entire
+        * dma segment.  we want one "dma packet" per dma segment, not
+        * one per USB packet, terminating the whole queue at once...
+        * NOTE that current hardware seems to ignore SOP and EOP.
+        */
+       bd->hOptions |= CPPI_SOP_SET;
+       tail->hOptions |= CPPI_EOP_SET;
+
+       if (debug >= 5) {
+               struct cppi_descriptor  *d;
+
+               for (d = rx->activeQueueHead; d; d = d->next)
+                       cppi_dump_rxbd("S", d);
+       }
+
+       /* in case the preceding transfer left some state... */
+       tail = rx->lastHwBDProcessed;
+       if (tail) {
+               tail->next = bd;
+               tail->hNext = bd->dma;
+       }
+
+       core_rxirq_enable(tibase, rx->chNo + 1);
+
+       /* BDs live in DMA-coherent memory, but writes might be pending */
+       cpu_drain_writebuffer();
+
+       /* REVISIT specs say to write this AFTER the BUFCNT register
+        * below ... but that loses badly.
+        */
+       musb_writel(rx->stateRam, 4, bd->dma);
+
+       /* bufferCount must be at least 3, and zeroes on completion
+        * unless it underflows below zero, or stops at two, or keeps
+        * growing ... grr.
+        */
+       i = musb_readl(tibase,
+                       DAVINCI_RXCPPI_BUFCNT0_REG + (rx->chNo * 4))
+                       & 0xffff;
+
+       if (!i)
+               musb_writel(tibase,
+                       DAVINCI_RXCPPI_BUFCNT0_REG + (rx->chNo * 4),
+                       n_bds + 2);
+       else if (n_bds > (i - 3))
+               musb_writel(tibase,
+                       DAVINCI_RXCPPI_BUFCNT0_REG + (rx->chNo * 4),
+                       n_bds - (i - 3));
+
+       i = musb_readl(tibase,
+                       DAVINCI_RXCPPI_BUFCNT0_REG + (rx->chNo * 4))
+                       & 0xffff;
+       if (i < (2 + n_bds)) {
+               DBG(2, "bufcnt%d underrun - %d (for %d)\n",
+                                       rx->chNo, i, n_bds);
+               musb_writel(tibase,
+                       DAVINCI_RXCPPI_BUFCNT0_REG + (rx->chNo * 4),
+                       n_bds + 2);
+       }
+
+       cppi_dump_rx(4, rx, "/S");
+}
+
+/**
+ * cppi_channel_program - program channel for data transfer
+ * @pChannel: the channel
+ * @wPacketSz: max packet size
+ * @mode: For RX, 1 unless the usb protocol driver promised to treat
+ *     all short reads as errors and kick in high level fault recovery.
+ *     For TX, ignored because of RNDIS mode races/glitches.
+ * @dma_addr: dma address of buffer
+ * @dwLength: length of buffer
+ * Context: controller irqlocked
+ */
+static int cppi_channel_program(struct dma_channel *pChannel,
+               u16 wPacketSz, u8 mode,
+               dma_addr_t dma_addr, u32 dwLength)
+{
+       struct cppi_channel     *otgChannel = pChannel->pPrivateData;
+       struct cppi             *pController = otgChannel->pController;
+       struct musb             *musb = pController->musb;
+
+       switch (pChannel->bStatus) {
+       case MGC_DMA_STATUS_BUS_ABORT:
+       case MGC_DMA_STATUS_CORE_ABORT:
+               /* fault irq handler should have handled cleanup */
+               WARN("%cX DMA%d not cleaned up after abort!\n",
+                               otgChannel->bTransmit ? 'T' : 'R',
+                               otgChannel->chNo);
+               //WARN_ON(1);
+               break;
+       case MGC_DMA_STATUS_BUSY:
+               WARN("program active channel?  %cX DMA%d\n",
+                               otgChannel->bTransmit ? 'T' : 'R',
+                               otgChannel->chNo);
+               //WARN_ON(1);
+               break;
+       case MGC_DMA_STATUS_UNKNOWN:
+               DBG(1, "%cX DMA%d not allocated!\n",
+                               otgChannel->bTransmit ? 'T' : 'R',
+                               otgChannel->chNo);
+               /* FALLTHROUGH */
+       case MGC_DMA_STATUS_FREE:
+               break;
+       }
+
+       pChannel->bStatus = MGC_DMA_STATUS_BUSY;
+
+       /* set transfer parameters, then queue up its first segment */
+       otgChannel->startAddr = dma_addr;
+       otgChannel->currOffset = 0;
+       otgChannel->pktSize = wPacketSz;
+       otgChannel->actualLen = 0;
+       otgChannel->transferSize = dwLength;
+
+       /* TX channel? or RX? */
+       if (otgChannel->bTransmit)
+               cppi_next_tx_segment(musb, otgChannel);
+       else
+               cppi_next_rx_segment(musb, otgChannel, mode);
+
+       return TRUE;
+}
+
+static int cppi_rx_scan(struct cppi *cppi, unsigned ch)
+{
+       struct cppi_channel             *rx = &cppi->rxCppi[ch];
+       struct cppi_rx_stateram         *state = rx->stateRam;
+       struct cppi_descriptor          *bd;
+       struct cppi_descriptor          *last = rx->lastHwBDProcessed;
+       int                             completed = 0, acked = 0;
+       int                             i;
+       dma_addr_t                      safe2ack;
+       void                            *__iomem regs = rx->pEndPt->regs;
+
+       cppi_dump_rx(6, rx, "/K");
+
+       bd = last ? last->next : rx->activeQueueHead;
+       if (!bd)
+               return 0;
+
+       /* run through all completed BDs */
+       for (i = 0, safe2ack = musb_readl(CAST &state->completionPtr, 0);
+                       (safe2ack || completed) && bd && i < NUM_RXCHAN_BD;
+                       i++, bd = bd->next) {
+               u16     len;
+
+               rmb();
+               if (!completed && (bd->hOptions & CPPI_OWN_SET))
+                       break;
+
+               DBG(5, "C/RXBD %08x: nxt %08x buf %08x "
+                       "off.len %08x opt.len %08x (%d)\n",
+                       bd->dma, bd->hNext, bd->buffPtr,
+                       bd->bOffBLen, bd->hOptions,
+                       rx->actualLen);
+
+               /* actual packet received length */
+               if ((bd->hOptions & CPPI_SOP_SET) && !completed)
+                       len = bd->bOffBLen & CPPI_RECV_PKTLEN_MASK;
+               else
+                       len = 0;
+
+               if (bd->hOptions & CPPI_EOQ_MASK)
+                       completed = 1;
+
+               if (!completed && len < bd->enqBuffLen) {
+                       /* NOTE:  when we get a short packet, RXCSR_H_REQPKT
+                        * must have been cleared, and no more DMA packets may
+                        * active be in the queue... TI docs didn't say, but
+                        * CPPI ignores those BDs even though OWN is still set.
+                        */
+                       completed = 1;
+                       DBG(3, "rx short %d/%d (%d)\n",
+                                       len, bd->enqBuffLen, rx->actualLen);
+               }
+
+               /* If we got here, we expect to ack at least one BD; meanwhile
+                * CPPI may completing other BDs while we scan this list...
+                *
+                * RACE: we can notice OWN cleared before CPPI raises the
+                * matching irq by writing that BD as the completion pointer.
+                * In such cases, stop scanning and wait for the irq, avoiding
+                * lost acks and states where BD ownership is unclear.
+                */
+               if (bd->dma == safe2ack) {
+                       musb_writel(CAST &state->completionPtr, 0, safe2ack);
+                       safe2ack = musb_readl(CAST &state->completionPtr, 0);
+                       acked = 1;
+                       if (bd->dma == safe2ack)
+                               safe2ack = 0;
+               }
+
+               rx->actualLen += len;
+
+               cppi_bd_free(rx, last);
+               last = bd;
+
+               /* stop scanning on end-of-segment */
+               if (bd->hNext == 0)
+                       completed = 1;
+       }
+       rx->lastHwBDProcessed = last;
+
+       /* dma abort, lost ack, or ... */
+       if (!acked && last) {
+               int     csr;
+
+               if (safe2ack == 0 || safe2ack == rx->lastHwBDProcessed->dma)
+                       musb_writel(CAST &state->completionPtr, 0, safe2ack);
+               if (safe2ack == 0) {
+                       cppi_bd_free(rx, last);
+                       rx->lastHwBDProcessed = NULL;
+
+                       /* if we land here on the host side, H_REQPKT will
+                        * be clear and we need to restart the queue...
+                        */
+                       WARN_ON(rx->activeQueueHead);
+               }
+               MGC_SelectEnd(cppi->pCoreBase, rx->chNo + 1);
+               csr = musb_readw(regs, MGC_O_HDRC_RXCSR);
+               if (csr & MGC_M_RXCSR_DMAENAB) {
+                       DBG(4, "list%d %p/%p, last %08x%s, csr %04x\n",
+                               rx->chNo,
+                               rx->activeQueueHead, rx->activeQueueTail,
+                               rx->lastHwBDProcessed
+                                       ? rx->lastHwBDProcessed->dma
+                                       : 0,
+                               completed ? ", completed" : "",
+                               csr);
+                       cppi_dump_rxq(4, "/what?", rx);
+               }
+       }
+       if (!completed) {
+               int     csr;
+
+               rx->activeQueueHead = bd;
+
+               /* REVISIT seems like "autoreq all but EOP" doesn't...
+                * setting it here "should" be racey, but seems to work
+                */
+               csr = musb_readw(rx->pEndPt->regs, MGC_O_HDRC_RXCSR);
+               if (is_host_active(cppi->musb)
+                               && bd
+                               && !(csr & MGC_M_RXCSR_H_REQPKT)) {
+                       csr |= MGC_M_RXCSR_H_REQPKT;
+                       musb_writew(regs, MGC_O_HDRC_RXCSR,
+                                       MGC_M_RXCSR_H_WZC_BITS | csr);
+                       csr = musb_readw(rx->pEndPt->regs, MGC_O_HDRC_RXCSR);
+               }
+       } else {
+               rx->activeQueueHead = NULL;
+               rx->activeQueueTail = NULL;
+       }
+
+       cppi_dump_rx(6, rx, completed ? "/completed" : "/cleaned");
+       return completed;
+}
+
+void cppi_completion(struct musb *pThis, u32 rx, u32 tx)
+{
+       void                    *__iomem regBase;
+       int                     i, chanNum, numCompleted;
+       u8                      bReqComplete;
+       struct cppi             *cppi;
+       struct cppi_descriptor  *bdPtr;
+       struct musb_hw_ep       *pEnd = NULL;
+
+       cppi = container_of(pThis->pDmaController, struct cppi, Controller);
+
+       regBase = pThis->ctrl_base;
+
+       chanNum = 0;
+       /* process TX channels */
+       for (chanNum = 0; tx; tx = tx >> 1, chanNum++) {
+               if (tx & 1) {
+                       struct cppi_channel             *txChannel;
+                       struct cppi_tx_stateram         *txState;
+
+                       txChannel = cppi->txCppi + chanNum;
+                       txState = txChannel->stateRam;
+
+                       /* FIXME  need a cppi_tx_scan() routine, which
+                        * can also be called from abort code
+                        */
+
+                       cppi_dump_tx(5, txChannel, "/E");
+
+                       bdPtr = txChannel->activeQueueHead;
+
+                       if (NULL == bdPtr) {
+                               DBG(1, "null BD\n");
+                               continue;
+                       }
+
+                       i = 0;
+                       bReqComplete = 0;
+
+                       numCompleted = 0;
+
+                       /* run through all completed BDs */
+                       for (i = 0;
+                                       !bReqComplete
+                                               && bdPtr
+                                               && i < NUM_TXCHAN_BD;
+                                       i++, bdPtr = bdPtr->next) {
+                               u16     len;
+
+                               rmb();
+                               if (bdPtr->hOptions & CPPI_OWN_SET)
+                                       break;
+
+                               DBG(5, "C/TXBD %p n %x b %x off %x opt %x\n",
+                                               bdPtr, bdPtr->hNext,
+                                               bdPtr->buffPtr,
+                                               bdPtr->bOffBLen,
+                                               bdPtr->hOptions);
+
+                               len = bdPtr->bOffBLen & CPPI_BUFFER_LEN_MASK;
+                               txChannel->actualLen += len;
+
+                               numCompleted++;
+                               txChannel->lastHwBDProcessed = bdPtr;
+
+                               /* write completion register to acknowledge
+                                * processing of completed BDs, and possibly
+                                * release the IRQ; EOQ might not be set ...
+                                *
+                                * REVISIT use the same ack strategy as rx
+                                *
+                                * REVISIT have observed bit 18 set; huh??
+                                */
+//                             if ((bdPtr->hOptions & CPPI_EOQ_MASK))
+                                       txState->completionPtr = bdPtr->dma;
+
+                               /* stop scanning on end-of-segment */
+                               if (bdPtr->hNext == 0)
+                                       bReqComplete = 1;
+                       }
+
+                       /* on end of segment, maybe go to next one */
+                       if (bReqComplete) {
+                               //cppi_dump_tx(4, txChannel, "/complete");
+
+                               /* transfer more, or report completion */
+                               if (txChannel->currOffset
+                                               >= txChannel->transferSize) {
+                                       txChannel->activeQueueHead = NULL;
+                                       txChannel->activeQueueTail = NULL;
+                                       txChannel->Channel.bStatus =
+                                                       MGC_DMA_STATUS_FREE;
+
+                                       pEnd = txChannel->pEndPt;
+
+                                       txChannel->Channel.dwActualLength =
+                                               txChannel->actualLen;
+
+                                       /* Peripheral role never repurposes the
+                                        * endpoint, so immediate completion is
+                                        * safe.  Host role waits for the fifo
+                                        * to empty (TXPKTRDY irq) before going
+                                        * to the next queued bulk transfer.
+                                        */
+                                       if (is_host_active(cppi->musb)) {
+#if 0
+                                               /* WORKAROUND because we may
+                                                * not always get TXKPTRDY ...
+                                                */
+                                               int     csr;
+
+                                               csr = musb_readw(pEnd->regs,
+                                                       MGC_O_HDRC_TXCSR);
+                                               if (csr & MGC_M_TXCSR_TXPKTRDY)
+#endif
+                                                       bReqComplete = 0;
+                                       }
+                                       if (bReqComplete)
+                                               musb_dma_completion(
+                                                       pThis, chanNum + 1, 1);
+
+                               } else {
+                                       /* Bigger transfer than we could fit in
+                                        * that first batch of descriptors...
+                                        */
+                                       cppi_next_tx_segment(pThis, txChannel);
+                               }
+                       } else
+                               txChannel->activeQueueHead = bdPtr;
+               }
+       }
+
+       /* Start processing the RX block */
+       for (chanNum = 0; rx; rx = rx >> 1, chanNum++) {
+
+               if (rx & 1) {
+                       struct cppi_channel             *rxChannel;
+
+                       rxChannel = cppi->rxCppi + chanNum;
+                       bReqComplete = cppi_rx_scan(cppi, chanNum);
+
+                       /* let incomplete dma segments finish */
+                       if (!bReqComplete)
+                               continue;
+
+                       /* start another dma segment if needed */
+                       if (rxChannel->actualLen != rxChannel->transferSize
+                                       && rxChannel->actualLen
+                                               == rxChannel->currOffset) {
+                               cppi_next_rx_segment(pThis, rxChannel, 1);
+                               continue;
+                       }
+
+                       /* all segments completed! */
+                       rxChannel->Channel.bStatus = MGC_DMA_STATUS_FREE;
+
+                       pEnd = rxChannel->pEndPt;
+
+                       rxChannel->Channel.dwActualLength =
+                                       rxChannel->actualLen;
+                       core_rxirq_disable(regBase, chanNum + 1);
+                       musb_dma_completion(pThis, chanNum + 1, 0);
+               }
+       }
+
+       /* write to CPPI EOI register to re-enable interrupts */
+       musb_writel(regBase, DAVINCI_CPPI_EOI_REG, 0);
+}
+
+/* Instantiate a software object representing a DMA controller. */
+struct dma_controller *__init
+dma_controller_create(struct musb *musb, void __iomem *pCoreBase)
+{
+       struct cppi             *pController;
+
+       pController = kzalloc(sizeof *pController, GFP_KERNEL);
+       if (!pController)
+               return NULL;
+
+       /* Initialize the Cppi DmaController  structure */
+       pController->pCoreBase = pCoreBase;
+       pController->musb = musb;
+       pController->Controller.pPrivateData = pController;
+       pController->Controller.start = cppi_controller_start;
+       pController->Controller.stop = cppi_controller_stop;
+       pController->Controller.channel_alloc = cppi_channel_allocate;
+       pController->Controller.channel_release = cppi_channel_release;
+       pController->Controller.channel_program = cppi_channel_program;
+       pController->Controller.channel_abort = cppi_channel_abort;
+
+       /* NOTE: allocating from on-chip SRAM would give the least
+        * contention for memory access, if that ever matters here.
+        */
+
+       /* setup BufferPool */
+       pController->pool = dma_pool_create("cppi",
+                       pController->musb->controller,
+                       sizeof(struct cppi_descriptor),
+                       CPPI_DESCRIPTOR_ALIGN, 0);
+       if (!pController->pool) {
+               kfree(pController);
+               return NULL;
+       }
+
+       return &pController->Controller;
+}
+
+/*
+ *  Destroy a previously-instantiated DMA controller.
+ */
+void dma_controller_destroy(struct dma_controller *c)
+{
+       struct cppi     *cppi;
+
+       cppi = container_of(c, struct cppi, Controller);
+
+       /* assert:  caller stopped the controller first */
+       dma_pool_destroy(cppi->pool);
+
+       kfree(cppi);
+}
+
+/*
+ * Context: controller irqlocked, endpoint selected
+ */
+static int cppi_channel_abort(struct dma_channel *channel)
+{
+       struct cppi_channel     *otgCh;
+       struct cppi             *pController;
+       int                     chNum;
+       void                    *__iomem mbase;
+       void                    *__iomem regBase;
+       void                    *__iomem regs;
+       u32                     regVal;
+       struct cppi_descriptor  *queue;
+
+       otgCh = container_of(channel, struct cppi_channel, Channel);
+
+       pController = otgCh->pController;
+       chNum = otgCh->chNo;
+
+       switch (channel->bStatus) {
+       case MGC_DMA_STATUS_BUS_ABORT:
+       case MGC_DMA_STATUS_CORE_ABORT:
+               /* from RX or TX fault irq handler */
+       case MGC_DMA_STATUS_BUSY:
+               /* the hardware needs shutting down */
+               regs = otgCh->pEndPt->regs;
+               break;
+       case MGC_DMA_STATUS_UNKNOWN:
+       case MGC_DMA_STATUS_FREE:
+               return 0;
+       default:
+               return -EINVAL;
+       }
+
+       if (!otgCh->bTransmit && otgCh->activeQueueHead)
+               cppi_dump_rxq(3, "/abort", otgCh);
+
+       mbase = pController->pCoreBase;
+       regBase = mbase - DAVINCI_BASE_OFFSET;
+
+       queue = otgCh->activeQueueHead;
+       otgCh->activeQueueHead = NULL;
+       otgCh->activeQueueTail = NULL;
+
+       /* REVISIT should rely on caller having done this,
+        * and caller should rely on us not changing it.
+        * peripheral code is safe ... check host too.
+        */
+       MGC_SelectEnd(mbase, chNum + 1);
+
+       if (otgCh->bTransmit) {
+               struct cppi_tx_stateram *__iomem txState;
+               int                     enabled;
+
+               /* mask interrupts raised to signal teardown complete.  */
+               enabled = musb_readl(regBase, DAVINCI_TXCPPI_INTENAB_REG)
+                               & (1 << otgCh->chNo);
+               if (enabled)
+                       musb_writel(regBase, DAVINCI_TXCPPI_INTCLR_REG,
+                                       (1 << otgCh->chNo));
+
+               // REVISIT put timeouts on these controller handshakes
+
+               cppi_dump_tx(6, otgCh, " (teardown)");
+
+               /* teardown DMA engine then usb core */
+               do {
+                       regVal = musb_readl(regBase, DAVINCI_TXCPPI_TEAR_REG);
+               } while (!(regVal & CPPI_TEAR_READY));
+               musb_writel(regBase, DAVINCI_TXCPPI_TEAR_REG, chNum);
+
+               txState = otgCh->stateRam;
+               do {
+                       regVal = txState->completionPtr;
+               } while (0xFFFFFFFC != regVal);
+               txState->completionPtr = 0xFFFFFFFC;
+
+               /* FIXME clean up the transfer state ... here?
+                * the completion routine should get called with
+                * an appropriate status code.
+                */
+
+               regVal = musb_readw(regs, MGC_O_HDRC_TXCSR);
+               regVal &= ~MGC_M_TXCSR_DMAENAB;
+               regVal |= MGC_M_TXCSR_FLUSHFIFO;
+               musb_writew(regs, MGC_O_HDRC_TXCSR, regVal);
+               musb_writew(regs, MGC_O_HDRC_TXCSR, regVal);
+
+               /* re-enable interrupt */
+               if (enabled)
+                       musb_writel(regBase, DAVINCI_TXCPPI_INTENAB_REG,
+                                       (1 << otgCh->chNo));
+
+               txState->headPtr = 0;
+               txState->sopDescPtr = 0;
+               txState->currBuffPtr = 0;
+               txState->currDescPtr = 0;
+               txState->flags = 0;
+               txState->remLength = 0;
+
+               /* Ensure that we clean up any Interrupt asserted
+                * 1. Write to completion Ptr value 0x1(bit 0 set)
+                *    (write back mode)
+                * 2. Write to completion Ptr value 0x0(bit 0 cleared)
+                *    (compare mode)
+                * Value written is compared(for bits 31:2) and being
+                * equal interrupt deasserted?
+                */
+
+               /* write back mode, bit 0 set, hence completion Ptr
+                * must be updated
+                */
+               txState->completionPtr = 0x1;
+               /* compare mode, write back zero now */
+               txState->completionPtr = 0;
+
+               cppi_dump_tx(5, otgCh, " (done teardown)");
+
+               /* REVISIT tx side _should_ clean up the same way
+                * as the RX side ... this does no cleanup at all!
+                */
+
+       } else /* RX */ {
+               u16                     csr;
+
+               /* NOTE: docs don't guarantee any of this works ...  we
+                * expect that if the usb core stops telling the cppi core
+                * to pull more data from it, then it'll be safe to flush
+                * current RX DMA state iff any pending fifo transfer is done.
+                */
+
+               core_rxirq_disable(regBase, otgCh->chNo + 1);
+
+               /* for host, ensure ReqPkt is never set again */
+               if (is_host_active(otgCh->pController->musb)) {
+                       regVal = musb_readl(regBase, DAVINCI_AUTOREQ_REG);
+                       regVal &= ~((0x3) << (otgCh->chNo * 2));
+                       musb_writel(regBase, DAVINCI_AUTOREQ_REG, regVal);
+               }
+
+               csr = musb_readw(regs, MGC_O_HDRC_RXCSR);
+
+               /* for host, clear (just) ReqPkt at end of current packet(s) */
+               if (is_host_active(otgCh->pController->musb)) {
+                       csr |= MGC_M_RXCSR_H_WZC_BITS;
+                       csr &= ~MGC_M_RXCSR_H_REQPKT;
+               } else
+                       csr |= MGC_M_RXCSR_P_WZC_BITS;
+
+               /* clear dma enable */
+               csr &= ~(MGC_M_RXCSR_DMAENAB);
+               musb_writew(regs, MGC_O_HDRC_RXCSR, csr);
+               csr = musb_readw(regs, MGC_O_HDRC_RXCSR);
+
+               /* quiesce: wait for current dma to finish (if not cleanup)
+                * we can't use bit zero of stateram->sopDescPtr since that
+                * refers to an entire "DMA packet" not just emptying the
+                * current fifo; most segments need multiple usb packets.
+                */
+               if (channel->bStatus == MGC_DMA_STATUS_BUSY)
+                       udelay(50);
+
+               /* scan the current list, reporting any data that was
+                * transferred and acking any IRQ
+                */
+               cppi_rx_scan(pController, chNum);
+
+               /* clobber the existing state once it's idle
+                *
+                * NOTE:  arguably, we should also wait for all the other
+                * RX channels to quiesce (how??) and then temporarily
+                * disable RXCPPI_CTRL_REG ... but it seems that we can
+                * rely on the controller restarting from state ram, with
+                * only RXCPPI_BUFCNT state being bogus.  BUFCNT will
+                * correct itself after the next DMA transfer though.
+                *
+                * REVISIT does using rndis mode change that?
+                */
+               cppi_reset_rx(otgCh->stateRam);
+
+               /* next DMA request _should_ load cppi head ptr */
+
+               /* ... we don't "free" that list, only mutate it in place.  */
+               cppi_dump_rx(5, otgCh, " (done abort)");
+
+               /* clean up previously pending bds */
+               cppi_bd_free(otgCh, otgCh->lastHwBDProcessed);
+               otgCh->lastHwBDProcessed = NULL;
+
+               while (queue) {
+                       struct cppi_descriptor  *tmp = queue->next;
+                       cppi_bd_free(otgCh, queue);
+                       queue = tmp;
+               }
+       }
+
+       channel->bStatus = MGC_DMA_STATUS_FREE;
+       otgCh->startAddr = 0;
+       otgCh->currOffset = 0;
+       otgCh->transferSize = 0;
+       otgCh->pktSize = 0;
+       return 0;
+}
+
+/* TBD Queries:
+ *
+ * Power Management ... probably turn off cppi during suspend, restart;
+ * check state ram?  Clocking is presumably shared with usb core.
+ */
diff --git a/drivers/usb/musb/cppi_dma.h b/drivers/usb/musb/cppi_dma.h
new file mode 100644 (file)
index 0000000..21e1cbe
--- /dev/null
@@ -0,0 +1,118 @@
+/* Copyright (C) 2005-2006 by Texas Instruments */
+
+#ifndef _CPPI_DMA_H_
+#define _CPPI_DMA_H_
+
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/dmapool.h>
+
+#include "dma.h"
+#include "musbdefs.h"
+#include "davinci.h"
+
+
+/* hOptions bit masks for CPPI BDs */
+#define CPPI_SOP_SET   ((u32)(1 << 31))
+#define CPPI_EOP_SET   ((u32)(1 << 30))
+#define CPPI_OWN_SET   ((u32)(1 << 29))        /* owned by cppi */
+#define CPPI_EOQ_MASK  ((u32)(1 << 28))
+#define CPPI_ZERO_SET  ((u32)(1 << 23))        /* rx saw zlp; tx issues one */
+#define CPPI_RXABT_MASK        ((u32)(1 << 19))        /* need more rx buffers */
+
+#define CPPI_RECV_PKTLEN_MASK 0xFFFF
+#define CPPI_BUFFER_LEN_MASK 0xFFFF
+
+#define CPPI_TEAR_READY ((u32)(1 << 31))
+
+/* CPPI data structure definitions */
+
+#define        CPPI_DESCRIPTOR_ALIGN   16      // bytes; 5-dec docs say 4-byte align
+
+struct cppi_descriptor {
+       /* Hardware Overlay */
+       u32 hNext;     /**< Next(hardware) Buffer Descriptor Pointer */
+       u32 buffPtr;       /**<Buffer Pointer (dma_addr_t) */
+       u32 bOffBLen;       /**<Buffer_offset16,buffer_length16 */
+       u32 hOptions;       /**<Option fields for SOP,EOP etc*/
+
+       struct cppi_descriptor *next;
+       dma_addr_t dma;         /* address of this descriptor */
+
+       /* for Rx Desc, track original Buffer len to detect short packets */
+       u32 enqBuffLen;
+} __attribute__ ((aligned(CPPI_DESCRIPTOR_ALIGN)));
+
+
+/* forward declaration for CppiDmaController structure */
+struct cppi;
+
+/**
+ *  Channel Control Structure
+ *
+ * CPPI  Channel Control structure. Using he same for Tx/Rx. If need be
+ * derive out of this later.
+ */
+struct cppi_channel {
+       /* First field must be dma_channel for easy type casting
+        * FIXME just use container_of() and be typesafe instead!
+        */
+       struct dma_channel Channel;
+
+       /* back pointer to the Dma Controller structure */
+       struct cppi             *pController;
+
+       /* which direction of which endpoint? */
+       struct musb_hw_ep       *pEndPt;
+       u8                      bTransmit;
+       u8                      chNo;
+
+       /* DMA modes:  RNDIS or "transparent" */
+       u8                      bLastModeRndis;
+
+       /* book keeping for current transfer request */
+       dma_addr_t              startAddr;
+       u32                     transferSize;
+       u32                     pktSize;
+       u32                     currOffset;     /* requested segments */
+       u32                     actualLen;      /* completed (Channel.actual) */
+
+       void __iomem            *stateRam;      /* CPPI state */
+
+       /* BD management fields */
+       struct cppi_descriptor  *bdPoolHead;
+       struct cppi_descriptor  *activeQueueHead;
+       struct cppi_descriptor  *activeQueueTail;
+       struct cppi_descriptor  *lastHwBDProcessed;
+
+       /* use tx_complete in host role to track endpoints waiting for
+        * FIFONOTEMPTY to clear.
+        */
+       struct list_head        tx_complete;
+};
+
+/**
+ *  CPPI Dma Controller Object
+ *
+ *  CPPI Dma controller object.Encapsulates all bookeeping and Data
+ *  structures pertaining to the CPPI Dma Controller.
+ */
+struct cppi {
+       struct dma_controller           Controller;
+       struct musb                     *musb;
+       void __iomem                    *pCoreBase;
+
+       struct cppi_channel             txCppi[MUSB_C_NUM_EPT - 1];
+       struct cppi_channel             rxCppi[MUSB_C_NUM_EPR - 1];
+
+       struct dma_pool                 *pool;
+
+       struct list_head                tx_complete;
+};
+
+/* irq handling hook */
+extern void cppi_completion(struct musb *, u32 rx, u32 tx);
+
+#endif                         /* end of ifndef _CPPI_DMA_H_ */
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
new file mode 100644 (file)
index 0000000..385640b
--- /dev/null
@@ -0,0 +1,461 @@
+/*
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux 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.
+ *
+ * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/memory.h>
+#include <asm/arch/gpio.h>
+#include <asm/mach-types.h>
+
+#include "musbdefs.h"
+
+
+#ifdef CONFIG_MACH_DAVINCI_EVM
+#include <asm/arch/i2c-client.h>
+#endif
+
+#include "davinci.h"
+#include "cppi_dma.h"
+
+
+/* REVISIT (PM) we should be able to keep the PHY in low power mode most
+ * of the time (24 MHZ oscillator and PLL off, etc) by setting POWER.D0
+ * and, when in host mode, autosuspending idle root ports... PHYPLLON
+ * (overriding SUSPENDM?) then likely needs to stay off.
+ */
+
+static inline void phy_on(void)
+{
+       /* start the on-chip PHY and its PLL */
+       __raw_writel(USBPHY_SESNDEN | USBPHY_VBDTCTEN | USBPHY_PHYPLLON,
+                       IO_ADDRESS(USBPHY_CTL_PADDR));
+       while ((__raw_readl(IO_ADDRESS(USBPHY_CTL_PADDR))
+                       & USBPHY_PHYCLKGD) == 0)
+               cpu_relax();
+}
+
+static inline void phy_off(void)
+{
+       /* powerdown the on-chip PHY and its oscillator */
+       __raw_writel(USBPHY_OSCPDWN | USBPHY_PHYPDWN,
+                       IO_ADDRESS(USBPHY_CTL_PADDR));
+}
+
+static int dma_off = 1;
+
+void musb_platform_enable(struct musb *musb)
+{
+       u32     tmp, old, val;
+
+       /* workaround:  setup irqs through both register sets */
+       tmp = (musb->wEndMask & DAVINCI_USB_TX_ENDPTS_MASK)
+                       << DAVINCI_USB_TXINT_SHIFT;
+       musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_SET_REG, tmp);
+       old = tmp;
+       tmp = (musb->wEndMask & (0xfffe & DAVINCI_USB_RX_ENDPTS_MASK))
+                       << DAVINCI_USB_RXINT_SHIFT;
+       musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_SET_REG, tmp);
+       tmp |= old;
+
+       val = ~MGC_M_INTR_SOF;
+       tmp |= ((val & 0x01ff) << DAVINCI_USB_USBINT_SHIFT);
+       musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_SET_REG, tmp);
+
+       if (is_dma_capable() && !dma_off)
+               printk(KERN_WARNING "%s %s: dma not reactivated\n",
+                               __FILE__, __FUNCTION__);
+       else
+               dma_off = 0;
+
+       /* force a DRVVBUS irq so we can start polling for ID change */
+       if (is_otg_enabled(musb))
+               musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG,
+                       DAVINCI_INTR_DRVVBUS << DAVINCI_USB_USBINT_SHIFT);
+}
+
+/*
+ * Disable the HDRC and flush interrupts
+ */
+void musb_platform_disable(struct musb *musb)
+{
+       /* because we don't set CTRLR.UINT, "important" to:
+        *  - not read/write INTRUSB/INTRUSBE
+        *  - (except during initial setup, as workaround)
+        *  - use INTSETR/INTCLRR instead
+        */
+       musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_CLR_REG,
+                         DAVINCI_USB_USBINT_MASK
+                       | DAVINCI_USB_TXINT_MASK
+                       | DAVINCI_USB_RXINT_MASK);
+       musb_writeb(musb->pRegs, MGC_O_HDRC_DEVCTL, 0);
+       musb_writel(musb->ctrl_base, DAVINCI_USB_EOI_REG, 0);
+
+       if (is_dma_capable() && !dma_off)
+               WARN("dma still active\n");
+}
+
+
+/* REVISIT it's not clear whether DaVinci can support full OTG.  */
+
+static int vbus_state = -1;
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+#define        portstate(stmt)         stmt
+#else
+#define        portstate(stmt)
+#endif
+
+
+/* VBUS SWITCHING IS BOARD-SPECIFIC */
+
+#ifdef CONFIG_MACH_DAVINCI_EVM
+#ifndef CONFIG_MACH_DAVINCI_EVM_OTG
+
+/* I2C operations are always synchronous, and require a task context.
+ * With unloaded systems, using the shared workqueue seems to suffice
+ * to satisfy the 100msec A_WAIT_VRISE timeout...
+ */
+static void evm_deferred_drvvbus(struct work_struct *ignored)
+{
+       davinci_i2c_expander_op(0x3a, USB_DRVVBUS, vbus_state);
+       vbus_state = !vbus_state;
+}
+DECLARE_WORK(evm_vbus_work, evm_deferred_drvvbus);
+
+#endif /* modified board */
+#endif /* EVM */
+
+static void davinci_source_power(struct musb *musb, int is_on, int immediate)
+{
+       if (is_on)
+               is_on = 1;
+
+       if (vbus_state == is_on)
+               return;
+       vbus_state = !is_on;            /* 0/1 vs "-1 == unknown/init" */
+
+#ifdef CONFIG_MACH_DAVINCI_EVM
+       if (machine_is_davinci_evm()) {
+#ifdef CONFIG_MACH_DAVINCI_EVM_OTG
+               /* modified EVM board switching VBUS with GPIO(6) not I2C
+                * NOTE:  PINMUX0.RGB888 (bit23) must be clear
+                */
+               if (is_on)
+                       gpio_set(GPIO(6));
+               else
+                       gpio_clear(GPIO(6));
+               immediate = 1;
+#else
+               if (immediate)
+                       davinci_i2c_expander_op(0x3a, USB_DRVVBUS, !is_on);
+               else
+                       schedule_work(&evm_vbus_work);
+#endif
+       }
+#endif
+       if (immediate)
+               vbus_state = is_on;
+}
+
+static void davinci_set_vbus(struct musb *musb, int is_on)
+{
+       WARN_ON(is_on && is_peripheral_active(musb));
+       return davinci_source_power(musb, is_on, 0);
+}
+
+
+#define        POLL_SECONDS    2
+
+static struct timer_list otg_workaround;
+
+static void otg_timer(unsigned long _musb)
+{
+       struct musb             *musb = (void *)_musb;
+       void    *__iomem        mregs = musb->pRegs;
+       u8                      devctl;
+       unsigned long           flags;
+
+       /* We poll because DaVinci's won't expose several OTG-critical
+       * status change events (from the transceiver) otherwise.
+        */
+       devctl = musb_readb(mregs, MGC_O_HDRC_DEVCTL);
+       DBG(7, "poll devctl %02x (%s)\n", devctl, otg_state_string(musb));
+
+       spin_lock_irqsave(&musb->Lock, flags);
+       switch (musb->xceiv.state) {
+       case OTG_STATE_A_WAIT_VFALL:
+               /* Wait till VBUS falls below SessionEnd (~0.2V); the 1.3 RTL
+                * seems to mis-handle session "start" otherwise (or in our
+                * case "recover"), in routine "VBUS was valid by the time
+                * VBUSERR got reported during enumeration" cases.
+                */
+               if (devctl & MGC_M_DEVCTL_VBUS) {
+                       mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+                       break;
+               }
+               musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
+               musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG,
+                       MGC_M_INTR_VBUSERROR << DAVINCI_USB_USBINT_SHIFT);
+               break;
+       case OTG_STATE_B_IDLE:
+               if (!is_peripheral_enabled(musb))
+                       break;
+
+               /* There's no ID-changed IRQ, so we have no good way to tell
+                * when to switch to the A-Default state machine (by setting
+                * the DEVCTL.SESSION flag).
+                *
+                * Workaround:  whenever we're in B_IDLE, try setting the
+                * session flag every few seconds.  If it works, ID was
+                * grounded and we're now in the A-Default state machine.
+                *
+                * NOTE setting the session flag is _supposed_ to trigger
+                * SRP, but clearly it doesn't.
+                */
+               musb_writeb(mregs, MGC_O_HDRC_DEVCTL,
+                               devctl | MGC_M_DEVCTL_SESSION);
+               devctl = musb_readb(mregs, MGC_O_HDRC_DEVCTL);
+               if (devctl & MGC_M_DEVCTL_BDEVICE)
+                       mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+               else
+                       musb->xceiv.state = OTG_STATE_A_IDLE;
+               break;
+       default:
+               break;
+       }
+       spin_unlock_irqrestore(&musb->Lock, flags);
+}
+
+static irqreturn_t davinci_interrupt(int irq, void *__hci)
+{
+       unsigned long   flags;
+       irqreturn_t     retval = IRQ_NONE;
+       struct musb     *musb = __hci;
+       void            *__iomem tibase = musb->ctrl_base;
+       u32             tmp;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+
+       /* NOTE: DaVinci shadows the Mentor IRQs.  Don't manage them through
+        * the Mentor registers (except for setup), use the TI ones and EOI.
+        *
+        * Docs describe irq "vector" registers asociated with the CPPI and
+        * USB EOI registers.  These hold a bitmask corresponding to the
+        * current IRQ, not an irq handler address.  Would using those bits
+        * resolve some of the races observed in this dispatch code??
+        */
+
+       /* CPPI interrupts share the same IRQ line, but have their own
+        * mask, state, "vector", and EOI registers.
+        */
+       if (is_cppi_enabled()) {
+               u32 cppi_tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG);
+               u32 cppi_rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG);
+
+               if (cppi_tx || cppi_rx) {
+                       DBG(4, "CPPI IRQ t%x r%x\n", cppi_tx, cppi_rx);
+                       cppi_completion(musb, cppi_rx, cppi_tx);
+                       retval = IRQ_HANDLED;
+               }
+       }
+
+       /* ack and handle non-CPPI interrupts */
+       tmp = musb_readl(tibase, DAVINCI_USB_INT_SRC_MASKED_REG);
+       musb_writel(tibase, DAVINCI_USB_INT_SRC_CLR_REG, tmp);
+       DBG(4, "IRQ %08x\n", tmp);
+
+       musb->int_rx = (tmp & DAVINCI_USB_RXINT_MASK)
+                       >> DAVINCI_USB_RXINT_SHIFT;
+       musb->int_tx = (tmp & DAVINCI_USB_TXINT_MASK)
+                       >> DAVINCI_USB_TXINT_SHIFT;
+       musb->int_usb = (tmp & DAVINCI_USB_USBINT_MASK)
+                       >> DAVINCI_USB_USBINT_SHIFT;
+
+       /* DRVVBUS irqs are the only proxy we have (a very poor one!) for
+        * DaVinci's missing ID change IRQ.  We need an ID change IRQ to
+        * switch appropriately between halves of the OTG state machine.
+        * Managing DEVCTL.SESSION per Mentor docs requires we know its
+        * value, but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set.
+        * Also, DRVVBUS pulses for SRP (but not at 5V) ...
+        */
+       if (tmp & (DAVINCI_INTR_DRVVBUS << DAVINCI_USB_USBINT_SHIFT)) {
+               int     drvvbus = musb_readl(tibase, DAVINCI_USB_STAT_REG);
+               void    *__iomem mregs = musb->pRegs;
+               u8      devctl = musb_readb(mregs, MGC_O_HDRC_DEVCTL);
+               int     err = musb->int_usb & MGC_M_INTR_VBUSERROR;
+
+               err = is_host_enabled(musb)
+                               && (musb->int_usb & MGC_M_INTR_VBUSERROR);
+               if (err) {
+                       /* The Mentor core doesn't debounce VBUS as needed
+                        * to cope with device connect current spikes. This
+                        * means it's not uncommon for bus-powered devices
+                        * to get VBUS errors during enumeration.
+                        *
+                        * This is a workaround, but newer RTL from Mentor
+                        * seems to lalow a better one: "re"starting sessions
+                        * without waiting (on EVM, a **long** time) for VBUS
+                        * to stop registering in devctl.
+                        */
+                       musb->int_usb &= ~MGC_M_INTR_VBUSERROR;
+                       musb->xceiv.state = OTG_STATE_A_WAIT_VFALL;
+                       mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+                       WARN("VBUS error workaround (delay coming)\n");
+               } else if (is_host_enabled(musb) && drvvbus) {
+                       musb->is_active = 1;
+                       MUSB_HST_MODE(musb);
+                       musb->xceiv.default_a = 1;
+                       musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
+                       portstate(musb->port1_status |= USB_PORT_STAT_POWER);
+                       del_timer(&otg_workaround);
+               } else {
+                       musb->is_active = 0;
+                       MUSB_DEV_MODE(musb);
+                       musb->xceiv.default_a = 0;
+                       musb->xceiv.state = OTG_STATE_B_IDLE;
+                       portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
+               }
+
+               /* NOTE:  this must complete poweron within 100 msec */
+               davinci_source_power(musb, drvvbus, 0);
+               DBG(2, "VBUS %s (%s)%s, devctl %02x\n",
+                               drvvbus ? "on" : "off",
+                               otg_state_string(musb),
+                               err ? " ERROR" : "",
+                               devctl);
+               retval = IRQ_HANDLED;
+       }
+
+       if (musb->int_tx || musb->int_rx || musb->int_usb)
+               retval |= musb_interrupt(musb);
+
+       /* irq stays asserted until EOI is written */
+       musb_writel(tibase, DAVINCI_USB_EOI_REG, 0);
+
+       /* poll for ID change */
+       if (is_otg_enabled(musb)
+                       && musb->xceiv.state == OTG_STATE_B_IDLE)
+               mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+
+       spin_unlock_irqrestore(&musb->Lock, flags);
+
+       /* REVISIT we sometimes get unhandled IRQs
+        * (e.g. ep0).  not clear why...
+        */
+       if (retval != IRQ_HANDLED)
+               DBG(5, "unhandled? %08x\n", tmp);
+       return IRQ_HANDLED;
+}
+
+int __init musb_platform_init(struct musb *musb)
+{
+       void    *__iomem tibase = musb->ctrl_base;
+       u32     revision;
+
+       musb->pRegs += DAVINCI_BASE_OFFSET;
+#if 0
+       /* REVISIT there's something odd about clocking, this
+        * didn't appear do the job ...
+        */
+       musb->clock = clk_get(pDevice, "usb");
+       if (IS_ERR(musb->clock))
+               return PTR_ERR(musb->clock);
+
+       status = clk_enable(musb->clock);
+       if (status < 0)
+               return -ENODEV;
+#endif
+
+       /* returns zero if e.g. not clocked */
+       revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG);
+       if (revision == 0)
+               return -ENODEV;
+
+       if (is_host_enabled(musb))
+               setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
+
+       musb->board_set_vbus = davinci_set_vbus;
+       davinci_source_power(musb, 0, 1);
+
+       /* reset the controller */
+       musb_writel(tibase, DAVINCI_USB_CTRL_REG, 0x1);
+
+       /* start the on-chip PHY and its PLL */
+       phy_on();
+
+       msleep(5);
+
+       /* NOTE:  irqs are in mixed mode, not bypass to pure-musb */
+       pr_debug("DaVinci OTG revision %08x phy %03x control %02x\n",
+               revision,
+               __raw_readl((void *__iomem) IO_ADDRESS(USBPHY_CTL_PADDR)),
+               musb_readb(tibase, DAVINCI_USB_CTRL_REG));
+
+       musb->isr = davinci_interrupt;
+       return 0;
+}
+
+int musb_platform_exit(struct musb *musb)
+{
+       if (is_host_enabled(musb))
+               del_timer_sync(&otg_workaround);
+
+       davinci_source_power(musb, 0 /*off*/, 1);
+
+       /* delay, to avoid problems with module reload */
+       if (is_host_enabled(musb) && musb->xceiv.default_a) {
+               int     maxdelay = 30;
+               u8      devctl, warn = 0;
+
+               /* if there's no peripheral connected, this can take a
+                * long time to fall, especially on EVM with huge C133.
+                */
+               do {
+                       devctl = musb_readb(musb->pRegs, MGC_O_HDRC_DEVCTL);
+                       if (!(devctl & MGC_M_DEVCTL_VBUS))
+                               break;
+                       if ((devctl & MGC_M_DEVCTL_VBUS) != warn) {
+                               warn = devctl & MGC_M_DEVCTL_VBUS;
+                               DBG(1, "VBUS %d\n", warn >> MGC_S_DEVCTL_VBUS);
+                       }
+                       msleep(1000);
+                       maxdelay--;
+               } while (maxdelay > 0);
+
+               /* in OTG mode, another host might be connected */
+               if (devctl & MGC_M_DEVCTL_VBUS)
+                       DBG(1, "VBUS off timeout (devctl %02x)\n", devctl);
+       }
+
+       phy_off();
+       return 0;
+}
diff --git a/drivers/usb/musb/davinci.h b/drivers/usb/musb/davinci.h
new file mode 100644 (file)
index 0000000..b5910ed
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * The Inventra Controller Driver for Linux 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 __MUSB_HDRDF_H__
+#define __MUSB_HDRDF_H__
+
+/*
+ * DaVinci-specific definitions
+ */
+
+/* Integrated highspeed/otg PHY */
+#define        USBPHY_CTL_PADDR        (DAVINCI_SYSTEM_MODULE_BASE + 0x34)
+#define        USBPHY_PHYCLKGD         (1 << 8)
+#define        USBPHY_SESNDEN          (1 << 7)        /* v(sess_end) comparator */
+#define        USBPHY_VBDTCTEN         (1 << 6)        /* v(bus) comparator */
+#define        USBPHY_PHYPLLON         (1 << 4)        /* override pll suspend */
+#define        USBPHY_CLKO1SEL         (1 << 3)
+#define        USBPHY_OSCPDWN          (1 << 2)
+#define        USBPHY_PHYPDWN          (1 << 0)
+
+/* For now include usb OTG module registers here */
+#define DAVINCI_USB_VERSION_REG                0x00
+#define DAVINCI_USB_CTRL_REG           0x04
+#define DAVINCI_USB_STAT_REG           0x08
+#define DAVINCI_RNDIS_REG              0x10
+#define DAVINCI_AUTOREQ_REG            0x14
+#define DAVINCI_USB_INT_SOURCE_REG     0x20
+#define DAVINCI_USB_INT_SET_REG                0x24
+#define DAVINCI_USB_INT_SRC_CLR_REG    0x28
+#define DAVINCI_USB_INT_MASK_REG       0x2c
+#define DAVINCI_USB_INT_MASK_SET_REG   0x30
+#define DAVINCI_USB_INT_MASK_CLR_REG   0x34
+#define DAVINCI_USB_INT_SRC_MASKED_REG 0x38
+#define DAVINCI_USB_EOI_REG            0x3c
+#define DAVINCI_USB_EOI_INTVEC         0x40
+
+/* CPPI related registers */
+#define DAVINCI_TXCPPI_CTRL_REG                0x80
+#define DAVINCI_TXCPPI_TEAR_REG                0x84
+#define DAVINCI_CPPI_EOI_REG           0x88
+#define DAVINCI_CPPI_INTVEC_REG                0x8c
+#define DAVINCI_TXCPPI_MASKED_REG      0x90
+#define DAVINCI_TXCPPI_RAW_REG         0x94
+#define DAVINCI_TXCPPI_INTENAB_REG     0x98
+#define DAVINCI_TXCPPI_INTCLR_REG      0x9c
+
+#define DAVINCI_RXCPPI_CTRL_REG                0xC0
+#define DAVINCI_RXCPPI_MASKED_REG      0xD0
+#define DAVINCI_RXCPPI_RAW_REG         0xD4
+#define DAVINCI_RXCPPI_INTENAB_REG     0xD8
+#define DAVINCI_RXCPPI_INTCLR_REG      0xDC
+
+#define DAVINCI_RXCPPI_BUFCNT0_REG     0xE0
+#define DAVINCI_RXCPPI_BUFCNT1_REG     0xE4
+#define DAVINCI_RXCPPI_BUFCNT2_REG     0xE8
+#define DAVINCI_RXCPPI_BUFCNT3_REG     0xEC
+
+/* CPPI state RAM entries */
+#define DAVINCI_CPPI_STATERAM_BASE_OFFSET   0x100
+
+#define DAVINCI_TXCPPI_STATERAM_OFFSET(channelNum) \
+       (DAVINCI_CPPI_STATERAM_BASE_OFFSET +       ((channelNum)* 0x40))
+#define DAVINCI_RXCPPI_STATERAM_OFFSET(channelNum) \
+       (DAVINCI_CPPI_STATERAM_BASE_OFFSET + 0x20 +((channelNum)* 0x40))
+
+/* CPPI masks */
+#define DAVINCI_DMA_CTRL_ENABLE                1
+#define DAVINCI_DMA_CTRL_DISABLE       0
+
+#define DAVINCI_DMA_ALL_CHANNELS_ENABLE        0xF
+#define DAVINCI_DMA_ALL_CHANNELS_DISABLE 0xF
+
+/* REVISIT relying on "volatile" here is wrong ... */
+
+/* define structures of Rx/Tx stateRam entries */
+struct cppi_tx_stateram {
+       volatile u32 headPtr;
+       volatile u32 sopDescPtr;
+       volatile u32 currDescPtr;
+       volatile u32 currBuffPtr;
+       volatile u32 flags;
+       volatile u32 remLength;
+       volatile u32 dummy;
+       volatile u32 completionPtr;
+};
+
+struct cppi_rx_stateram {
+       volatile u32 buffOffset;
+       volatile u32 headPtr;
+       volatile u32 sopDescPtr;
+       volatile u32 currDescPtr;
+       volatile u32 currBuffPtr;
+       volatile u32 pktLength;
+       volatile u32 byteCount;
+       volatile u32 completionPtr;
+};
+
+#define DAVINCI_USB_TX_ENDPTS_MASK     0x1f            /* ep0 + 4 tx */
+#define DAVINCI_USB_RX_ENDPTS_MASK     0x1e            /* 4 rx */
+
+#define DAVINCI_USB_USBINT_SHIFT       16
+#define DAVINCI_USB_TXINT_SHIFT                0
+#define DAVINCI_USB_RXINT_SHIFT                8
+
+#define DAVINCI_INTR_DRVVBUS           0x0100
+
+#define DAVINCI_USB_USBINT_MASK                0x01ff0000      /* 8 Mentor, DRVVBUS */
+#define DAVINCI_USB_TXINT_MASK \
+       (DAVINCI_USB_TX_ENDPTS_MASK << DAVINCI_USB_TXINT_SHIFT)
+#define DAVINCI_USB_RXINT_MASK \
+       (DAVINCI_USB_RX_ENDPTS_MASK << DAVINCI_USB_RXINT_SHIFT)
+
+#define DAVINCI_BASE_OFFSET            0x400
+
+#endif /* __MUSB_HDRDF_H__ */
diff --git a/drivers/usb/musb/debug.h b/drivers/usb/musb/debug.h
new file mode 100644 (file)
index 0000000..ef0c4a7
--- /dev/null
@@ -0,0 +1,65 @@
+/******************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux 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.
+ *
+ * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+#ifndef __MUSB_LINUX_DEBUG_H__
+#define __MUSB_LINUX_DEBUG_H__
+
+#define yprintk(facility, format, args...) \
+       do { printk(facility "%s %d: " format , \
+       __FUNCTION__, __LINE__ , ## args); } while (0)
+#define WARN(fmt, args...) yprintk(KERN_WARNING,fmt, ## args)
+#define INFO(fmt,args...) yprintk(KERN_INFO,fmt, ## args)
+#define ERR(fmt,args...) yprintk(KERN_ERR,fmt, ## args)
+
+#define xprintk(level, facility, format, args...) do { \
+       if ( _dbg_level(level) ) { \
+               printk(facility "%s %d: " format , \
+                               __FUNCTION__, __LINE__ , ## args); \
+       } } while (0)
+
+#if MUSB_DEBUG > 0
+extern unsigned debug;
+#else
+#define debug  0
+#endif
+
+static inline int _dbg_level(unsigned l)
+{
+       return debug >= l;
+}
+
+#define DBG(level,fmt,args...) xprintk(level,KERN_DEBUG,fmt, ## args)
+
+extern const char *otg_state_string(struct musb *);
+
+#endif                         //  __MUSB_LINUX_DEBUG_H__
diff --git a/drivers/usb/musb/dma.h b/drivers/usb/musb/dma.h
new file mode 100644 (file)
index 0000000..cececd9
--- /dev/null
@@ -0,0 +1,186 @@
+/******************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux 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.
+ *
+ * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+#ifndef __MUSB_DMA_H__
+#define __MUSB_DMA_H__
+
+struct musb_hw_ep;
+
+/*
+ * DMA Controller Abstraction
+ *
+ * DMA Controllers are abstracted to allow use of a variety of different
+ * implementations of DMA, as allowed by the Inventra USB cores.  On the
+ * host side, usbcore sets up the DMA mappings and flushes caches; on the
+ * peripheral side, the gadget controller driver does.  Responsibilities
+ * of a DMA controller driver include:
+ *
+ *  - Handling the details of moving multiple USB packets
+ *    in cooperation with the Inventra USB core, including especially
+ *    the correct RX side treatment of short packets and buffer-full
+ *    states (both of which terminate transfers).
+ *
+ *  - Knowing the correlation between dma channels and the
+ *    Inventra core's local endpoint resources and data direction.
+ *
+ *  - Maintaining a list of allocated/available channels.
+ *
+ *  - Updating channel status on interrupts,
+ *    whether shared with the Inventra core or separate.
+ */
+
+#define        DMA_ADDR_INVALID        (~(dma_addr_t)0)
+
+#ifndef CONFIG_USB_INVENTRA_FIFO
+#define        is_dma_capable()        (1)
+#else
+#define        is_dma_capable()        (0)
+#endif
+
+#ifdef CONFIG_USB_TI_CPPI_DMA
+#define        is_cppi_enabled()       1
+#else
+#define        is_cppi_enabled()       0
+#endif
+
+
+/*
+ * DMA channel status ... updated by the dma controller driver whenever that
+ * status changes, and protected by the overall controller spinlock.
+ */
+enum dma_channel_status {
+       /* unallocated */
+       MGC_DMA_STATUS_UNKNOWN,
+       /* allocated ... but not busy, no errors */
+       MGC_DMA_STATUS_FREE,
+       /* busy ... transactions are active */
+       MGC_DMA_STATUS_BUSY,
+       /* transaction(s) aborted due to ... dma or memory bus error */
+       MGC_DMA_STATUS_BUS_ABORT,
+       /* transaction(s) aborted due to ... core error or USB fault */
+       MGC_DMA_STATUS_CORE_ABORT
+};
+
+struct dma_controller;
+
+/**
+ * struct dma_channel - A DMA channel.
+ * @pPrivateData: channel-private data
+ * @wMaxLength: the maximum number of bytes the channel can move in one
+ *     transaction (typically representing many USB maximum-sized packets)
+ * @dwActualLength: how many bytes have been transferred
+ * @bStatus: current channel status (updated e.g. on interrupt)
+ * @bDesiredMode: TRUE if mode 1 is desired; FALSE if mode 0 is desired
+ *
+ * channels are associated with an endpoint for the duration of at least
+ * one usb transfer.
+ */
+struct dma_channel {
+       void                    *pPrivateData;
+       // FIXME not void* private_data, but a dma_controller *
+       size_t                  dwMaxLength;
+       size_t                  dwActualLength;
+       enum dma_channel_status bStatus;
+       u8                      bDesiredMode;
+};
+
+/*
+ * Program a DMA channel to move data at the core's request.
+ * The local core endpoint and direction should already be known,
+ * since they are specified in the channel_alloc call.
+ *
+ * @channel: pointer to a channel obtained by channel_alloc
+ * @maxpacket: the maximum packet size
+ * @bMode: TRUE if mode 1; FALSE if mode 0
+ * @dma_addr: base address of data (in DMA space)
+ * @length: the number of bytes to transfer; no larger than the channel's
+ *     reported dwMaxLength
+ *
+ * Returns TRUE on success, else FALSE
+ */
+typedef int (*MGC_pfDmaProgramChannel) (
+               struct dma_channel      *channel,
+               u16                     maxpacket,
+               u8                      bMode,
+               dma_addr_t              dma_addr,
+               u32                     length);
+
+/*
+ * dma_channel_status - return status of dma channel
+ * @c: the channel
+ *
+ * Returns the software's view of the channel status.  If that status is BUSY
+ * then it's possible that the hardware has completed (or aborted) a transfer,
+ * so the driver needs to update that status.
+ */
+static inline enum dma_channel_status
+dma_channel_status(struct dma_channel *c)
+{
+       return (is_dma_capable() && c) ? c->bStatus : MGC_DMA_STATUS_UNKNOWN;
+}
+
+/**
+ * struct dma_controller - A DMA Controller.
+ * @pPrivateData: controller-private data;
+ * @start: call this to start a DMA controller;
+ *     return 0 on success, else negative errno
+ * @stop: call this to stop a DMA controller
+ *     return 0 on success, else negative errno
+ * @channel_alloc: call this to allocate a DMA channel
+ * @channel_release: call this to release a DMA channel
+ * @channel_abort: call this to abort a pending DMA transaction,
+ *     returning it to FREE (but allocated) state
+ *
+ * Controllers manage dma channels.
+ */
+struct dma_controller {
+       void                    *pPrivateData;
+       int                     (*start)(struct dma_controller *);
+       int                     (*stop)(struct dma_controller *);
+       struct dma_channel      *(*channel_alloc)(struct dma_controller *,
+                                       struct musb_hw_ep *, u8 is_tx);
+       void                    (*channel_release)(struct dma_channel *);
+       MGC_pfDmaProgramChannel channel_program;
+       int                     (*channel_abort)(struct dma_channel *);
+};
+
+/* called after channel_program(), may indicate a fault */
+extern void musb_dma_completion(struct musb *musb, u8 bLocalEnd, u8 bTransmit);
+
+
+extern struct dma_controller *__init
+dma_controller_create(struct musb *, void __iomem *);
+
+extern void dma_controller_destroy(struct dma_controller *);
+
+#endif /* __MUSB_DMA_H__ */
diff --git a/drivers/usb/musb/g_ep0.c b/drivers/usb/musb/g_ep0.c
new file mode 100644 (file)
index 0000000..c4cb544
--- /dev/null
@@ -0,0 +1,970 @@
+/******************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux 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.
+ *
+ * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+
+#include "musbdefs.h"
+
+/* ep0 is always musb->aLocalEnd[0].ep_in */
+#define        next_ep0_request(musb)  next_in_request(&(musb)->aLocalEnd[0])
+
+/*
+ * Locking note:  we use only the controller lock, for simpler correctness.
+ * It's always held with IRQs blocked.
+ *
+ * It protects the ep0 request queue as well as ep0_state, not just the
+ * controller and indexed registers.  And that lock stays held unless it
+ * needs to be dropped to allow reentering this driver ... like upcalls to
+ * the gadget driver, or adjusting endpoint halt status.
+ */
+
+static char *decode_ep0stage(u8 stage)
+{
+       switch(stage) {
+       case MGC_END0_STAGE_SETUP:      return "idle";
+       case MGC_END0_STAGE_TX:         return "in";
+       case MGC_END0_STAGE_RX:         return "out";
+       case MGC_END0_STAGE_ACKWAIT:    return "wait";
+       case MGC_END0_STAGE_STATUSIN:   return "in/status";
+       case MGC_END0_STAGE_STATUSOUT:  return "out/status";
+       default:                        return "?";
+       }
+}
+
+/* handle a standard GET_STATUS request
+ * Context:  caller holds controller lock
+ */
+static int service_tx_status_request(
+       struct musb *pThis,
+       const struct usb_ctrlrequest *pControlRequest)
+{
+       void __iomem    *pBase = pThis->pRegs;
+       int handled = 1;
+       u8 bResult[2], bEnd = 0;
+       const u8 bRecip = pControlRequest->bRequestType & USB_RECIP_MASK;
+
+       bResult[1] = 0;
+
+       switch (bRecip) {
+       case USB_RECIP_DEVICE:
+               bResult[0] = pThis->bIsSelfPowered << USB_DEVICE_SELF_POWERED;
+               bResult[0] |= pThis->bMayWakeup << USB_DEVICE_REMOTE_WAKEUP;
+#ifdef CONFIG_USB_MUSB_OTG
+               if (pThis->g.is_otg) {
+                       bResult[0] |= pThis->g.b_hnp_enable
+                               << USB_DEVICE_B_HNP_ENABLE;
+                       bResult[0] |= pThis->g.a_alt_hnp_support
+                               << USB_DEVICE_A_ALT_HNP_SUPPORT;
+                       bResult[0] |= pThis->g.a_hnp_support
+                               << USB_DEVICE_A_HNP_SUPPORT;
+               }
+#endif
+               break;
+
+       case USB_RECIP_INTERFACE:
+               bResult[0] = 0;
+               break;
+
+       case USB_RECIP_ENDPOINT: {
+               int             is_in;
+               struct musb_ep  *ep;
+               u16             tmp;
+               void __iomem    *regs;
+
+               bEnd = (u8) pControlRequest->wIndex;
+               if (!bEnd) {
+                       bResult[0] = 0;
+                       break;
+               }
+
+               is_in = bEnd & USB_DIR_IN;
+               if (is_in) {
+                       bEnd &= 0x0f;
+                       ep = &pThis->aLocalEnd[bEnd].ep_in;
+               } else {
+                       ep = &pThis->aLocalEnd[bEnd].ep_out;
+               }
+               regs = pThis->aLocalEnd[bEnd].regs;
+
+               if (bEnd >= MUSB_C_NUM_EPS || !ep->desc) {
+                       handled = -EINVAL;
+                       break;
+               }
+
+               MGC_SelectEnd(pBase, bEnd);
+               if (is_in)
+                       tmp = musb_readw(regs, MGC_O_HDRC_TXCSR)
+                                               & MGC_M_TXCSR_P_SENDSTALL;
+               else
+                       tmp = musb_readw(regs, MGC_O_HDRC_RXCSR)
+                                               & MGC_M_RXCSR_P_SENDSTALL;
+               MGC_SelectEnd(pBase, 0);
+
+               bResult[0] = tmp ? 1 : 0;
+               } break;
+
+       default:
+               /* class, vendor, etc ... delegate */
+               handled = 0;
+               break;
+       }
+
+       /* fill up the fifo; caller updates csr0 */
+       if (handled > 0) {
+               u16     len = le16_to_cpu(pControlRequest->wLength);
+
+               if (len > 2)
+                       len = 2;
+               musb_write_fifo(&pThis->aLocalEnd[0], len, bResult);
+       }
+
+       return handled;
+}
+
+/*
+ * handle a control-IN request, the end0 buffer contains the current request
+ * that is supposed to be a standard control request. Assumes the fifo to
+ * be at least 2 bytes long.
+ *
+ * @return 0 if the request was NOT HANDLED,
+ * < 0 when error
+ * > 0 when the request is processed
+ *
+ * Context:  caller holds controller lock
+ */
+static int
+service_in_request(struct musb *pThis,
+               const struct usb_ctrlrequest *pControlRequest)
+{
+       int handled = 0;        /* not handled */
+
+       if ((pControlRequest->bRequestType & USB_TYPE_MASK)
+                       == USB_TYPE_STANDARD) {
+               switch (pControlRequest->bRequest) {
+               case USB_REQ_GET_STATUS:
+                       handled = service_tx_status_request(pThis,
+                                       pControlRequest);
+                       break;
+
+               /* case USB_REQ_SYNC_FRAME: */
+
+               default:
+                       break;
+               }
+       }
+       return handled;
+}
+
+/*
+ * Context:  caller holds controller lock
+ */
+static void musb_g_ep0_giveback(struct musb *pThis, struct usb_request *req)
+{
+       pThis->ep0_state = MGC_END0_STAGE_SETUP;
+       musb_g_giveback(&pThis->aLocalEnd[0].ep_in, req, 0);
+}
+
+/*
+ * Handle all control requests with no DATA stage, including standard
+ * requests such as:
+ * USB_REQ_SET_CONFIGURATION, USB_REQ_SET_INTERFACE, unrecognized
+ *     always delegated to the gadget driver
+ * USB_REQ_SET_ADDRESS, USB_REQ_CLEAR_FEATURE, USB_REQ_SET_FEATURE
+ *     always handled here, except for class/vendor/... features
+ *
+ * Context:  caller holds controller lock
+ */
+static int
+service_zero_data_request(struct musb *pThis,
+               struct usb_ctrlrequest *pControlRequest)
+__releases(pThis->Lock)
+__acquires(pThis->Lock)
+{
+       int handled = -EINVAL;
+       void __iomem *pBase = pThis->pRegs;
+       const u8 bRecip = pControlRequest->bRequestType & USB_RECIP_MASK;
+
+       /* the gadget driver handles everything except what we MUST handle */
+       if ((pControlRequest->bRequestType & USB_TYPE_MASK)
+                       == USB_TYPE_STANDARD) {
+               switch (pControlRequest->bRequest) {
+               case USB_REQ_SET_ADDRESS:
+                       /* change it after the status stage */
+                       pThis->bSetAddress = TRUE;
+                       pThis->bAddress = (u8) (pControlRequest->wValue & 0x7f);
+                       handled = 1;
+                       break;
+
+               case USB_REQ_CLEAR_FEATURE:
+                       switch (bRecip) {
+                       case USB_RECIP_DEVICE:
+                               if (pControlRequest->wValue
+                                               != USB_DEVICE_REMOTE_WAKEUP)
+                                       break;
+                               pThis->bMayWakeup = 0;
+                               handled = 1;
+                               break;
+                       case USB_RECIP_INTERFACE:
+                               break;
+                       case USB_RECIP_ENDPOINT:{
+                               const u8 bEnd = pControlRequest->wIndex & 0x0f;
+                               struct musb_ep *pEnd;
+
+                               if (bEnd == 0
+                                               || bEnd >= MUSB_C_NUM_EPS
+                                               || pControlRequest->wValue
+                                                       != USB_ENDPOINT_HALT)
+                                       break;
+
+                               if (pControlRequest->wIndex & USB_DIR_IN)
+                                       pEnd = &pThis->aLocalEnd[bEnd].ep_in;
+                               else
+                                       pEnd = &pThis->aLocalEnd[bEnd].ep_out;
+                               if (!pEnd->desc)
+                                       break;
+
+                               /* REVISIT do it directly, no locking games */
+                               spin_unlock(&pThis->Lock);
+                               musb_gadget_set_halt(&pEnd->end_point, 0);
+                               spin_lock(&pThis->Lock);
+
+                               /* select ep0 again */
+                               MGC_SelectEnd(pBase, 0);
+                               handled = 1;
+                               } break;
+                       default:
+                               /* class, vendor, etc ... delegate */
+                               handled = 0;
+                               break;
+                       }
+                       break;
+
+               case USB_REQ_SET_FEATURE:
+                       switch (bRecip) {
+                       case USB_RECIP_DEVICE:
+                               handled = 1;
+                               switch (pControlRequest->wValue) {
+                               case USB_DEVICE_REMOTE_WAKEUP:
+                                       pThis->bMayWakeup = 1;
+                                       break;
+                               case USB_DEVICE_TEST_MODE:
+                                       if (pThis->g.speed != USB_SPEED_HIGH)
+                                               goto stall;
+                                       if (pControlRequest->wIndex & 0xff)
+                                               goto stall;
+
+                                       switch (pControlRequest->wIndex >> 8) {
+                                       case 1:
+                                               pr_debug("TEST_J\n");
+                                               /* TEST_J */
+                                               pThis->bTestModeValue =
+                                                       MGC_M_TEST_J;
+                                               break;
+                                       case 2:
+                                               /* TEST_K */
+                                               pr_debug("TEST_K\n");
+                                               pThis->bTestModeValue =
+                                                       MGC_M_TEST_K;
+                                               break;
+                                       case 3:
+                                               /* TEST_SE0_NAK */
+                                               pr_debug("TEST_SE0_NAK\n");
+                                               pThis->bTestModeValue =
+                                                       MGC_M_TEST_SE0_NAK;
+                                               break;
+                                       case 4:
+                                               /* TEST_PACKET */
+                                               pr_debug("TEST_PACKET\n");
+                                               pThis->bTestModeValue =
+                                                       MGC_M_TEST_PACKET;
+                                               break;
+                                       default:
+                                               goto stall;
+                                       }
+
+                                       /* enter test mode after irq */
+                                       if (handled > 0)
+                                               pThis->bTestMode = TRUE;
+                                       break;
+#ifdef CONFIG_USB_MUSB_OTG
+                               case USB_DEVICE_B_HNP_ENABLE:
+                                       if (!pThis->g.is_otg)
+                                               goto stall;
+                                       { u8 devctl;
+                                       pThis->g.b_hnp_enable = 1;
+                                       devctl = musb_readb(pBase,
+                                                       MGC_O_HDRC_DEVCTL);
+                                       musb_writeb(pBase, MGC_O_HDRC_DEVCTL,
+                                               devctl | MGC_M_DEVCTL_HR);
+                                       }
+                                       break;
+                               case USB_DEVICE_A_HNP_SUPPORT:
+                                       if (!pThis->g.is_otg)
+                                               goto stall;
+                                       pThis->g.a_hnp_support = 1;
+                                       break;
+                               case USB_DEVICE_A_ALT_HNP_SUPPORT:
+                                       if (!pThis->g.is_otg)
+                                               goto stall;
+                                       pThis->g.a_alt_hnp_support = 1;
+                                       break;
+#endif
+stall:
+                               default:
+                                       handled = -EINVAL;
+                                       break;
+                               }
+                               break;
+
+                       case USB_RECIP_INTERFACE:
+                               break;
+
+                       case USB_RECIP_ENDPOINT:{
+                               const u8                bEnd =
+                                       pControlRequest->wIndex & 0x0f;
+                               struct musb_ep          *pEnd;
+                               struct musb_hw_ep       *ep;
+                               void __iomem            *regs;
+                               int                     is_in;
+                               u16                     csr;
+
+                               if (bEnd == 0
+                                               || bEnd >= MUSB_C_NUM_EPS
+                                               || pControlRequest->wValue
+                                                       != USB_ENDPOINT_HALT)
+                                       break;
+
+                               ep = pThis->aLocalEnd + bEnd;
+                               regs = ep->regs;
+                               is_in = pControlRequest->wIndex & USB_DIR_IN;
+                               if (is_in)
+                                       pEnd = &ep->ep_in;
+                               else
+                                       pEnd = &ep->ep_out;
+                               if (!pEnd->desc)
+                                       break;
+
+                               MGC_SelectEnd(pBase, bEnd);
+                               if (is_in) {
+                                       csr = musb_readw(regs,
+                                                       MGC_O_HDRC_TXCSR);
+                                       if (csr & MGC_M_TXCSR_FIFONOTEMPTY)
+                                               csr |= MGC_M_TXCSR_FLUSHFIFO;
+                                       csr |= MGC_M_TXCSR_P_SENDSTALL
+                                               | MGC_M_TXCSR_CLRDATATOG
+                                               | MGC_M_TXCSR_P_WZC_BITS;
+                                       musb_writew(regs, MGC_O_HDRC_TXCSR,
+                                                       csr);
+                               } else {
+                                       csr = musb_readw(regs,
+                                                       MGC_O_HDRC_RXCSR);
+                                       csr |= MGC_M_RXCSR_P_SENDSTALL
+                                               | MGC_M_RXCSR_FLUSHFIFO
+                                               | MGC_M_RXCSR_CLRDATATOG
+                                               | MGC_M_TXCSR_P_WZC_BITS;
+                                       musb_writew(regs, MGC_O_HDRC_RXCSR,
+                                                       csr);
+                               }
+
+                               /* select ep0 again */
+                               MGC_SelectEnd(pBase, 0);
+                               handled = 1;
+                               } break;
+
+                       default:
+                               /* class, vendor, etc ... delegate */
+                               handled = 0;
+                               break;
+                       }
+                       break;
+               default:
+                       /* delegate SET_CONFIGURATION, etc */
+                       handled = 0;
+               }
+       } else
+               handled = 0;
+       return handled;
+}
+
+/* we have an ep0out data packet
+ * Context:  caller holds controller lock
+ */
+static void ep0_rxstate(struct musb *this)
+{
+       void __iomem            *regs = this->control_ep->regs;
+       struct usb_request      *req;
+       u16                     tmp;
+
+       req = next_ep0_request(this);
+
+       /* read packet and ack; or stall because of gadget driver bug:
+        * should have provided the rx buffer before setup() returned.
+        */
+       if (req) {
+               void            *buf = req->buf + req->actual;
+               unsigned        len = req->length - req->actual;
+
+               /* read the buffer */
+               tmp = musb_readb(regs, MGC_O_HDRC_COUNT0);
+               if (tmp > len) {
+                       req->status = -EOVERFLOW;
+                       tmp = len;
+               }
+               musb_read_fifo(&this->aLocalEnd[0], tmp, buf);
+               req->actual += tmp;
+               tmp = MGC_M_CSR0_P_SVDRXPKTRDY;
+               if (tmp < 64 || req->actual == req->length) {
+                       this->ep0_state = MGC_END0_STAGE_STATUSIN;
+                       tmp |= MGC_M_CSR0_P_DATAEND;
+               } else
+                       req = NULL;
+       } else
+               tmp = MGC_M_CSR0_P_SVDRXPKTRDY | MGC_M_CSR0_P_SENDSTALL;
+       musb_writew(regs, MGC_O_HDRC_CSR0, tmp);
+
+
+       /* NOTE:  we "should" hold off reporting DATAEND and going to
+        * STATUSIN until after the completion handler decides whether
+        * to issue a stall instead, since this hardware can do that.
+        */
+       if (req)
+               musb_g_ep0_giveback(this, req);
+}
+
+/*
+ * transmitting to the host (IN), this code might be called from IRQ
+ * and from kernel thread.
+ *
+ * Context:  caller holds controller lock
+ */
+static void ep0_txstate(struct musb *pThis)
+{
+       void __iomem            *regs = pThis->control_ep->regs;
+       struct usb_request      *pRequest = next_ep0_request(pThis);
+       u16                     wCsrVal = MGC_M_CSR0_TXPKTRDY;
+       u8                      *pFifoSource;
+       u8                      wFifoCount;
+
+       if (!pRequest) {
+               // WARN_ON(1);
+               DBG(2, "odd; csr0 %04x\n", musb_readw(regs, MGC_O_HDRC_CSR0));
+               return;
+       }
+
+       /* load the data */
+       pFifoSource = (u8 *) pRequest->buf + pRequest->actual;
+       wFifoCount = min((unsigned) MGC_END0_FIFOSIZE,
+               pRequest->length - pRequest->actual);
+       musb_write_fifo(&pThis->aLocalEnd[0], wFifoCount, pFifoSource);
+       pRequest->actual += wFifoCount;
+
+       /* update the flags */
+       if (wFifoCount < MUSB_MAX_END0_PACKET
+                       || pRequest->actual == pRequest->length) {
+               pThis->ep0_state = MGC_END0_STAGE_STATUSOUT;
+               wCsrVal |= MGC_M_CSR0_P_DATAEND;
+       } else
+               pRequest = NULL;
+
+       /* send it out, triggering a "txpktrdy cleared" irq */
+       musb_writew(regs, MGC_O_HDRC_CSR0, wCsrVal);
+
+       /* report completions as soon as the fifo's loaded; there's no
+        * win in waiting till this last packet gets acked.  (other than
+        * very precise fault reporting, needed by USB TMC; possible with
+        * this hardware, but not usable from portable gadget drivers.)
+        */
+       if (pRequest)
+               musb_g_ep0_giveback(pThis, pRequest);
+}
+
+/*
+ * Read a SETUP packet (struct usb_ctrlrequest) from the hardware.
+ * Fields are left in USB byte-order.
+ *
+ * Context:  caller holds controller lock.
+ */
+static void
+musb_read_setup(struct musb *pThis, struct usb_ctrlrequest *req)
+{
+       struct usb_request      *r;
+       void __iomem            *regs = pThis->control_ep->regs;
+
+       musb_read_fifo(&pThis->aLocalEnd[0], sizeof *req, (u8 *)req);
+
+       /* NOTE:  earlier 2.6 versions changed setup packets to host
+        * order, but now USB packets always stay in USB byte order.
+        */
+       DBG(3, "SETUP req%02x.%02x v%04x i%04x l%d\n",
+               req->bRequestType,
+               req->bRequest,
+               le16_to_cpu(req->wValue),
+               le16_to_cpu(req->wIndex),
+               le16_to_cpu(req->wLength));
+
+       /* clean up any leftover transfers */
+       r = next_ep0_request(pThis);
+       if (r)
+               musb_g_ep0_giveback(pThis, r);
+
+       /* For zero-data requests we want to delay the STATUS stage to
+        * avoid SETUPEND errors.  If we read data (OUT), delay accepting
+        * packets until there's a buffer to store them in.
+        *
+        * If we write data, the controller acts happier if we enable
+        * the TX FIFO right away, and give the controller a moment
+        * to switch modes...
+        */
+       pThis->bSetAddress = FALSE;
+       pThis->ackpend = MGC_M_CSR0_P_SVDRXPKTRDY;
+       if (req->wLength == 0) {
+               if (req->bRequestType & USB_DIR_IN)
+                       pThis->ackpend |= MGC_M_CSR0_TXPKTRDY;
+               pThis->ep0_state = MGC_END0_STAGE_ACKWAIT;
+       } else if (req->bRequestType & USB_DIR_IN) {
+               pThis->ep0_state = MGC_END0_STAGE_TX;
+               musb_writew(regs, MGC_O_HDRC_CSR0, MGC_M_CSR0_P_SVDRXPKTRDY);
+               while ((musb_readw(regs, MGC_O_HDRC_CSR0)
+                               & MGC_M_CSR0_RXPKTRDY) != 0)
+                       cpu_relax();
+               pThis->ackpend = 0;
+       } else
+               pThis->ep0_state = MGC_END0_STAGE_RX;
+}
+
+static int
+forward_to_driver(struct musb *musb,
+               const struct usb_ctrlrequest *pControlRequest)
+__releases(musb->Lock)
+__acquires(musb->Lock)
+{
+       int retval;
+       if (!musb->pGadgetDriver)
+               return -EOPNOTSUPP;
+       spin_unlock(&musb->Lock);
+       retval = musb->pGadgetDriver->setup(&musb->g, pControlRequest);
+       spin_lock(&musb->Lock);
+       return retval;
+}
+
+/*
+ * Handle peripheral ep0 interrupt
+ * @param pThis this
+ *
+ * Context: irq handler; we won't re-enter the driver that way.
+ */
+irqreturn_t musb_g_ep0_irq(struct musb *pThis)
+{
+       u16             wCsrVal;
+       u16             wCount;
+       void __iomem    *pBase = pThis->pRegs;
+       void __iomem    *regs = pThis->aLocalEnd[0].regs;
+       irqreturn_t     retval = IRQ_NONE;
+
+       MGC_SelectEnd(pBase, 0);        /* select ep0 */
+       wCsrVal = musb_readw(regs, MGC_O_HDRC_CSR0);
+       wCount = musb_readb(regs, MGC_O_HDRC_COUNT0);
+
+       DBG(4, "csr %04x, count %d, myaddr %d, ep0stage %s\n",
+                       wCsrVal, wCount,
+                       musb_readb(pBase, MGC_O_HDRC_FADDR),
+                       decode_ep0stage(pThis->ep0_state));
+
+       /* I sent a stall.. need to acknowledge it now.. */
+       if (wCsrVal & MGC_M_CSR0_P_SENTSTALL) {
+               musb_writew(regs, MGC_O_HDRC_CSR0,
+                               wCsrVal & ~MGC_M_CSR0_P_SENTSTALL);
+               retval = IRQ_HANDLED;
+               pThis->ep0_state = MGC_END0_STAGE_SETUP;
+               wCsrVal = musb_readw(regs, MGC_O_HDRC_CSR0);
+       }
+
+       /* request ended "early" */
+       if (wCsrVal & MGC_M_CSR0_P_SETUPEND) {
+               musb_writew(regs, MGC_O_HDRC_CSR0, MGC_M_CSR0_P_SVDSETUPEND);
+               retval = IRQ_HANDLED;
+               pThis->ep0_state = MGC_END0_STAGE_SETUP;
+               wCsrVal = musb_readw(regs, MGC_O_HDRC_CSR0);
+               /* NOTE:  request may need completion */
+       }
+
+       /* docs from Mentor only describe tx, rx, and idle/setup states.
+        * we need to handle nuances around status stages, and also the
+        * case where status and setup stages come back-to-back ...
+        */
+       switch (pThis->ep0_state) {
+
+       case MGC_END0_STAGE_TX:
+               /* irq on clearing txpktrdy */
+               if ((wCsrVal & MGC_M_CSR0_TXPKTRDY) == 0) {
+                       ep0_txstate(pThis);
+                       retval = IRQ_HANDLED;
+               }
+               break;
+
+       case MGC_END0_STAGE_RX:
+               /* irq on set rxpktrdy */
+               if (wCsrVal & MGC_M_CSR0_RXPKTRDY) {
+                       ep0_rxstate(pThis);
+                       retval = IRQ_HANDLED;
+               }
+               break;
+
+       case MGC_END0_STAGE_STATUSIN:
+               /* end of sequence #2 (OUT/RX state) or #3 (no data) */
+
+               /* update address (if needed) only @ the end of the
+                * status phase per usb spec, which also guarantees
+                * we get 10 msec to receive this irq... until this
+                * is done we won't see the next packet.
+                */
+               if (pThis->bSetAddress) {
+                       pThis->bSetAddress = FALSE;
+                       musb_writeb(pBase, MGC_O_HDRC_FADDR, pThis->bAddress);
+               }
+
+               /* enter test mode if needed (exit by reset) */
+               else if (pThis->bTestMode) {
+                       DBG(1, "entering TESTMODE\n");
+
+                       if (MGC_M_TEST_PACKET == pThis->bTestModeValue)
+                               musb_load_testpacket(pThis);
+
+                       musb_writeb(pBase, MGC_O_HDRC_TESTMODE,
+                                       pThis->bTestModeValue);
+               }
+               /* FALLTHROUGH */
+
+       case MGC_END0_STAGE_STATUSOUT:
+               /* end of sequence #1: write to host (TX state) */
+               {
+                       struct usb_request      *req;
+
+                       req = next_ep0_request(pThis);
+                       if (req)
+                               musb_g_ep0_giveback(pThis, req);
+               }
+               retval = IRQ_HANDLED;
+               pThis->ep0_state = MGC_END0_STAGE_SETUP;
+               /* FALLTHROUGH */
+
+       case MGC_END0_STAGE_SETUP:
+               if (wCsrVal & MGC_M_CSR0_RXPKTRDY) {
+                       struct usb_ctrlrequest  setup;
+                       int                     handled = 0;
+
+                       if (wCount != 8) {
+                               ERR("SETUP packet len %d != 8 ?\n", wCount);
+                               break;
+                       }
+                       musb_read_setup(pThis, &setup);
+                       retval = IRQ_HANDLED;
+
+                       /* sometimes the RESET won't be reported */
+                       if (unlikely(pThis->g.speed == USB_SPEED_UNKNOWN)) {
+                               u8      power;
+
+                               printk(KERN_NOTICE "%s: peripheral reset "
+                                               "irq lost!\n",
+                                               musb_driver_name);
+                               power = musb_readb(pBase, MGC_O_HDRC_POWER);
+                               pThis->g.speed = (power & MGC_M_POWER_HSMODE)
+                                       ? USB_SPEED_HIGH : USB_SPEED_FULL;
+
+                       }
+
+                       switch (pThis->ep0_state) {
+
+                       /* sequence #3 (no data stage), includes requests
+                        * we can't forward (notably SET_ADDRESS and the
+                        * device/endpoint feature set/clear operations)
+                        * plus SET_CONFIGURATION and others we must
+                        */
+                       case MGC_END0_STAGE_ACKWAIT:
+                               handled = service_zero_data_request(
+                                               pThis, &setup);
+
+                               /* status stage might be immediate */
+                               if (handled > 0) {
+                                       pThis->ackpend |= MGC_M_CSR0_P_DATAEND;
+                                       pThis->ep0_state =
+                                               MGC_END0_STAGE_STATUSIN;
+                               }
+                               break;
+
+                       /* sequence #1 (IN to host), includes GET_STATUS
+                        * requests that we can't forward, GET_DESCRIPTOR
+                        * and others that we must
+                        */
+                       case MGC_END0_STAGE_TX:
+                               handled = service_in_request(pThis, &setup);
+                               if (handled > 0) {
+                                       pThis->ackpend = MGC_M_CSR0_TXPKTRDY
+                                               | MGC_M_CSR0_P_DATAEND;
+                                       pThis->ep0_state =
+                                               MGC_END0_STAGE_STATUSOUT;
+                               }
+                               break;
+
+                       /* sequence #2 (OUT from host), always forward */
+                       default:                /* MGC_END0_STAGE_RX */
+                               break;
+                       }
+
+                       DBG(3, "handled %d, csr %04x, ep0stage %s\n",
+                               handled, wCsrVal,
+                               decode_ep0stage(pThis->ep0_state));
+
+                       /* unless we need to delegate this to the gadget
+                        * driver, we know how to wrap this up:  csr0 has
+                        * not yet been written.
+                        */
+                       if (handled < 0)
+                               goto stall;
+                       else if (handled > 0)
+                               goto finish;
+
+                       handled = forward_to_driver(pThis, &setup);
+                       if (handled < 0) {
+                               MGC_SelectEnd(pBase, 0);
+stall:
+                               DBG(3, "stall (%d)\n", handled);
+                               pThis->ackpend |= MGC_M_CSR0_P_SENDSTALL;
+                               pThis->ep0_state = MGC_END0_STAGE_SETUP;
+finish:
+                               musb_writew(regs, MGC_O_HDRC_CSR0,
+                                               pThis->ackpend);
+                               pThis->ackpend = 0;
+                       }
+               }
+               break;
+
+       case MGC_END0_STAGE_ACKWAIT:
+               /* This should not happen. But happens with tusb6010 with
+                * g_file_storage and high speed. Do nothing.
+                */
+               retval = IRQ_HANDLED;
+               break;
+
+       default:
+               /* "can't happen" */
+               WARN_ON(1);
+               musb_writew(regs, MGC_O_HDRC_CSR0, MGC_M_CSR0_P_SENDSTALL);
+               pThis->ep0_state = MGC_END0_STAGE_SETUP;
+               break;
+       }
+
+       return retval;
+}
+
+
+static int
+musb_g_ep0_enable(struct usb_ep *ep, const struct usb_endpoint_descriptor *desc)
+{
+       /* always enabled */
+       return -EINVAL;
+}
+
+static int musb_g_ep0_disable(struct usb_ep *e)
+{
+       /* always enabled */
+       return -EINVAL;
+}
+
+static void *musb_g_ep0_alloc_buffer(struct usb_ep *ep, unsigned bytes,
+                       dma_addr_t * dma, gfp_t gfp_flags)
+{
+       *dma = DMA_ADDR_INVALID;
+       return kmalloc(bytes, gfp_flags);
+}
+
+static void musb_g_ep0_free_buffer(struct usb_ep *ep, void *address,
+                       dma_addr_t dma, unsigned bytes)
+{
+       kfree(address);
+}
+
+static int
+musb_g_ep0_queue(struct usb_ep *e, struct usb_request *r, gfp_t gfp_flags)
+{
+       struct musb_ep          *ep;
+       struct musb_request     *req;
+       struct musb             *musb;
+       int                     status;
+       unsigned long           lockflags;
+       void __iomem            *regs;
+
+       if (!e || !r)
+               return -EINVAL;
+
+       ep = to_musb_ep(e);
+       musb = ep->pThis;
+       regs = musb->control_ep->regs;
+
+       req = to_musb_request(r);
+       req->musb = musb;
+       req->request.actual = 0;
+       req->request.status = -EINPROGRESS;
+       req->bTx = ep->is_in;
+
+       spin_lock_irqsave(&musb->Lock, lockflags);
+
+       if (!list_empty(&ep->req_list)) {
+               status = -EBUSY;
+               goto cleanup;
+       }
+
+       switch (musb->ep0_state) {
+       case MGC_END0_STAGE_RX:         /* control-OUT data */
+       case MGC_END0_STAGE_TX:         /* control-IN data */
+       case MGC_END0_STAGE_ACKWAIT:    /* zero-length data */
+               status = 0;
+               break;
+       default:
+               DBG(1, "ep0 request queued in state %d\n",
+                               musb->ep0_state);
+               status = -EINVAL;
+               goto cleanup;
+       }
+
+       /* add request to the list */
+       list_add_tail(&(req->request.list), &(ep->req_list));
+
+       DBG(3, "queue to %s (%s), length=%d\n",
+                       ep->name, ep->is_in ? "IN/TX" : "OUT/RX",
+                       req->request.length);
+
+       MGC_SelectEnd(musb->pRegs, 0);
+
+       /* sequence #1, IN ... start writing the data */
+       if (musb->ep0_state == MGC_END0_STAGE_TX)
+               ep0_txstate(musb);
+
+       /* sequence #3, no-data ... issue IN status */
+       else if (musb->ep0_state == MGC_END0_STAGE_ACKWAIT) {
+               if (req->request.length)
+                       status = -EINVAL;
+               else {
+                       musb->ep0_state = MGC_END0_STAGE_STATUSIN;
+                       musb_writew(regs, MGC_O_HDRC_CSR0,
+                                       musb->ackpend | MGC_M_CSR0_P_DATAEND);
+                       musb->ackpend = 0;
+                       musb_g_ep0_giveback(ep->pThis, r);
+               }
+
+       /* else for sequence #2 (OUT), caller provides a buffer
+        * before the next packet arrives.  deferred responses
+        * (after SETUP is acked) are racey.
+        */
+       } else if (musb->ackpend) {
+               musb_writew(regs, MGC_O_HDRC_CSR0, musb->ackpend);
+               musb->ackpend = 0;
+       }
+
+cleanup:
+       spin_unlock_irqrestore(&musb->Lock, lockflags);
+       return status;
+}
+
+static int
+musb_g_ep0_dequeue(struct usb_ep *ep, struct usb_request *req)
+{
+       /* we just won't support this */
+       return -EINVAL;
+}
+
+static int musb_g_ep0_halt(struct usb_ep *e, int value)
+{
+       struct musb_ep          *ep;
+       struct musb             *musb;
+       void __iomem            *base, *regs;
+       unsigned long           flags;
+       int                     status;
+       u16                     csr;
+
+       if (!e || !value)
+               return -EINVAL;
+
+       ep = to_musb_ep(e);
+       musb = ep->pThis;
+       base = musb->pRegs;
+       regs = musb->control_ep->regs;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+
+       if (!list_empty(&ep->req_list)) {
+               status = -EBUSY;
+               goto cleanup;
+       }
+
+       switch (musb->ep0_state) {
+       case MGC_END0_STAGE_TX:         /* control-IN data */
+       case MGC_END0_STAGE_ACKWAIT:    /* STALL for zero-length data */
+       case MGC_END0_STAGE_RX:         /* control-OUT data */
+               status = 0;
+
+               MGC_SelectEnd(base, 0);
+               csr = musb_readw(regs, MGC_O_HDRC_CSR0);
+               csr |= MGC_M_CSR0_P_SENDSTALL;
+               musb_writew(regs, MGC_O_HDRC_CSR0, csr);
+               musb->ep0_state = MGC_END0_STAGE_SETUP;
+               break;
+       default:
+               DBG(1, "ep0 can't halt in state %d\n", musb->ep0_state);
+               status = -EINVAL;
+       }
+
+cleanup:
+       spin_unlock_irqrestore(&musb->Lock, flags);
+       return status;
+}
+
+const struct usb_ep_ops musb_g_ep0_ops = {
+       .enable         = musb_g_ep0_enable,
+       .disable        = musb_g_ep0_disable,
+       .alloc_request  = musb_alloc_request,
+       .free_request   = musb_free_request,
+       .alloc_buffer   = musb_g_ep0_alloc_buffer,
+       .free_buffer    = musb_g_ep0_free_buffer,
+       .queue          = musb_g_ep0_queue,
+       .dequeue        = musb_g_ep0_dequeue,
+       .set_halt       = musb_g_ep0_halt,
+       .fifo_status    = NULL,
+       .fifo_flush     = NULL,
+};
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
new file mode 100644 (file)
index 0000000..da70ee1
--- /dev/null
@@ -0,0 +1,2045 @@
+/******************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux 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.
+ *
+ * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/module.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/moduleparam.h>
+#include <linux/stat.h>
+#include <linux/dma-mapping.h>
+
+#include "musbdefs.h"
+
+
+/* MUSB PERIPHERAL status 3-mar:
+ *
+ * - EP0 seems solid.  It passes both USBCV and usbtest control cases.
+ *   Minor glitches:
+ *
+ *     + remote wakeup to Linux hosts work, but saw USBCV failures;
+ *       in one test run (operator error?)
+ *     + endpoint halt tests -- in both usbtest and usbcv -- seem
+ *       to break when dma is enabled ... is something wrongly
+ *       clearing SENDSTALL?
+ *
+ * - Mass storage behaved ok when last tested.  Network traffic patterns
+ *   (with lots of short transfers etc) need retesting; they turn up the
+ *   worst cases of the DMA, since short packets are typical but are not
+ *   required.
+ *
+ * - TX/IN
+ *     + both pio and dma behave in with network and g_zero tests
+ *     + no cppi throughput issues other than no-hw-queueing
+ *     + failed with FLAT_REG (DaVinci)
+ *     + seems to behave with double buffering, PIO -and- CPPI
+ *     + with gadgetfs + AIO, requests got lost?
+ *
+ * - RX/OUT
+ *     + both pio and dma behave in with network and g_zero tests
+ *     + dma is slow in typical case (short_not_ok is clear)
+ *     + double buffering ok with PIO
+ *     + double buffering *FAILS* with CPPI, wrong data bytes sometimes
+ *     + request lossage observed with gadgetfs
+ *
+ * - ISO not tested ... might work, but only weakly isochronous
+ *
+ * - Gadget driver disabling of softconnect during bind() is ignored; so
+ *   drivers can't hold off host requests until userspace is ready.
+ *   (Workaround:  they can turn it off later.)
+ *
+ * - PORTABILITY (assumes PIO works):
+ *     + DaVinci, basically works with cppi dma
+ *     + OMAP 2430, ditto with mentor dma
+ *     + TUSB 6010, platform-specific dma in the works
+ */
+
+/**************************************************************************
+Handling completion
+**************************************************************************/
+
+/*
+ * Immediately complete a request.
+ *
+ * @param pRequest the request to complete
+ * @param status the status to complete the request with
+ * Context: controller locked, IRQs blocked.
+ */
+void musb_g_giveback(
+       struct musb_ep          *ep,
+       struct usb_request      *pRequest,
+       int status)
+__releases(ep->musb->Lock)
+__acquires(ep->musb->Lock)
+{
+       struct musb_request     *req;
+       struct musb             *musb;
+       int                     busy = ep->busy;
+
+       req = to_musb_request(pRequest);
+
+       list_del(&pRequest->list);
+       if (req->request.status == -EINPROGRESS)
+               req->request.status = status;
+       musb = req->musb;
+
+       ep->busy = 1;
+       spin_unlock(&musb->Lock);
+       if (is_dma_capable()) {
+               if (req->mapped) {
+                       dma_unmap_single(musb->controller,
+                                       req->request.dma,
+                                       req->request.length,
+                                       req->bTx
+                                               ? DMA_TO_DEVICE
+                                               : DMA_FROM_DEVICE);
+                       req->request.dma = DMA_ADDR_INVALID;
+                       req->mapped = 0;
+               } else if (req->request.dma != DMA_ADDR_INVALID)
+                       dma_sync_single_for_cpu(musb->controller,
+                                       req->request.dma,
+                                       req->request.length,
+                                       req->bTx
+                                               ? DMA_TO_DEVICE
+                                               : DMA_FROM_DEVICE);
+       }
+       if (pRequest->status == 0)
+               DBG(5, "%s done request %p,  %d/%d\n",
+                               ep->end_point.name, pRequest,
+                               req->request.actual, req->request.length);
+       else
+               DBG(2, "%s request %p, %d/%d fault %d\n",
+                               ep->end_point.name, pRequest,
+                               req->request.actual, req->request.length,
+                               pRequest->status);
+       req->request.complete(&req->ep->end_point, &req->request);
+       spin_lock(&musb->Lock);
+       ep->busy = busy;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/*
+ * Abort requests queued to an endpoint using the status. Synchronous.
+ * caller locked controller and blocked irqs, and selected this ep.
+ */
+static void nuke(struct musb_ep *ep, const int status)
+{
+       struct musb_request     *req = NULL;
+
+       ep->busy = 1;
+
+       if (is_dma_capable() && ep->dma) {
+               struct dma_controller   *c = ep->pThis->pDmaController;
+               int value;
+
+               value = c->channel_abort(ep->dma);
+               DBG(value ? 1 : 6, "%s: abort DMA --> %d\n", ep->name, value);
+               c->channel_release(ep->dma);
+               ep->dma = NULL;
+       }
+
+       while (!list_empty(&(ep->req_list))) {
+               req = container_of(ep->req_list.next, struct musb_request,
+                               request.list);
+               musb_g_giveback(ep, &req->request, status);
+       }
+}
+
+/**************************************************************************
+ * TX/IN and RX/OUT Data transfers
+ **************************************************************************/
+
+/*
+ * This assumes the separate CPPI engine is responding to DMA requests
+ * from the usb core ... sequenced a bit differently from mentor dma.
+ */
+
+static inline int max_ep_writesize(struct musb *pThis, struct musb_ep *ep)
+{
+       if (can_bulk_split(pThis, ep->type))
+               return ep->hw_ep->wMaxPacketSizeTx;
+       else
+               return ep->wPacketSize;
+}
+
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+
+/* Peripheral tx (IN) using Mentor DMA works as follows:
+       Only mode 0 is used for transfers <= wPktSize,
+       mode 1 is used for larger transfers,
+
+       One of the following happens:
+       - Host sends IN token which causes an endpoint interrupt
+               -> TxAvail
+                       -> if DMA is currently busy, exit.
+                       -> if queue is non-empty, txstate().
+
+       - Request is queued by the gadget driver.
+               -> if queue was previously empty, txstate()
+
+       txstate()
+               -> start
+                 /\    -> setup DMA
+                 |     (data is transferred to the FIFO, then sent out when
+                 |     IN token(s) are recd from Host.
+                 |             -> DMA interrupt on completion
+                 |                calls TxAvail.
+                 |                   -> stop DMA, ~DmaEenab,
+                 |                   -> set TxPktRdy for last short pkt or zlp
+                 |                   -> Complete Request
+                 |                   -> Continue next request (call txstate)
+                 |___________________________________|
+
+ * Non-Mentor DMA engines can of course work differently, such as by
+ * upleveling from irq-per-packet to irq-per-buffer.
+ */
+
+#endif
+
+/*
+ * An endpoint is transmitting data. This can be called either from
+ * the IRQ routine or from ep.queue() to kickstart a request on an
+ * endpoint.
+ *
+ * Context: controller locked, IRQs blocked, endpoint selected
+ */
+static void txstate(struct musb *pThis, struct musb_request *req)
+{
+       u8                      bEnd = req->bEnd;
+       struct musb_ep          *pEnd;
+       void __iomem            *epio = pThis->aLocalEnd[bEnd].regs;
+       struct usb_request      *pRequest;
+       u16                     wFifoCount = 0, wCsrVal;
+       int                     use_dma = 0;
+
+       pEnd = req->ep;
+
+       /* we shouldn't get here while DMA is active ... but we do ... */
+       if (dma_channel_status(pEnd->dma) == MGC_DMA_STATUS_BUSY) {
+               DBG(4, "dma pending...\n");
+               return;
+       }
+
+       /* read TXCSR before */
+       wCsrVal = musb_readw(epio, MGC_O_HDRC_TXCSR);
+
+       pRequest = &req->request;
+       wFifoCount = min(max_ep_writesize(pThis, pEnd),
+                       (int)(pRequest->length - pRequest->actual));
+
+       if (wCsrVal & MGC_M_TXCSR_TXPKTRDY) {
+               DBG(5, "%s old packet still ready , txcsr %03x\n",
+                               pEnd->end_point.name, wCsrVal);
+               return;
+       }
+
+       if (wCsrVal & MGC_M_TXCSR_P_SENDSTALL) {
+               DBG(5, "%s stalling, txcsr %03x\n",
+                               pEnd->end_point.name, wCsrVal);
+               return;
+       }
+
+       DBG(4, "hw_ep%d, maxpacket %d, fifo count %d, txcsr %03x\n",
+                       bEnd, pEnd->wPacketSize, wFifoCount,
+                       wCsrVal);
+
+#ifndef        CONFIG_USB_INVENTRA_FIFO
+       if (is_dma_capable() && pEnd->dma) {
+               struct dma_controller   *c = pThis->pDmaController;
+
+               use_dma = (pRequest->dma != DMA_ADDR_INVALID);
+
+               /* MGC_M_TXCSR_P_ISO is still set correctly */
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+               {
+                       size_t request_size;
+
+                       /* setup DMA, then program endpoint CSR */
+                       request_size = min(pRequest->length,
+                                               pEnd->dma->dwMaxLength);
+                       if (request_size <= pEnd->wPacketSize)
+                               pEnd->dma->bDesiredMode = 0;
+                       else
+                               pEnd->dma->bDesiredMode = 1;
+
+                       use_dma = use_dma && c->channel_program(
+                                       pEnd->dma, pEnd->wPacketSize,
+                                       pEnd->dma->bDesiredMode,
+                                       pRequest->dma, request_size);
+                       if (use_dma) {
+                               if (pEnd->dma->bDesiredMode == 0) {
+                                       /* ASSERT: DMAENAB is clear */
+                                       wCsrVal &= ~(MGC_M_TXCSR_AUTOSET |
+                                                       MGC_M_TXCSR_DMAMODE);
+                                       wCsrVal |= (MGC_M_TXCSR_DMAENAB |
+                                                       MGC_M_TXCSR_MODE);
+                                       // against programming guide
+                               }
+                               else
+                                       wCsrVal |= (MGC_M_TXCSR_AUTOSET
+                                                       | MGC_M_TXCSR_DMAENAB
+                                                       | MGC_M_TXCSR_DMAMODE
+                                                       | MGC_M_TXCSR_MODE);
+
+                               wCsrVal &= ~MGC_M_TXCSR_P_UNDERRUN;
+                               musb_writew(epio, MGC_O_HDRC_TXCSR, wCsrVal);
+                       }
+               }
+
+#elif defined(CONFIG_USB_TI_CPPI_DMA)
+               /* program endpoint CSR first, then setup DMA */
+               wCsrVal &= ~(MGC_M_TXCSR_AUTOSET
+                               | MGC_M_TXCSR_DMAMODE
+                               | MGC_M_TXCSR_P_UNDERRUN
+                               | MGC_M_TXCSR_TXPKTRDY);
+               wCsrVal |= MGC_M_TXCSR_MODE | MGC_M_TXCSR_DMAENAB;
+               musb_writew(epio, MGC_O_HDRC_TXCSR,
+                       (MGC_M_TXCSR_P_WZC_BITS & ~MGC_M_TXCSR_P_UNDERRUN)
+                               | wCsrVal);
+
+               /* ensure writebuffer is empty */
+               wCsrVal = musb_readw(epio, MGC_O_HDRC_TXCSR);
+
+               /* NOTE host side sets DMAENAB later than this; both are
+                * OK since the transfer dma glue (between CPPI and Mentor
+                * fifos) just tells CPPI it could start.  Data only moves
+                * to the USB TX fifo when both fifos are ready.
+                */
+
+               /* "mode" is irrelevant here; handle terminating ZLPs like
+                * PIO does, since the hardware RNDIS mode seems unreliable
+                * except for the last-packet-is-already-short case.
+                */
+               use_dma = use_dma && c->channel_program(
+                               pEnd->dma, pEnd->wPacketSize,
+                               0,
+                               pRequest->dma,
+                               pRequest->length);
+               if (!use_dma) {
+                       c->channel_release(pEnd->dma);
+                       pEnd->dma = NULL;
+                       /* ASSERT: DMAENAB clear */
+                       wCsrVal &= ~(MGC_M_TXCSR_DMAMODE | MGC_M_TXCSR_MODE);
+                       /* invariant: prequest->buf is non-null */
+               }
+#elif defined(CONFIG_USB_TUSB_OMAP_DMA)
+               use_dma = use_dma && c->channel_program(
+                               pEnd->dma, pEnd->wPacketSize,
+                               pRequest->zero,
+                               pRequest->dma,
+                               pRequest->length);
+#endif
+       }
+#endif
+
+       if (!use_dma) {
+               musb_write_fifo(pEnd->hw_ep, wFifoCount,
+                               (u8 *) (pRequest->buf + pRequest->actual));
+               pRequest->actual += wFifoCount;
+               wCsrVal |= MGC_M_TXCSR_TXPKTRDY;
+               wCsrVal &= ~MGC_M_TXCSR_P_UNDERRUN;
+               musb_writew(epio, MGC_O_HDRC_TXCSR, wCsrVal);
+       }
+
+       /* host may already have the data when this message shows... */
+       DBG(3, "%s TX/IN %s len %d/%d, txcsr %04x, fifo %d/%d\n",
+                       pEnd->end_point.name, use_dma ? "dma" : "pio",
+                       pRequest->actual, pRequest->length,
+                       musb_readw(epio, MGC_O_HDRC_TXCSR),
+                       wFifoCount,
+                       musb_readw(epio, MGC_O_HDRC_TXMAXP));
+}
+
+/*
+ * FIFO state update (e.g. data ready).
+ * Called from IRQ,  with controller locked.
+ */
+void musb_g_tx(struct musb *pThis, u8 bEnd)
+{
+       u16                     wCsrVal;
+       struct usb_request      *pRequest;
+       u8 __iomem              *pBase = pThis->pRegs;
+       struct musb_ep          *pEnd = &pThis->aLocalEnd[bEnd].ep_in;
+       void __iomem            *epio = pThis->aLocalEnd[bEnd].regs;
+       struct dma_channel      *dma;
+
+       MGC_SelectEnd(pBase, bEnd);
+       pRequest = next_request(pEnd);
+
+       wCsrVal = musb_readw(epio, MGC_O_HDRC_TXCSR);
+       DBG(4, "<== %s, txcsr %04x\n", pEnd->end_point.name, wCsrVal);
+
+       dma = is_dma_capable() ? pEnd->dma : NULL;
+       do {
+               /* REVISIT for high bandwidth, MGC_M_TXCSR_P_INCOMPTX
+                * probably rates reporting as a host error
+                */
+               if (wCsrVal & MGC_M_TXCSR_P_SENTSTALL) {
+                       wCsrVal |= MGC_M_TXCSR_P_WZC_BITS;
+                       wCsrVal &= ~MGC_M_TXCSR_P_SENTSTALL;
+                       musb_writew(epio, MGC_O_HDRC_TXCSR, wCsrVal);
+                       if (dma_channel_status(dma) == MGC_DMA_STATUS_BUSY) {
+                               dma->bStatus = MGC_DMA_STATUS_CORE_ABORT;
+                               pThis->pDmaController->channel_abort(dma);
+                       }
+
+                       if (pRequest)
+                               musb_g_giveback(pEnd, pRequest, -EPIPE);
+
+                       break;
+               }
+
+               if (wCsrVal & MGC_M_TXCSR_P_UNDERRUN) {
+                       /* we NAKed, no big deal ... little reason to care */
+                       wCsrVal |= MGC_M_TXCSR_P_WZC_BITS;
+                       wCsrVal &= ~(MGC_M_TXCSR_P_UNDERRUN
+                                       | MGC_M_TXCSR_TXPKTRDY);
+                       musb_writew(epio, MGC_O_HDRC_TXCSR, wCsrVal);
+                       DBG(20, "underrun on ep%d, req %p\n", bEnd, pRequest);
+               }
+
+               if (dma_channel_status(dma) == MGC_DMA_STATUS_BUSY) {
+                       /* SHOULD NOT HAPPEN ... has with cppi though, after
+                        * changing SENDSTALL (and other cases); harmless?
+                        */
+                       DBG(5, "%s dma still busy?\n", pEnd->end_point.name);
+                       break;
+               }
+
+               if (pRequest) {
+                       u8      is_dma = 0;
+
+                       if (dma && (wCsrVal & MGC_M_TXCSR_DMAENAB)) {
+                               is_dma = 1;
+                               wCsrVal |= MGC_M_TXCSR_P_WZC_BITS;
+                               wCsrVal &= ~(MGC_M_TXCSR_DMAENAB
+                                               | MGC_M_TXCSR_P_UNDERRUN
+                                               | MGC_M_TXCSR_TXPKTRDY);
+                               musb_writew(epio, MGC_O_HDRC_TXCSR, wCsrVal);
+                               /* ensure writebuffer is empty */
+                               wCsrVal = musb_readw(epio, MGC_O_HDRC_TXCSR);
+                               DBG(4, "TXCSR%d %04x, dma off, "
+                                               "len %Zd, req %p\n",
+                                       bEnd, wCsrVal,
+                                       pEnd->dma->dwActualLength,
+                                       pRequest);
+                               pRequest->actual += pEnd->dma->dwActualLength;
+                       }
+
+                       if (is_dma || pRequest->actual == pRequest->length) {
+
+                               /* First, maybe a terminating short packet.
+                                * Some DMA engines might handle this by
+                                * themselves.
+                                */
+                               if ((pRequest->zero
+                                               && pRequest->length
+                                               && (pRequest->length
+                                                       % pEnd->wPacketSize)
+                                                       == 0)
+#ifdef CONFIG_USB_INVENTRA_DMA
+                                       || (is_dma &&
+                                               (pRequest->actual
+                                                       < pEnd->wPacketSize))
+#endif
+                               ) {
+                                       /* on dma completion, fifo may not
+                                        * be available yet ...
+                                        */
+                                       if (wCsrVal & MGC_M_TXCSR_TXPKTRDY)
+                                               break;
+
+                                       DBG(4, "sending zero pkt\n");
+                                       musb_writew(epio, MGC_O_HDRC_TXCSR,
+                                                       MGC_M_TXCSR_MODE
+                                                       | MGC_M_TXCSR_TXPKTRDY);
+                               }
+
+                               /* ... or if not, then complete it */
+                               musb_g_giveback(pEnd, pRequest, 0);
+
+                               /* kickstart next transfer if appropriate;
+                                * the packet that just completed might not
+                                * be transmitted for hours or days.
+                                * REVISIT for double buffering...
+                                * FIXME revisit for stalls too...
+                                */
+                               MGC_SelectEnd(pBase, bEnd);
+                               wCsrVal = musb_readw(epio, MGC_O_HDRC_TXCSR);
+                               if (wCsrVal & MGC_M_TXCSR_FIFONOTEMPTY)
+                                       break;
+                               pRequest = pEnd->desc
+                                               ? next_request(pEnd)
+                                               : NULL;
+                               if (!pRequest) {
+                                       DBG(4, "%s idle now\n",
+                                                       pEnd->end_point.name);
+                                       break;
+                               }
+                       }
+
+                       txstate(pThis, to_musb_request(pRequest));
+               }
+
+       } while (0);
+}
+
+/* ------------------------------------------------------------ */
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+
+/* Peripheral rx (OUT) using Mentor DMA works as follows:
+       - Only mode 0 is used.
+
+       - Request is queued by the gadget class driver.
+               -> if queue was previously empty, rxstate()
+
+       - Host sends OUT token which causes an endpoint interrupt
+         /\      -> RxReady
+         |           -> if request queued, call rxstate
+         |             /\      -> setup DMA
+         |             |            -> DMA interrupt on completion
+         |             |               -> RxReady
+         |             |                     -> stop DMA
+         |             |                     -> ack the read
+         |             |                     -> if data recd = max expected
+         |             |                               by the request, or host
+         |             |                               sent a short packet,
+         |             |                               complete the request,
+         |             |                               and start the next one.
+         |             |_____________________________________|
+         |                                      else just wait for the host
+         |                                         to send the next OUT token.
+         |__________________________________________________|
+
+ * Non-Mentor DMA engines can of course work differently.
+ */
+
+#endif
+
+/*
+ * Context: controller locked, IRQs blocked, endpoint selected
+ */
+static void rxstate(struct musb *pThis, struct musb_request *req)
+{
+       u16                     wCsrVal = 0;
+       const u8                bEnd = req->bEnd;
+       struct usb_request      *pRequest = &req->request;
+       struct musb_ep          *pEnd = &pThis->aLocalEnd[bEnd].ep_out;
+       void __iomem            *epio = pThis->aLocalEnd[bEnd].regs;
+       u16                     wFifoCount = 0;
+       u16                     wCount = pEnd->wPacketSize;
+
+       wCsrVal = musb_readw(epio, MGC_O_HDRC_RXCSR);
+
+       if (is_cppi_enabled() && pEnd->dma) {
+               struct dma_controller   *c = pThis->pDmaController;
+               struct dma_channel      *channel = pEnd->dma;
+
+               /* NOTE:  CPPI won't actually stop advancing the DMA
+                * queue after short packet transfers, so this is almost
+                * always going to run as IRQ-per-packet DMA so that
+                * faults will be handled correctly.
+                */
+               if (c->channel_program(channel,
+                               pEnd->wPacketSize,
+                               !pRequest->short_not_ok,
+                               pRequest->dma + pRequest->actual,
+                               pRequest->length - pRequest->actual)) {
+
+                       /* make sure that if an rxpkt arrived after the irq,
+                        * the cppi engine will be ready to take it as soon
+                        * as DMA is enabled
+                        */
+                       wCsrVal &= ~(MGC_M_RXCSR_AUTOCLEAR
+                                       | MGC_M_RXCSR_DMAMODE);
+                       wCsrVal |= MGC_M_RXCSR_DMAENAB | MGC_M_RXCSR_P_WZC_BITS;
+                       musb_writew(epio, MGC_O_HDRC_RXCSR, wCsrVal);
+                       return;
+               }
+       }
+
+       if (wCsrVal & MGC_M_RXCSR_RXPKTRDY) {
+               wCount = musb_readw(epio, MGC_O_HDRC_RXCOUNT);
+               if (pRequest->actual < pRequest->length) {
+#ifdef CONFIG_USB_INVENTRA_DMA
+                       if (is_dma_capable() && pEnd->dma) {
+                               struct dma_controller   *c;
+                               struct dma_channel      *channel;
+                               int                     use_dma = 0;
+
+                               c = pThis->pDmaController;
+                               channel = pEnd->dma;
+
+       /* We use DMA Req mode 0 in RxCsr, and DMA controller operates in
+        * mode 0 only. So we do not get endpoint interrupts due to DMA
+        * completion. We only get interrupts from DMA controller.
+        *
+        * We could operate in DMA mode 1 if we knew the size of the tranfer
+        * in advance. For mass storage class, request->length = what the host
+        * sends, so that'd work.  But for pretty much everything else,
+        * request->length is routinely more than what the host sends. For
+        * most these gadgets, end of is signified either by a short packet,
+        * or filling the last byte of the buffer.  (Sending extra data in
+        * that last pckate should trigger an overflow fault.)  But in mode 1,
+        * we don't get DMA completion interrrupt for short packets.
+        *
+        * Theoretically, we could enable DMAReq interrupt (RxCsr_DMAMODE = 1),
+        * to get endpoint interrupt on every DMA req, but that didn't seem
+        * to work reliably.
+        *
+        * REVISIT an updated g_file_storage can set req->short_not_ok, which
+        * then becomes usable as a runtime "use mode 1" hint...
+        */
+
+                               wCsrVal |= MGC_M_RXCSR_DMAENAB;
+#ifdef USE_MODE1
+                               wCsrVal |= MGC_M_RXCSR_AUTOCLEAR;
+//                             wCsrVal |= MGC_M_RXCSR_DMAMODE;
+
+                               /* this special sequence (enabling and then
+                                  disabling MGC_M_RXCSR_DMAMODE) is required
+                                  to get DMAReq to activate
+                                */
+                               musb_writew(epio, MGC_O_HDRC_RXCSR,
+                                       wCsrVal | MGC_M_RXCSR_DMAMODE);
+#endif
+                               musb_writew(epio, MGC_O_HDRC_RXCSR,
+                                               wCsrVal);
+
+                               if (pRequest->actual < pRequest->length) {
+                                       int transfer_size = 0;
+#ifdef USE_MODE1
+                                       transfer_size = min(pRequest->length,
+                                                       channel->dwMaxLength);
+#else
+                                       transfer_size = wCount;
+#endif
+                                       if (transfer_size <= pEnd->wPacketSize)
+                                               pEnd->dma->bDesiredMode = 0;
+                                       else
+                                               pEnd->dma->bDesiredMode = 1;
+
+                                       use_dma = c->channel_program(
+                                                       channel,
+                                                       pEnd->wPacketSize,
+                                                       channel->bDesiredMode,
+                                                       pRequest->dma
+                                                       + pRequest->actual,
+                                                       transfer_size);
+                               }
+
+                               if (use_dma)
+                                       return;
+                       }
+#endif /* Mentor's USB */
+
+                       wFifoCount = pRequest->length - pRequest->actual;
+                       DBG(3, "%s OUT/RX pio fifo %d/%d, maxpacket %d\n",
+                                       pEnd->end_point.name,
+                                       wCount, wFifoCount,
+                                       pEnd->wPacketSize);
+
+                       wFifoCount = min(wCount, wFifoCount);
+
+#ifdef CONFIG_USB_TUSB_OMAP_DMA
+                       if (tusb_dma_omap() && pEnd->dma) {
+                               struct dma_controller *c = pThis->pDmaController;
+                               struct dma_channel *channel = pEnd->dma;
+                               u32 dma_addr = pRequest->dma + pRequest->actual;
+                               int ret;
+
+                               ret = c->channel_program(channel,
+                                               pEnd->wPacketSize,
+                                               channel->bDesiredMode,
+                                               dma_addr,
+                                               wFifoCount);
+                               if (ret == TRUE)
+                                       return;
+                       }
+#endif
+
+                       musb_read_fifo(pEnd->hw_ep, wFifoCount, (u8 *)
+                                       (pRequest->buf + pRequest->actual));
+                       pRequest->actual += wFifoCount;
+
+                       /* REVISIT if we left anything in the fifo, flush
+                        * it and report -EOVERFLOW
+                        */
+
+                       /* ack the read! */
+                       wCsrVal |= MGC_M_RXCSR_P_WZC_BITS;
+                       wCsrVal &= ~MGC_M_RXCSR_RXPKTRDY;
+                       musb_writew(epio, MGC_O_HDRC_RXCSR, wCsrVal);
+               }
+       }
+
+       /* reach the end or short packet detected */
+       if (pRequest->actual == pRequest->length || wCount < pEnd->wPacketSize)
+               musb_g_giveback(pEnd, pRequest, 0);
+}
+
+/*
+ * Data ready for a request; called from IRQ
+ * @param pThis the controller
+ * @param req the request
+ */
+void musb_g_rx(struct musb *pThis, u8 bEnd)
+{
+       u16                     wCsrVal;
+       struct usb_request      *pRequest;
+       void __iomem            *pBase = pThis->pRegs;
+       struct musb_ep          *pEnd = &pThis->aLocalEnd[bEnd].ep_out;
+       void __iomem            *epio = pThis->aLocalEnd[bEnd].regs;
+       struct dma_channel      *dma;
+
+       MGC_SelectEnd(pBase, bEnd);
+
+       pRequest = next_request(pEnd);
+
+       wCsrVal = musb_readw(epio, MGC_O_HDRC_RXCSR);
+       dma = is_dma_capable() ? pEnd->dma : NULL;
+
+       DBG(4, "<== %s, rxcsr %04x%s %p\n", pEnd->end_point.name,
+                       wCsrVal, dma ? " (dma)" : "", pRequest);
+
+       if (wCsrVal & MGC_M_RXCSR_P_SENTSTALL) {
+               if (dma_channel_status(dma) == MGC_DMA_STATUS_BUSY) {
+                       dma->bStatus = MGC_DMA_STATUS_CORE_ABORT;
+                       (void) pThis->pDmaController->channel_abort(dma);
+                       pRequest->actual += pEnd->dma->dwActualLength;
+               }
+
+               wCsrVal |= MGC_M_RXCSR_P_WZC_BITS;
+               wCsrVal &= ~MGC_M_RXCSR_P_SENTSTALL;
+               musb_writew(epio, MGC_O_HDRC_RXCSR, wCsrVal);
+
+               if (pRequest)
+                       musb_g_giveback(pEnd, pRequest, -EPIPE);
+               goto done;
+       }
+
+       if (wCsrVal & MGC_M_RXCSR_P_OVERRUN) {
+               // wCsrVal |= MGC_M_RXCSR_P_WZC_BITS;
+               wCsrVal &= ~MGC_M_RXCSR_P_OVERRUN;
+               musb_writew(epio, MGC_O_HDRC_RXCSR, wCsrVal);
+
+               DBG(3, "%s iso overrun on %p\n", pEnd->name, pRequest);
+               if (pRequest && pRequest->status == -EINPROGRESS)
+                       pRequest->status = -EOVERFLOW;
+       }
+       if (wCsrVal & MGC_M_RXCSR_INCOMPRX) {
+               /* REVISIT not necessarily an error */
+               DBG(4, "%s, incomprx\n", pEnd->end_point.name);
+       }
+
+       if (dma_channel_status(dma) == MGC_DMA_STATUS_BUSY) {
+               /* "should not happen"; likely RXPKTRDY pending for DMA */
+               DBG((wCsrVal & MGC_M_RXCSR_DMAENAB) ? 4 : 1,
+                       "%s busy, csr %04x\n",
+                       pEnd->end_point.name, wCsrVal);
+               goto done;
+       }
+
+       if (dma && (wCsrVal & MGC_M_RXCSR_DMAENAB)) {
+               wCsrVal &= ~(MGC_M_RXCSR_AUTOCLEAR
+                               | MGC_M_RXCSR_DMAENAB
+                               | MGC_M_RXCSR_DMAMODE);
+               musb_writew(epio, MGC_O_HDRC_RXCSR,
+                       MGC_M_RXCSR_P_WZC_BITS | wCsrVal);
+
+               pRequest->actual += pEnd->dma->dwActualLength;
+
+               DBG(4, "RXCSR%d %04x, dma off, %04x, len %Zd, req %p\n",
+                       bEnd, wCsrVal,
+                       musb_readw(epio, MGC_O_HDRC_RXCSR),
+                       pEnd->dma->dwActualLength, pRequest);
+
+#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA)
+               /* Autoclear doesn't clear RxPktRdy for short packets */
+               if ((dma->bDesiredMode == 0)
+                               || (dma->dwActualLength
+                                       & (pEnd->wPacketSize - 1))) {
+                       /* ack the read! */
+                       wCsrVal &= ~MGC_M_RXCSR_RXPKTRDY;
+                       musb_writew(epio, MGC_O_HDRC_RXCSR, wCsrVal);
+               }
+
+               /* incomplete, and not short? wait for next IN packet */
+                if ((pRequest->actual < pRequest->length)
+                               && (pEnd->dma->dwActualLength
+                                       == pEnd->wPacketSize))
+                       goto done;
+#endif
+               musb_g_giveback(pEnd, pRequest, 0);
+
+               pRequest = next_request(pEnd);
+               if (!pRequest)
+                       goto done;
+
+               /* don't start more i/o till the stall clears */
+               MGC_SelectEnd(pBase, bEnd);
+               wCsrVal = musb_readw(epio, MGC_O_HDRC_RXCSR);
+               if (wCsrVal & MGC_M_RXCSR_P_SENDSTALL)
+                       goto done;
+       }
+
+
+       /* analyze request if the ep is hot */
+       if (pRequest)
+               rxstate(pThis, to_musb_request(pRequest));
+       else
+               DBG(3, "packet waiting for %s%s request\n",
+                               pEnd->desc ? "" : "inactive ",
+                               pEnd->end_point.name);
+
+done:
+       return;
+}
+
+/* ------------------------------------------------------------ */
+
+static int musb_gadget_enable(struct usb_ep *ep,
+                       const struct usb_endpoint_descriptor *desc)
+{
+       unsigned long           flags;
+       struct musb_ep          *pEnd;
+       struct musb_hw_ep       *hw_ep;
+       void __iomem            *regs;
+       struct musb     *pThis;
+       void __iomem    *pBase;
+       u8              bEnd;
+       u16             csr;
+       unsigned        tmp;
+       int             status = -EINVAL;
+
+       if (!ep || !desc)
+               return -EINVAL;
+
+       pEnd = to_musb_ep(ep);
+       hw_ep = pEnd->hw_ep;
+       regs = hw_ep->regs;
+       pThis = pEnd->pThis;
+       pBase = pThis->pRegs;
+       bEnd = pEnd->bEndNumber;
+
+       spin_lock_irqsave(&pThis->Lock, flags);
+
+       if (pEnd->desc) {
+               status = -EBUSY;
+               goto fail;
+       }
+       pEnd->type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+       /* check direction and (later) maxpacket size against endpoint */
+       if ((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) != bEnd)
+               goto fail;
+
+       /* REVISIT this rules out high bandwidth periodic transfers */
+       tmp = le16_to_cpu(desc->wMaxPacketSize);
+       if (tmp & ~0x07ff)
+               goto fail;
+       pEnd->wPacketSize = tmp;
+
+       /* enable the interrupts for the endpoint, set the endpoint
+        * packet size (or fail), set the mode, clear the fifo
+        */
+       MGC_SelectEnd(pBase, bEnd);
+       if (desc->bEndpointAddress & USB_DIR_IN) {
+               u16 wIntrTxE = musb_readw(pBase, MGC_O_HDRC_INTRTXE);
+
+               if (hw_ep->bIsSharedFifo)
+                       pEnd->is_in = 1;
+               if (!pEnd->is_in)
+                       goto fail;
+               if (tmp > hw_ep->wMaxPacketSizeTx)
+                       goto fail;
+
+               wIntrTxE |= (1 << bEnd);
+               musb_writew(pBase, MGC_O_HDRC_INTRTXE, wIntrTxE);
+
+               /* REVISIT if can_bulk_split(), use by updating "tmp";
+                * likewise high bandwidth periodic tx
+                */
+               musb_writew(regs, MGC_O_HDRC_TXMAXP, tmp);
+
+               csr = MGC_M_TXCSR_MODE | MGC_M_TXCSR_CLRDATATOG;
+               if (musb_readw(regs, MGC_O_HDRC_TXCSR)
+                               & MGC_M_TXCSR_FIFONOTEMPTY)
+                       csr |= MGC_M_TXCSR_FLUSHFIFO;
+               if (pEnd->type == USB_ENDPOINT_XFER_ISOC)
+                       csr |= MGC_M_TXCSR_P_ISO;
+
+               /* set twice in case of double buffering */
+               musb_writew(regs, MGC_O_HDRC_TXCSR, csr);
+               /* REVISIT may be inappropriate w/o FIFONOTEMPTY ... */
+               musb_writew(regs, MGC_O_HDRC_TXCSR, csr);
+
+       } else {
+               u16 wIntrRxE = musb_readw(pBase, MGC_O_HDRC_INTRRXE);
+
+               if (hw_ep->bIsSharedFifo)
+                       pEnd->is_in = 0;
+               if (pEnd->is_in)
+                       goto fail;
+               if (tmp > hw_ep->wMaxPacketSizeRx)
+                       goto fail;
+
+               wIntrRxE |= (1 << bEnd);
+               musb_writew(pBase, MGC_O_HDRC_INTRRXE, wIntrRxE);
+
+               /* REVISIT if can_bulk_combine() use by updating "tmp"
+                * likewise high bandwidth periodic rx
+                */
+               musb_writew(regs, MGC_O_HDRC_RXMAXP, tmp);
+
+               /* force shared fifo to OUT-only mode */
+               if (hw_ep->bIsSharedFifo) {
+                       csr = musb_readw(regs, MGC_O_HDRC_TXCSR);
+                       csr &= ~(MGC_M_TXCSR_MODE | MGC_M_TXCSR_TXPKTRDY);
+                       musb_writew(regs, MGC_O_HDRC_TXCSR, csr);
+               }
+
+               csr = MGC_M_RXCSR_FLUSHFIFO | MGC_M_RXCSR_CLRDATATOG;
+               if (pEnd->type == USB_ENDPOINT_XFER_ISOC)
+                       csr |= MGC_M_RXCSR_P_ISO;
+               else if (pEnd->type == USB_ENDPOINT_XFER_INT)
+                       csr |= MGC_M_RXCSR_DISNYET;
+
+               /* set twice in case of double buffering */
+               musb_writew(regs, MGC_O_HDRC_RXCSR, csr);
+               musb_writew(regs, MGC_O_HDRC_RXCSR, csr);
+       }
+
+       /* NOTE:  all the I/O code _should_ work fine without DMA, in case
+        * for some reason you run out of channels here.
+        */
+       if (is_dma_capable() && pThis->pDmaController) {
+               struct dma_controller   *c = pThis->pDmaController;
+
+               pEnd->dma = c->channel_alloc(c, hw_ep,
+                               (desc->bEndpointAddress & USB_DIR_IN));
+       } else
+               pEnd->dma = NULL;
+
+       pEnd->desc = desc;
+       pEnd->busy = 0;
+       status = 0;
+
+       pr_debug("%s periph: enabled %s for %s %s, %smaxpacket %d\n",
+                       musb_driver_name, pEnd->end_point.name,
+                       ({ char *s; switch (pEnd->type) {
+                       case USB_ENDPOINT_XFER_BULK:    s = "bulk"; break;
+                       case USB_ENDPOINT_XFER_INT:     s = "int"; break;
+                       default:                        s = "iso"; break;
+                       }; s; }),
+                       pEnd->is_in ? "IN" : "OUT",
+                       pEnd->dma ? "dma, " : "",
+                       pEnd->wPacketSize);
+
+       schedule_work(&pThis->irq_work);
+
+fail:
+       spin_unlock_irqrestore(&pThis->Lock, flags);
+       return status;
+}
+
+/*
+ * Disable an endpoint flushing all requests queued.
+ */
+static int musb_gadget_disable(struct usb_ep *ep)
+{
+       unsigned long   flags;
+       struct musb     *pThis;
+       u8              bEnd;
+       struct musb_ep  *pEnd;
+       void __iomem    *epio;
+       int             status = 0;
+
+       pEnd = to_musb_ep(ep);
+       pThis = pEnd->pThis;
+       bEnd = pEnd->bEndNumber;
+       epio = pThis->aLocalEnd[bEnd].regs;
+
+       spin_lock_irqsave(&pThis->Lock, flags);
+       MGC_SelectEnd(pThis->pRegs, bEnd);
+
+       /* zero the endpoint sizes */
+       if (pEnd->is_in) {
+               u16 wIntrTxE = musb_readw(pThis->pRegs, MGC_O_HDRC_INTRTXE);
+               wIntrTxE &= ~(1 << bEnd);
+               musb_writew(pThis->pRegs, MGC_O_HDRC_INTRTXE, wIntrTxE);
+               musb_writew(epio, MGC_O_HDRC_TXMAXP, 0);
+       } else {
+               u16 wIntrRxE = musb_readw(pThis->pRegs, MGC_O_HDRC_INTRRXE);
+               wIntrRxE &= ~(1 << bEnd);
+               musb_writew(pThis->pRegs, MGC_O_HDRC_INTRRXE, wIntrRxE);
+               musb_writew(epio, MGC_O_HDRC_RXMAXP, 0);
+       }
+
+       pEnd->desc = NULL;
+
+       /* abort all pending DMA and requests */
+       nuke(pEnd, -ESHUTDOWN);
+
+       schedule_work(&pThis->irq_work);
+
+       spin_unlock_irqrestore(&(pThis->Lock), flags);
+
+       DBG(2, "%s\n", pEnd->end_point.name);
+
+       return status;
+}
+
+/*
+ * Allocate a request for an endpoint.
+ * Reused by ep0 code.
+ */
+struct usb_request *musb_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
+{
+       struct musb_ep          *musb_ep = to_musb_ep(ep);
+       struct musb_request     *pRequest = NULL;
+
+       pRequest = kzalloc(sizeof *pRequest, gfp_flags);
+       if (pRequest) {
+               INIT_LIST_HEAD(&pRequest->request.list);
+               pRequest->request.dma = DMA_ADDR_INVALID;
+               pRequest->bEnd = musb_ep->bEndNumber;
+               pRequest->ep = musb_ep;
+       }
+
+       return &pRequest->request;
+}
+
+/*
+ * Free a request
+ * Reused by ep0 code.
+ */
+void musb_free_request(struct usb_ep *ep, struct usb_request *req)
+{
+       kfree(to_musb_request(req));
+}
+
+/*
+ * dma-coherent memory allocation (for dma-capable endpoints)
+ *
+ * NOTE: the dma_*_coherent() API calls suck; most implementations are
+ * (a) page-oriented, so small buffers lose big, and (b) asymmetric with
+ * respect to calls with irqs disabled:  alloc is safe, free is not.
+ */
+static void *musb_gadget_alloc_buffer(struct usb_ep *ep, unsigned bytes,
+                       dma_addr_t * dma, gfp_t gfp_flags)
+{
+       struct musb_ep *musb_ep = to_musb_ep(ep);
+
+       return dma_alloc_coherent(musb_ep->pThis->controller,
+                       bytes, dma, gfp_flags);
+}
+
+static DEFINE_SPINLOCK(buflock);
+static LIST_HEAD(buffers);
+
+struct free_record {
+       struct list_head        list;
+       struct device           *dev;
+       unsigned                bytes;
+       dma_addr_t              dma;
+};
+
+static void do_free(unsigned long ignored)
+{
+       spin_lock_irq(&buflock);
+       while (!list_empty(&buffers)) {
+               struct free_record      *buf;
+
+               buf = list_entry(buffers.next, struct free_record, list);
+               list_del(&buf->list);
+               spin_unlock_irq(&buflock);
+
+               dma_free_coherent(buf->dev, buf->bytes, buf, buf->dma);
+
+               spin_lock_irq(&buflock);
+       }
+       spin_unlock_irq(&buflock);
+}
+
+static DECLARE_TASKLET(deferred_free, do_free, 0);
+
+static void musb_gadget_free_buffer(struct usb_ep *ep,
+               void *address, dma_addr_t dma, unsigned bytes)
+{
+       struct musb_ep          *musb_ep = to_musb_ep(ep);
+       struct free_record      *buf = address;
+       unsigned long           flags;
+
+       buf->dev = musb_ep->pThis->controller;
+       buf->bytes = bytes;
+       buf->dma = dma;
+
+       spin_lock_irqsave(&buflock, flags);
+       list_add_tail(&buf->list, &buffers);
+       tasklet_schedule(&deferred_free);
+       spin_unlock_irqrestore(&buflock, flags);
+}
+
+/*
+ * Context: controller locked, IRQs blocked.
+ */
+static void musb_ep_restart(struct musb *pThis, struct musb_request *req)
+{
+       DBG(3, "<== %s request %p len %u on hw_ep%d\n",
+               req->bTx ? "TX/IN" : "RX/OUT",
+               &req->request, req->request.length, req->bEnd);
+
+       MGC_SelectEnd(pThis->pRegs, req->bEnd);
+       if (req->bTx)
+               txstate(pThis, req);
+       else
+               rxstate(pThis, req);
+}
+
+static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
+                       gfp_t gfp_flags)
+{
+       struct musb_ep          *pEnd;
+       struct musb_request     *pRequest;
+       struct musb             *musb;
+       int                     status = 0;
+       unsigned long           lockflags;
+
+       if (!ep || !req)
+               return -EINVAL;
+
+       pEnd = to_musb_ep(ep);
+       musb = pEnd->pThis;
+
+       pRequest = to_musb_request(req);
+       pRequest->musb = musb;
+
+       if (pRequest->ep != pEnd)
+               return -EINVAL;
+
+       DBG(4, "<== to %s request=%p\n", ep->name, req);
+
+       /* request is mine now... */
+       pRequest->request.actual = 0;
+       pRequest->request.status = -EINPROGRESS;
+       pRequest->bEnd = pEnd->bEndNumber;
+       pRequest->bTx = pEnd->is_in;
+
+       if (is_dma_capable() && pEnd->dma) {
+               if (pRequest->request.dma == DMA_ADDR_INVALID) {
+                       pRequest->request.dma = dma_map_single(
+                                       musb->controller,
+                                       pRequest->request.buf,
+                                       pRequest->request.length,
+                                       pRequest->bTx
+                                               ? DMA_TO_DEVICE
+                                               : DMA_FROM_DEVICE);
+                       pRequest->mapped = 1;
+               } else {
+                       dma_sync_single_for_device(musb->controller,
+                                       pRequest->request.dma,
+                                       pRequest->request.length,
+                                       pRequest->bTx
+                                               ? DMA_TO_DEVICE
+                                               : DMA_FROM_DEVICE);
+                       pRequest->mapped = 0;
+               }
+       } else if (!req->buf) {
+               return -ENODATA;
+       } else
+               pRequest->mapped = 0;
+
+       spin_lock_irqsave(&musb->Lock, lockflags);
+
+       /* don't queue if the ep is down */
+       if (!pEnd->desc) {
+               DBG(4, "req %p queued to %s while ep %s\n",
+                               req, ep->name, "disabled");
+               status = -ESHUTDOWN;
+               goto cleanup;
+       }
+
+       /* add pRequest to the list */
+       list_add_tail(&(pRequest->request.list), &(pEnd->req_list));
+
+       /* it this is the head of the queue, start i/o ... */
+       if (!pEnd->busy && &pRequest->request.list == pEnd->req_list.next)
+               musb_ep_restart(musb, pRequest);
+
+cleanup:
+       spin_unlock_irqrestore(&musb->Lock, lockflags);
+       return status;
+}
+
+static int musb_gadget_dequeue(struct usb_ep *ep, struct usb_request *pRequest)
+{
+       struct musb_ep          *pEnd = to_musb_ep(ep);
+       struct usb_request      *r;
+       unsigned long           flags;
+       int                     status = 0;
+
+       if (!ep || !pRequest || to_musb_request(pRequest)->ep != pEnd)
+               return -EINVAL;
+
+       spin_lock_irqsave(&pEnd->pThis->Lock, flags);
+
+       list_for_each_entry(r, &pEnd->req_list, list) {
+               if (r == pRequest)
+                       break;
+       }
+       if (r != pRequest) {
+               DBG(3, "request %p not queued to %s\n", pRequest, ep->name);
+               status = -EINVAL;
+               goto done;
+       }
+
+       /* if the hardware doesn't have the request, easy ... */
+       if (pEnd->req_list.next != &pRequest->list || pEnd->busy)
+               musb_g_giveback(pEnd, pRequest, -ECONNRESET);
+
+       /* ... else abort the dma transfer ... */
+       else if (is_dma_capable() && pEnd->dma) {
+               struct dma_controller   *c = pEnd->pThis->pDmaController;
+
+               MGC_SelectEnd(pEnd->pThis->pRegs, pEnd->bEndNumber);
+               if (c->channel_abort)
+                       status = c->channel_abort(pEnd->dma);
+               else
+                       status = -EBUSY;
+               if (status == 0)
+                       musb_g_giveback(pEnd, pRequest, -ECONNRESET);
+       } else {
+               /* NOTE: by sticking to easily tested hardware/driver states,
+                * we leave counting of in-flight packets imprecise.
+                */
+               musb_g_giveback(pEnd, pRequest, -ECONNRESET);
+       }
+
+done:
+       spin_unlock_irqrestore(&pEnd->pThis->Lock, flags);
+       return status;
+}
+
+/*
+ * Set or clear the halt bit of an endpoint. A halted enpoint won't tx/rx any
+ * data but will queue requests.
+ *
+ * exported to ep0 code
+ */
+int musb_gadget_set_halt(struct usb_ep *ep, int value)
+{
+       struct musb_ep          *pEnd = to_musb_ep(ep);
+       u8                      bEnd = pEnd->bEndNumber;
+       struct musb             *pThis = pEnd->pThis;
+       void __iomem            *epio = pThis->aLocalEnd[bEnd].regs;
+       void __iomem            *pBase;
+       unsigned long           flags;
+       u16                     wCsr;
+       struct musb_request     *pRequest = NULL;
+       int                     status = 0;
+
+       pBase = pThis->pRegs;
+
+       spin_lock_irqsave(&pThis->Lock, flags);
+
+       if ((USB_ENDPOINT_XFER_ISOC == pEnd->type)) {
+               status = -EINVAL;
+               goto done;
+       }
+
+       MGC_SelectEnd(pBase, bEnd);
+
+       /* cannot portably stall with non-empty FIFO */
+       pRequest = to_musb_request(next_request(pEnd));
+       if (value && pEnd->is_in) {
+               wCsr = musb_readw(epio, MGC_O_HDRC_TXCSR);
+               if (wCsr & MGC_M_TXCSR_FIFONOTEMPTY) {
+                       DBG(3, "%s fifo busy, cannot halt\n", ep->name);
+                       spin_unlock_irqrestore(&pThis->Lock, flags);
+                       return -EAGAIN;
+               }
+
+       }
+
+       /* set/clear the stall and toggle bits */
+       DBG(2, "%s: %s stall\n", ep->name, value ? "set" : "clear");
+       if (pEnd->is_in) {
+               wCsr = musb_readw(epio, MGC_O_HDRC_TXCSR);
+               if (wCsr & MGC_M_TXCSR_FIFONOTEMPTY)
+                       wCsr |= MGC_M_TXCSR_FLUSHFIFO;
+               wCsr |= MGC_M_TXCSR_P_WZC_BITS
+                       | MGC_M_TXCSR_CLRDATATOG;
+               if (value)
+                       wCsr |= MGC_M_TXCSR_P_SENDSTALL;
+               else
+                       wCsr &= ~(MGC_M_TXCSR_P_SENDSTALL
+                               | MGC_M_TXCSR_P_SENTSTALL);
+               wCsr &= ~MGC_M_TXCSR_TXPKTRDY;
+               musb_writew(epio, MGC_O_HDRC_TXCSR, wCsr);
+       } else {
+               wCsr = musb_readw(epio, MGC_O_HDRC_RXCSR);
+               wCsr |= MGC_M_RXCSR_P_WZC_BITS
+                       | MGC_M_RXCSR_FLUSHFIFO
+                       | MGC_M_RXCSR_CLRDATATOG;
+               if (value)
+                       wCsr |= MGC_M_RXCSR_P_SENDSTALL;
+               else
+                       wCsr &= ~(MGC_M_RXCSR_P_SENDSTALL
+                               | MGC_M_RXCSR_P_SENTSTALL);
+               musb_writew(epio, MGC_O_HDRC_RXCSR, wCsr);
+       }
+
+done:
+
+       /* maybe start the first request in the queue */
+       if (!pEnd->busy && !value && pRequest) {
+               DBG(3, "restarting the request\n");
+               musb_ep_restart(pThis, pRequest);
+       }
+
+       spin_unlock_irqrestore(&pThis->Lock, flags);
+       return status;
+}
+
+static int musb_gadget_fifo_status(struct usb_ep *ep)
+{
+       struct musb_ep          *musb_ep = to_musb_ep(ep);
+       void __iomem            *epio = musb_ep->hw_ep->regs;
+       int                     retval = -EINVAL;
+
+       if (musb_ep->desc && !musb_ep->is_in) {
+               struct musb             *musb = musb_ep->pThis;
+               int                     bEnd = musb_ep->bEndNumber;
+               void __iomem            *mbase = musb->pRegs;
+               unsigned long           flags;
+
+               spin_lock_irqsave(&musb->Lock, flags);
+
+               MGC_SelectEnd(mbase, bEnd);
+               /* FIXME return zero unless RXPKTRDY is set */
+               retval = musb_readw(epio, MGC_O_HDRC_RXCOUNT);
+
+               spin_unlock_irqrestore(&musb->Lock, flags);
+       }
+       return retval;
+}
+
+static void musb_gadget_fifo_flush(struct usb_ep *ep)
+{
+       struct musb_ep  *musb_ep = to_musb_ep(ep);
+       struct musb     *musb = musb_ep->pThis;
+       u8              nEnd = musb_ep->bEndNumber;
+       void __iomem    *epio = musb->aLocalEnd[nEnd].regs;
+       void __iomem    *mbase;
+       unsigned long   flags;
+       u16             wCsr, wIntrTxE;
+
+       mbase = musb->pRegs;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+       MGC_SelectEnd(mbase, (u8) nEnd);
+
+       /* disable interrupts */
+       wIntrTxE = musb_readw(mbase, MGC_O_HDRC_INTRTXE);
+       musb_writew(mbase, MGC_O_HDRC_INTRTXE, wIntrTxE & ~(1 << nEnd));
+
+       if (musb_ep->is_in) {
+               wCsr = musb_readw(epio, MGC_O_HDRC_TXCSR);
+               if (wCsr & MGC_M_TXCSR_FIFONOTEMPTY) {
+                       wCsr |= MGC_M_TXCSR_FLUSHFIFO | MGC_M_TXCSR_P_WZC_BITS;
+                       musb_writew(epio, MGC_O_HDRC_TXCSR, wCsr);
+                       /* REVISIT may be inappropriate w/o FIFONOTEMPTY ... */
+                       musb_writew(epio, MGC_O_HDRC_TXCSR, wCsr);
+               }
+       } else {
+               wCsr = musb_readw(epio, MGC_O_HDRC_RXCSR);
+               wCsr |= MGC_M_RXCSR_FLUSHFIFO | MGC_M_RXCSR_P_WZC_BITS;
+               musb_writew(epio, MGC_O_HDRC_RXCSR, wCsr);
+               musb_writew(epio, MGC_O_HDRC_RXCSR, wCsr);
+       }
+
+       /* re-enable interrupt */
+       musb_writew(mbase, MGC_O_HDRC_INTRTXE, wIntrTxE);
+       spin_unlock_irqrestore(&musb->Lock, flags);
+}
+
+static const struct usb_ep_ops musb_ep_ops = {
+       .enable         = musb_gadget_enable,
+       .disable        = musb_gadget_disable,
+       .alloc_request  = musb_alloc_request,
+       .free_request   = musb_free_request,
+       .alloc_buffer   = musb_gadget_alloc_buffer,
+       .free_buffer    = musb_gadget_free_buffer,
+       .queue          = musb_gadget_queue,
+       .dequeue        = musb_gadget_dequeue,
+       .set_halt       = musb_gadget_set_halt,
+       .fifo_status    = musb_gadget_fifo_status,
+       .fifo_flush     = musb_gadget_fifo_flush
+};
+
+/***********************************************************************/
+
+static int musb_gadget_get_frame(struct usb_gadget *gadget)
+{
+       struct musb     *pThis = gadget_to_musb(gadget);
+
+       return (int)musb_readw(pThis->pRegs, MGC_O_HDRC_FRAME);
+}
+
+static int musb_gadget_wakeup(struct usb_gadget *gadget)
+{
+       struct musb     *musb = gadget_to_musb(gadget);
+       unsigned long   flags;
+       int             status = -EINVAL;
+       u8              power;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+
+       /* fail if we're not suspended */
+       power = musb_readb(musb->pRegs, MGC_O_HDRC_POWER);
+       if (!(power & MGC_M_POWER_SUSPENDM))
+               goto done;
+
+       switch (musb->xceiv.state) {
+       case OTG_STATE_B_PERIPHERAL:
+               /* NOTE:  OTG state machine doesn't include B_SUSPENDED;
+                * that's part of the standard usb 1.1 state machine, and
+                * doesn't affect OTG transitions.
+                */
+               if (musb->bMayWakeup)
+                       break;
+               goto done;
+       case OTG_STATE_B_IDLE:
+               /* REVISIT we might be able to do SRP even without OTG,
+                * though Linux doesn't yet expose that capability.  SRP
+                * starts by setting DEVCTL.SESSION (not POWER.RESUME);
+                * though DaVinci can't do it.
+                */
+               if (is_otg_enabled(musb)) {
+                       musb->xceiv.state = OTG_STATE_B_SRP_INIT;
+                       break;
+               }
+               /* FALLTHROUGH */
+       default:
+               goto done;
+       }
+
+       status = 0;
+       power |= MGC_M_POWER_RESUME;
+       musb_writeb(musb->pRegs, MGC_O_HDRC_POWER, power);
+
+       /* FIXME do this next chunk in a timer callback, no udelay */
+       mdelay(2);
+
+       power = musb_readb(musb->pRegs, MGC_O_HDRC_POWER);
+       power &= ~MGC_M_POWER_RESUME;
+       musb_writeb(musb->pRegs, MGC_O_HDRC_POWER, power);
+
+       if (musb->xceiv.state == OTG_STATE_B_SRP_INIT)
+               musb->xceiv.state = OTG_STATE_B_IDLE;
+done:
+       spin_unlock_irqrestore(&musb->Lock, flags);
+       return status;
+}
+
+static int
+musb_gadget_set_self_powered(struct usb_gadget *gadget, int is_selfpowered)
+{
+       struct musb     *pThis = gadget_to_musb(gadget);
+
+       pThis->bIsSelfPowered = !!is_selfpowered;
+       return 0;
+}
+
+static void musb_pullup(struct musb *musb, int is_on)
+{
+       u8 power;
+
+       power = musb_readb(musb->pRegs, MGC_O_HDRC_POWER);
+       if (is_on)
+               power |= MGC_M_POWER_SOFTCONN;
+       else
+               power &= ~MGC_M_POWER_SOFTCONN;
+
+       /* FIXME if on, HdrcStart; if off, HdrcStop */
+
+       DBG(3, "gadget %s D+ pullup %s\n",
+               musb->pGadgetDriver->function, is_on ? "on" : "off");
+       musb_writeb(musb->pRegs, MGC_O_HDRC_POWER, power);
+}
+
+#if 0
+static int musb_gadget_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+       DBG(2, "<= %s =>\n", __FUNCTION__);
+
+       // FIXME iff driver's softconnect flag is set (as it is during probe,
+       // though that can clear it), just musb_pullup().
+
+       return -EINVAL;
+}
+
+static int musb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+       /* FIXME -- delegate to otg_transciever logic */
+
+       DBG(2, "<= vbus_draw %u =>\n", mA);
+       return 0;
+}
+#endif
+
+static int musb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+       struct musb     *musb = gadget_to_musb(gadget);
+
+       if (!musb->xceiv.set_power)
+               return -EOPNOTSUPP;
+       return otg_set_power(&musb->xceiv, mA);
+}
+
+static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on)
+{
+       struct musb     *musb = gadget_to_musb(gadget);
+       unsigned long   flags;
+
+       is_on = !!is_on;
+
+       /* NOTE: this assumes we are sensing vbus; we'd rather
+        * not pullup unless the B-session is active.
+        */
+       spin_lock_irqsave(&musb->Lock, flags);
+       if (is_on != musb->softconnect) {
+               musb->softconnect = is_on;
+               musb_pullup(musb, is_on);
+       }
+       spin_unlock_irqrestore(&musb->Lock, flags);
+       return 0;
+}
+
+static const struct usb_gadget_ops musb_gadget_operations = {
+       .get_frame              = musb_gadget_get_frame,
+       .wakeup                 = musb_gadget_wakeup,
+       .set_selfpowered        = musb_gadget_set_self_powered,
+       //.vbus_session         = musb_gadget_vbus_session,
+       .vbus_draw              = musb_gadget_vbus_draw,
+       .pullup                 = musb_gadget_pullup,
+};
+
+/****************************************************************
+ * Registration operations
+ ****************************************************************/
+
+/* Only this registration code "knows" the rule (from USB standards)
+ * about there being only one external upstream port.  It assumes
+ * all peripheral ports are external...
+ */
+static struct musb *the_gadget;
+
+static void musb_gadget_release(struct device *dev)
+{
+       // kref_put(WHAT)
+       dev_dbg(dev, "%s\n", __FUNCTION__);
+}
+
+
+static void __init
+init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 bEnd, int is_in)
+{
+       struct musb_hw_ep       *hw_ep = musb->aLocalEnd + bEnd;
+
+       memset(ep, 0, sizeof *ep);
+
+       ep->bEndNumber = bEnd;
+       ep->pThis = musb;
+       ep->hw_ep = hw_ep;
+       ep->is_in = is_in;
+
+       INIT_LIST_HEAD(&ep->req_list);
+
+       sprintf(ep->name, "ep%d%s", bEnd,
+                       (!bEnd || hw_ep->bIsSharedFifo) ? "" : (
+                               is_in ? "in" : "out"));
+       ep->end_point.name = ep->name;
+       INIT_LIST_HEAD(&ep->end_point.ep_list);
+       if (!bEnd) {
+               ep->end_point.maxpacket = 64;
+               ep->end_point.ops = &musb_g_ep0_ops;
+               musb->g.ep0 = &ep->end_point;
+       } else {
+               if (is_in)
+                       ep->end_point.maxpacket = hw_ep->wMaxPacketSizeTx;
+               else
+                       ep->end_point.maxpacket = hw_ep->wMaxPacketSizeRx;
+               ep->end_point.ops = &musb_ep_ops;
+               list_add_tail(&ep->end_point.ep_list, &musb->g.ep_list);
+       }
+}
+
+/*
+ * Initialize the endpoints exposed to peripheral drivers, with backlinks
+ * to the rest of the driver state.
+ */
+static inline void __init musb_g_init_endpoints(struct musb *pThis)
+{
+       u8                      bEnd;
+       struct musb_hw_ep       *hw_ep;
+       unsigned                count = 0;
+
+       /* intialize endpoint list just once */
+       INIT_LIST_HEAD(&(pThis->g.ep_list));
+
+       for (bEnd = 0, hw_ep = pThis->aLocalEnd;
+                       bEnd < pThis->bEndCount;
+                       bEnd++, hw_ep++) {
+               if (hw_ep->bIsSharedFifo /* || !bEnd */) {
+                       init_peripheral_ep(pThis, &hw_ep->ep_in, bEnd, 0);
+                       count++;
+               } else {
+                       if (hw_ep->wMaxPacketSizeTx) {
+                               init_peripheral_ep(pThis, &hw_ep->ep_in,
+                                                       bEnd, 1);
+                               count++;
+                       }
+                       if (hw_ep->wMaxPacketSizeRx) {
+                               init_peripheral_ep(pThis, &hw_ep->ep_out,
+                                                       bEnd, 0);
+                               count++;
+                       }
+               }
+       }
+}
+
+/* called once during driver setup to initialize and link into
+ * the driver model; memory is zeroed.
+ */
+int __init musb_gadget_setup(struct musb *musb)
+{
+       int status;
+
+       /* REVISIT minor race:  if (erroneously) setting up two
+        * musb peripherals at the same time, only the bus lock
+        * is probably held.
+        */
+       if (the_gadget)
+               return -EBUSY;
+       the_gadget = musb;
+
+       musb->g.ops = &musb_gadget_operations;
+       musb->g.is_dualspeed = 1;
+       musb->g.speed = USB_SPEED_UNKNOWN;
+
+       /* this "gadget" abstracts/virtualizes the controller */
+       strcpy(musb->g.dev.bus_id, "gadget");
+       musb->g.dev.parent = musb->controller;
+       musb->g.dev.dma_mask = musb->controller->dma_mask;
+       musb->g.dev.release = musb_gadget_release;
+       musb->g.name = musb_driver_name;
+
+       if (is_otg_enabled(musb))
+               musb->g.is_otg = 1;
+
+       musb_g_init_endpoints(musb);
+
+       musb->is_active = 0;
+       musb_platform_try_idle(musb);
+
+       status = device_register(&musb->g.dev);
+       if (status != 0)
+               the_gadget = NULL;
+       return status;
+}
+
+void musb_gadget_cleanup(struct musb *musb)
+{
+       if (musb != the_gadget)
+               return;
+
+       device_unregister(&musb->g.dev);
+       the_gadget = NULL;
+}
+
+/*
+ * Register the gadget driver. Used by gadget drivers when
+ * registering themselves with the controller.
+ *
+ * -EINVAL something went wrong (not driver)
+ * -EBUSY another gadget is already using the controller
+ * -ENOMEM no memeory to perform the operation
+ *
+ * @param driver the gadget driver
+ * @return <0 if error, 0 if everything is fine
+ */
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+       int retval;
+       unsigned long flags;
+       struct musb *pThis = the_gadget;
+
+       if (!driver
+                       || driver->speed != USB_SPEED_HIGH
+                       || !driver->bind
+                       || !driver->setup)
+               return -EINVAL;
+
+       /* driver must be initialized to support peripheral mode */
+       if (!pThis || !(pThis->board_mode == MUSB_OTG
+                               || pThis->board_mode != MUSB_OTG)) {
+               DBG(1,"%s, no dev??\n", __FUNCTION__);
+               return -ENODEV;
+       }
+
+       DBG(3, "registering driver %s\n", driver->function);
+       spin_lock_irqsave(&pThis->Lock, flags);
+
+       if (pThis->pGadgetDriver) {
+               DBG(1, "%s is already bound to %s\n",
+                               musb_driver_name,
+                               pThis->pGadgetDriver->driver.name);
+               retval = -EBUSY;
+       } else {
+               pThis->pGadgetDriver = driver;
+               pThis->g.dev.driver = &driver->driver;
+               driver->driver.bus = NULL;
+               pThis->softconnect = 1;
+               retval = 0;
+       }
+
+       spin_unlock_irqrestore(&pThis->Lock, flags);
+
+       if (retval == 0)
+               retval = driver->bind(&pThis->g);
+       if (retval != 0) {
+               DBG(3, "bind to driver %s failed --> %d\n",
+                       driver->driver.name, retval);
+               pThis->pGadgetDriver = NULL;
+               pThis->g.dev.driver = NULL;
+       }
+
+       /* start peripheral and/or OTG engines */
+       if (retval == 0) {
+               spin_lock_irqsave(&pThis->Lock, flags);
+
+               /* REVISIT always use otg_set_peripheral(), handling
+                * issues including the root hub one below ...
+                */
+               pThis->xceiv.gadget = &pThis->g;
+               pThis->xceiv.state = OTG_STATE_B_IDLE;
+               pThis->is_active = 1;
+
+               /* FIXME this ignores the softconnect flag.  Drivers are
+                * allowed hold the peripheral inactive until for example
+                * userspace hooks up printer hardware or DSP codecs, so
+                * hosts only see fully functional devices.
+                */
+
+               if (!is_otg_enabled(pThis))
+                       musb_start(pThis);
+
+               spin_unlock_irqrestore(&pThis->Lock, flags);
+
+               if (is_otg_enabled(pThis)) {
+                       DBG(3, "OTG startup...\n");
+
+                       /* REVISIT:  funcall to other code, which also
+                        * handles power budgeting ... this way also
+                        * ensures HdrcStart is indirectly called.
+                        */
+                       retval = usb_add_hcd(musb_to_hcd(pThis), -1, 0);
+                       if (retval < 0) {
+                               DBG(1, "add_hcd failed, %d\n", retval);
+                               spin_lock_irqsave(&pThis->Lock, flags);
+                               pThis->xceiv.gadget = NULL;
+                               pThis->xceiv.state = OTG_STATE_UNDEFINED;
+                               pThis->pGadgetDriver = NULL;
+                               pThis->g.dev.driver = NULL;
+                               spin_unlock_irqrestore(&pThis->Lock, flags);
+                       }
+               }
+       }
+
+       return retval;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+static void
+stop_activity(struct musb *musb, struct usb_gadget_driver *driver)
+{
+       int                     i;
+       struct musb_hw_ep       *hw_ep;
+
+       /* don't disconnect if it's not connected */
+       if (musb->g.speed == USB_SPEED_UNKNOWN)
+               driver = NULL;
+       else
+               musb->g.speed = USB_SPEED_UNKNOWN;
+
+       /* deactivate the hardware */
+       if (musb->softconnect) {
+               musb->softconnect = 0;
+               musb_pullup(musb, 0);
+       }
+       musb_stop(musb);
+
+       /* killing any outstanding requests will quiesce the driver;
+        * then report disconnect
+        */
+       if (driver) {
+               for (i = 0, hw_ep = musb->aLocalEnd;
+                               i < musb->bEndCount;
+                               i++, hw_ep++) {
+                       MGC_SelectEnd(musb->pRegs, i);
+                       if (hw_ep->bIsSharedFifo /* || !bEnd */) {
+                               nuke(&hw_ep->ep_in, -ESHUTDOWN);
+                       } else {
+                               if (hw_ep->wMaxPacketSizeTx)
+                                       nuke(&hw_ep->ep_in, -ESHUTDOWN);
+                               if (hw_ep->wMaxPacketSizeRx)
+                                       nuke(&hw_ep->ep_out, -ESHUTDOWN);
+                       }
+               }
+
+               spin_unlock(&musb->Lock);
+               driver->disconnect (&musb->g);
+               spin_lock(&musb->Lock);
+       }
+}
+
+/*
+ * Unregister the gadget driver. Used by gadget drivers when
+ * unregistering themselves from the controller.
+ *
+ * @param driver the gadget driver to unregister
+ */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+       unsigned long   flags;
+       int             retval = 0;
+       struct musb     *musb = the_gadget;
+
+       if (!driver || !driver->unbind || !musb)
+               return -EINVAL;
+
+       /* REVISIT always use otg_set_peripheral() here too;
+        * this needs to shut down the OTG engine.
+        */
+
+       spin_lock_irqsave(&musb->Lock, flags);
+       if (musb->pGadgetDriver == driver) {
+               musb->xceiv.state = OTG_STATE_UNDEFINED;
+               stop_activity(musb, driver);
+
+               DBG(3, "unregistering driver %s\n", driver->function);
+               spin_unlock_irqrestore(&musb->Lock, flags);
+               driver->unbind(&musb->g);
+               spin_lock_irqsave(&musb->Lock, flags);
+
+               musb->pGadgetDriver = NULL;
+               musb->g.dev.driver = NULL;
+
+               musb->is_active = 0;
+               musb_platform_try_idle(musb);
+       } else
+               retval = -EINVAL;
+       spin_unlock_irqrestore(&musb->Lock, flags);
+
+       if (is_otg_enabled(musb) && retval == 0) {
+               usb_remove_hcd(musb_to_hcd(musb));
+               /* FIXME we need to be able to register another
+                * gadget driver here and have everything work;
+                * that currently misbehaves.
+                */
+       }
+
+       return retval;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+
+/***********************************************************************/
+
+/* lifecycle operations called through plat_uds.c */
+
+void musb_g_resume(struct musb *pThis)
+{
+       switch (pThis->xceiv.state) {
+       case OTG_STATE_B_IDLE:
+               break;
+       case OTG_STATE_B_WAIT_ACON:
+       case OTG_STATE_B_PERIPHERAL:
+               pThis->is_active = 1;
+               if (pThis->pGadgetDriver && pThis->pGadgetDriver->resume) {
+                       spin_unlock(&pThis->Lock);
+                       pThis->pGadgetDriver->resume(&pThis->g);
+                       spin_lock(&pThis->Lock);
+               }
+               break;
+       default:
+               WARN("unhandled RESUME transition (%s)\n",
+                               otg_state_string(pThis));
+       }
+}
+
+/* called when SOF packets stop for 3+ msec */
+void musb_g_suspend(struct musb *pThis)
+{
+       u8      devctl;
+
+       devctl = musb_readb(pThis->pRegs, MGC_O_HDRC_DEVCTL);
+       DBG(3, "devctl %02x\n", devctl);
+
+       switch (pThis->xceiv.state) {
+       case OTG_STATE_B_IDLE:
+               if ((devctl & MGC_M_DEVCTL_VBUS) == MGC_M_DEVCTL_VBUS)
+                       pThis->xceiv.state = OTG_STATE_B_PERIPHERAL;
+               break;
+       case OTG_STATE_B_PERIPHERAL:
+               if (pThis->pGadgetDriver && pThis->pGadgetDriver->suspend) {
+                       spin_unlock(&pThis->Lock);
+                       pThis->pGadgetDriver->suspend(&pThis->g);
+                       spin_lock(&pThis->Lock);
+               }
+               break;
+       default:
+               /* REVISIT if B_HOST, clear DEVCTL.HOSTREQ;
+                * A_PERIPHERAL may need care too
+                */
+               WARN("unhandled SUSPEND transition (%s)\n",
+                               otg_state_string(pThis));
+       }
+}
+
+/* called when VBUS drops below session threshold, and in other cases */
+void musb_g_disconnect(struct musb *pThis)
+{
+       void __iomem    *mregs = pThis->pRegs;
+       u8      devctl = musb_readb(mregs, MGC_O_HDRC_DEVCTL);
+
+       DBG(3, "devctl %02x\n", devctl);
+
+       /* clear HR */
+       musb_writeb(mregs, MGC_O_HDRC_DEVCTL, devctl & MGC_M_DEVCTL_SESSION);
+
+       /* don't draw vbus until new b-default session */
+       (void) musb_gadget_vbus_draw(&pThis->g, 0);
+
+       pThis->g.speed = USB_SPEED_UNKNOWN;
+       if (pThis->pGadgetDriver && pThis->pGadgetDriver->disconnect) {
+               spin_unlock(&pThis->Lock);
+               pThis->pGadgetDriver->disconnect(&pThis->g);
+               spin_lock(&pThis->Lock);
+       }
+
+       switch (pThis->xceiv.state) {
+       default:
+#ifdef CONFIG_USB_MUSB_OTG
+               pThis->xceiv.state = OTG_STATE_A_IDLE;
+               break;
+       case OTG_STATE_B_WAIT_ACON:
+       case OTG_STATE_B_HOST:
+#endif
+       case OTG_STATE_B_PERIPHERAL:
+               pThis->xceiv.state = OTG_STATE_B_IDLE;
+               break;
+       case OTG_STATE_B_SRP_INIT:
+               break;
+       }
+
+       pThis->is_active = 0;
+}
+
+void musb_g_reset(struct musb *pThis)
+__releases(pThis->Lock)
+__acquires(pThis->Lock)
+{
+       void __iomem    *pBase = pThis->pRegs;
+       u8              devctl = musb_readb(pBase, MGC_O_HDRC_DEVCTL);
+       u8              power;
+
+       DBG(3, "<== %s addr=%x driver '%s'\n",
+                       (devctl & MGC_M_DEVCTL_BDEVICE)
+                               ? "B-Device" : "A-Device",
+                       musb_readb(pBase, MGC_O_HDRC_FADDR),
+                       pThis->pGadgetDriver
+                               ? pThis->pGadgetDriver->driver.name
+                               : NULL
+                       );
+
+       /* report disconnect, if we didn't already (flushing EP state) */
+       if (pThis->g.speed != USB_SPEED_UNKNOWN)
+               musb_g_disconnect(pThis);
+
+       /* clear HR */
+       else if (devctl & MGC_M_DEVCTL_HR)
+               musb_writeb(pBase, MGC_O_HDRC_DEVCTL, MGC_M_DEVCTL_SESSION);
+
+
+       /* what speed did we negotiate? */
+       power = musb_readb(pBase, MGC_O_HDRC_POWER);
+       pThis->g.speed = (power & MGC_M_POWER_HSMODE)
+                       ? USB_SPEED_HIGH : USB_SPEED_FULL;
+
+       /* start in USB_STATE_DEFAULT */
+       pThis->is_active = 1;
+       MUSB_DEV_MODE(pThis);
+       pThis->bAddress = 0;
+       pThis->ep0_state = MGC_END0_STAGE_SETUP;
+
+       pThis->bMayWakeup = 0;
+       pThis->g.b_hnp_enable = 0;
+       pThis->g.a_alt_hnp_support = 0;
+       pThis->g.a_hnp_support = 0;
+
+       /* Normal reset, as B-Device;
+        * or else after HNP, as A-Device
+        */
+       if (devctl & MGC_M_DEVCTL_BDEVICE) {
+               pThis->xceiv.state = OTG_STATE_B_PERIPHERAL;
+               pThis->g.is_a_peripheral = 0;
+       } else if (is_otg_enabled(pThis)) {
+               pThis->xceiv.state = OTG_STATE_A_PERIPHERAL;
+               pThis->g.is_a_peripheral = 1;
+       } else
+               WARN_ON(1);
+
+       /* start with default limits on VBUS power draw */
+       (void) musb_gadget_vbus_draw(&pThis->g,
+                       is_otg_enabled(pThis) ? 8 : 100);
+}
diff --git a/drivers/usb/musb/musb_gadget.h b/drivers/usb/musb/musb_gadget.h
new file mode 100644 (file)
index 0000000..5c7c7c3
--- /dev/null
@@ -0,0 +1,107 @@
+/******************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux 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.
+ *
+ * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+#ifndef __MUSB_GADGET_H
+#define __MUSB_GADGET_H
+
+struct musb_request {
+       struct usb_request      request;
+       struct musb_ep          *ep;
+       struct musb             *musb;
+       u8 bTx;                 /* endpoint direction */
+       u8 bEnd;
+       u8 mapped;
+};
+
+static inline struct musb_request *to_musb_request(struct usb_request *req)
+{
+       return req ? container_of(req, struct musb_request, request) : NULL;
+}
+
+extern struct usb_request *
+musb_alloc_request(struct usb_ep *ep, gfp_t gfp_flags);
+extern void musb_free_request(struct usb_ep *ep, struct usb_request *req);
+
+
+/*
+ * struct musb_ep - peripheral side view of endpoint rx or tx side
+ */
+struct musb_ep {
+       /* stuff towards the head is basically write-once. */
+       struct usb_ep                   end_point;
+       char                            name[12];
+       struct musb_hw_ep               *hw_ep;
+       struct musb                     *pThis;
+       u8                              bEndNumber;
+
+       /* ... when enabled/disabled ... */
+       u8                              type;
+       u8                              is_in;
+       u16                             wPacketSize;
+       const struct usb_endpoint_descriptor    *desc;
+       struct dma_channel              *dma;
+
+       /* later things are modified based on usage */
+       struct list_head                req_list;
+
+       /* true if lock must be dropped but req_list may not be advanced */
+       u8                              busy;
+};
+
+static inline struct musb_ep *to_musb_ep(struct usb_ep *ep)
+{
+       return ep ? container_of(ep, struct musb_ep, end_point) : NULL;
+}
+
+static inline struct usb_request *next_request(struct musb_ep *ep)
+{
+       struct list_head        *queue = &ep->req_list;
+
+       if (list_empty(queue))
+               return NULL;
+       return container_of(queue->next, struct usb_request, list);
+}
+
+extern void musb_g_tx(struct musb *pThis, u8 bEnd);
+extern void musb_g_rx(struct musb *pThis, u8 bEnd);
+
+extern const struct usb_ep_ops musb_g_ep0_ops;
+
+extern int musb_gadget_setup(struct musb *);
+extern void musb_gadget_cleanup(struct musb *);
+
+extern void musb_g_giveback(struct musb_ep *, struct usb_request *, int);
+
+extern int musb_gadget_set_halt(struct usb_ep *ep, int value);
+
+#endif         /* __MUSB_GADGET_H */
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
new file mode 100644 (file)
index 0000000..848575c
--- /dev/null
@@ -0,0 +1,2173 @@
+/******************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006 by Nokia Corporation
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux 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.
+ *
+ * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/list.h>
+
+#include "musbdefs.h"
+#include "musb_host.h"
+
+
+/* MUSB HOST status 22-mar-2006
+ *
+ * - There's still lots of partial code duplication for fault paths, so
+ *   they aren't handled as consistently as they need to be.
+ *
+ * - PIO mostly behaved when last tested.
+ *     + including ep0, with all usbtest cases 9, 10
+ *     + usbtest 14 (ep0out) doesn't seem to run at all
+ *     + double buffered OUT/TX endpoints saw stalls(!) with certain usbtest
+ *       configurations, but otherwise double buffering passes basic tests.
+ *     + for 2.6.N, for N > ~10, needs API changes for hcd framework.
+ *
+ * - DMA (CPPI) ... partially behaves, not currently recommended
+ *     + about 1/15 the speed of typical EHCI implementations (PCI)
+ *     + RX, all too often reqpkt seems to misbehave after tx
+ *     + TX, no known issues (other than evident silicon issue)
+ *
+ * - DMA (Mentor/OMAP) ...has at least toggle update problems
+ *
+ * - Still no traffic scheduling code to make NAKing for bulk or control
+ *   transfers unable to starve other requests; or to make efficient use
+ *   of hardware with periodic transfers.  (Note that network drivers
+ *   commonly post bulk reads that stay pending for a long time; these
+ *   would make very visible trouble.)
+ *
+ * - Not tested with HNP, but some SRP paths seem to behave.
+ *
+ * NOTE 24-August:
+ *
+ * - Bulk traffic finally uses both sides of hardware ep1, freeing up an
+ *   extra endpoint for periodic use enabling hub + keybd + mouse.  That
+ *   mostly works, except that with "usbnet" it's easy to trigger cases
+ *   with "ping" where RX loses.  (a) ping to davinci, even "ping -f",
+ *   fine; but (b) ping _from_ davinci, even "ping -c 1", ICMP RX loses
+ *   although ARP RX wins.  (That test was done with a full speed link.)
+ */
+
+
+/*
+ * NOTE on endpoint usage:
+ *
+ * CONTROL transfers all go through ep0.  BULK ones go through dedicated IN
+ * and OUT endpoints ... hardware is dedicated for those "async" queue(s).
+ *
+ * (Yes, bulk _could_ use more of the endpoints than that, and would even
+ * benefit from it ... one remote device may easily be NAKing while others
+ * need to perform transfers in that same direction.  The same thing could
+ * be done in software though, assuming dma cooperates.)
+ *
+ * INTERUPPT and ISOCHRONOUS transfers are scheduled to the other endpoints.
+ * So far that scheduling is both dumb and optimistic:  the endpoint will be
+ * "claimed" until its software queue is no longer refilled.  No multiplexing
+ * of transfers between endpoints, or anything clever.
+ */
+
+
+/*************************** Forwards ***************************/
+
+static void musb_ep_program(struct musb *pThis, u8 bEnd,
+                       struct urb *pUrb, unsigned int nOut,
+                       u8 * pBuffer, u32 dwLength);
+
+/*
+ * Start transmit. Caller is responsible for locking shared resources.
+ * pThis must be locked.
+ */
+static inline void musb_h_tx_start(struct musb_hw_ep *ep)
+{
+       u16     txcsr;
+
+       /* NOTE: no locks here; caller should lock and select EP */
+       if (ep->bLocalEnd) {
+               txcsr = musb_readw(ep->regs, MGC_O_HDRC_TXCSR);
+               txcsr |= MGC_M_TXCSR_TXPKTRDY | MGC_M_TXCSR_H_WZC_BITS;
+               musb_writew(ep->regs, MGC_O_HDRC_TXCSR, txcsr);
+       } else {
+               txcsr = MGC_M_CSR0_H_SETUPPKT | MGC_M_CSR0_TXPKTRDY;
+               musb_writew(ep->regs, MGC_O_HDRC_CSR0, txcsr);
+       }
+
+}
+
+static inline void cppi_host_txdma_start(struct musb_hw_ep *ep)
+{
+       u16     txcsr;
+
+       /* NOTE: no locks here; caller should lock and select EP */
+       txcsr = musb_readw(ep->regs, MGC_O_HDRC_TXCSR);
+       txcsr |= MGC_M_TXCSR_DMAENAB | MGC_M_TXCSR_H_WZC_BITS;
+       musb_writew(ep->regs, MGC_O_HDRC_TXCSR, txcsr);
+}
+
+/*
+ * Start the URB at the front of an endpoint's queue
+ * end must be claimed from the caller.
+ *
+ * Context: controller locked, irqs blocked
+ */
+static void
+musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
+{
+       u16                     wFrame;
+       u32                     dwLength;
+       void                    *pBuffer;
+       void __iomem            *pBase =  musb->pRegs;
+       struct urb              *urb = next_urb(qh);
+       struct musb_hw_ep       *pEnd = qh->hw_ep;
+       unsigned                nPipe = urb->pipe;
+       u8                      bAddress = usb_pipedevice(nPipe);
+       int                     bEnd = pEnd->bLocalEnd;
+
+       /* initialize software qh state */
+       qh->offset = 0;
+       qh->segsize = 0;
+
+       /* gather right source of data */
+       switch (qh->type) {
+       case USB_ENDPOINT_XFER_CONTROL:
+               /* control transfers always start with SETUP */
+               is_in = 0;
+               pEnd->out_qh = qh;
+               musb->bEnd0Stage = MGC_END0_START;
+               pBuffer = urb->setup_packet;
+               dwLength = 8;
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+               qh->iso_idx = 0;
+               qh->frame = 0;
+               pBuffer = urb->transfer_buffer + urb->iso_frame_desc[0].offset;
+               dwLength = urb->iso_frame_desc[0].length;
+               break;
+       default:                /* bulk, interrupt */
+               pBuffer = urb->transfer_buffer;
+               dwLength = urb->transfer_buffer_length;
+       }
+
+       DBG(4, "qh %p urb %p dev%d ep%d%s%s, hw_ep %d, %p/%d\n",
+                       qh, urb, bAddress, qh->epnum,
+                       is_in ? "in" : "out",
+                       ({char *s; switch (qh->type) {
+                       case USB_ENDPOINT_XFER_CONTROL: s = ""; break;
+                       case USB_ENDPOINT_XFER_BULK:    s = "-bulk"; break;
+                       case USB_ENDPOINT_XFER_ISOC:    s = "-iso"; break;
+                       default:                        s = "-intr"; break;
+                       }; s;}),
+                       bEnd, pBuffer, dwLength);
+
+       /* Configure endpoint */
+       if (is_in || pEnd->bIsSharedFifo)
+               pEnd->in_qh = qh;
+       else
+               pEnd->out_qh = qh;
+       musb_ep_program(musb, bEnd, urb, !is_in, pBuffer, dwLength);
+
+       /* transmit may have more work: start it when it is time */
+       if (is_in)
+               return;
+
+       /* determine if the time is right for a periodic transfer */
+       switch (qh->type) {
+       case USB_ENDPOINT_XFER_ISOC:
+       case USB_ENDPOINT_XFER_INT:
+               DBG(3, "check whether there's still time for periodic Tx\n");
+               qh->iso_idx = 0;
+               wFrame = musb_readw(pBase, MGC_O_HDRC_FRAME);
+               /* FIXME this doesn't implement that scheduling policy ...
+                * or handle framecounter wrapping
+                */
+               if ((urb->transfer_flags & URB_ISO_ASAP)
+                               || (wFrame >= urb->start_frame)) {
+                       /* REVISIT the SOF irq handler shouldn't duplicate
+                        * this code; and we don't init urb->start_frame...
+                        */
+                       qh->frame = 0;
+                       goto start;
+               } else {
+                       qh->frame = urb->start_frame;
+                       /* enable SOF interrupt so we can count down */
+DBG(1,"SOF for %d\n", bEnd);
+#if 1 // ifndef        CONFIG_ARCH_DAVINCI
+                       musb_writeb(pBase, MGC_O_HDRC_INTRUSBE, 0xff);
+#endif
+               }
+               break;
+       default:
+start:
+               DBG(4, "Start TX%d %s\n", bEnd,
+                       pEnd->tx_channel ? "dma" : "pio");
+
+               if (!pEnd->tx_channel)
+                       musb_h_tx_start(pEnd);
+               else if (is_cppi_enabled())
+                       cppi_host_txdma_start(pEnd);
+       }
+}
+
+/* caller owns controller lock, irqs are blocked */
+static void
+__musb_giveback(struct musb *musb, struct urb *urb, int status)
+__releases(musb->Lock)
+__acquires(musb->Lock)
+{
+       if ((urb->transfer_flags & URB_SHORT_NOT_OK)
+                       && (urb->actual_length < urb->transfer_buffer_length)
+                       && status == 0
+                       && usb_pipein(urb->pipe))
+               status = -EREMOTEIO;
+
+       spin_lock(&urb->lock);
+       urb->hcpriv = NULL;
+       if (urb->status == -EINPROGRESS)
+               urb->status = status;
+       spin_unlock(&urb->lock);
+
+       DBG(({ int level; switch (urb->status) {
+                               case 0:
+                                       level = 4;
+                                       break;
+                               /* common/boring faults */
+                               case -EREMOTEIO:
+                               case -ESHUTDOWN:
+                               case -ECONNRESET:
+                               case -EPIPE:
+                                       level = 3;
+                                       break;
+                               default:
+                                       level = 2;
+                                       break;
+                               }; level; }),
+                       "complete %p (%d), dev%d ep%d%s, %d/%d\n",
+                       urb, urb->status,
+                       usb_pipedevice(urb->pipe),
+                       usb_pipeendpoint(urb->pipe),
+                       usb_pipein(urb->pipe) ? "in" : "out",
+                       urb->actual_length, urb->transfer_buffer_length
+                       );
+
+       spin_unlock(&musb->Lock);
+       usb_hcd_giveback_urb(musb_to_hcd(musb), urb);
+       spin_lock(&musb->Lock);
+}
+
+/* for bulk/interrupt endpoints only */
+static inline void musb_save_toggle(struct musb_hw_ep *ep, int is_in, struct urb *urb)
+{
+       struct usb_device       *udev = urb->dev;
+       u16                     csr;
+       void __iomem            *epio = ep->regs;
+       struct musb_qh          *qh;
+
+       /* FIXME:  the current Mentor DMA code seems to have
+        * problems getting toggle correct.
+        */
+
+       if (is_in || ep->bIsSharedFifo)
+               qh = ep->in_qh;
+       else
+               qh = ep->out_qh;
+
+       if (!is_in) {
+               csr = musb_readw(epio, MGC_O_HDRC_TXCSR);
+               usb_settoggle(udev, qh->epnum, 1,
+                       (csr & MGC_M_TXCSR_H_DATATOGGLE)
+                               ? 1 : 0);
+       } else {
+               csr = musb_readw(epio, MGC_O_HDRC_RXCSR);
+               usb_settoggle(udev, qh->epnum, 0,
+                       (csr & MGC_M_RXCSR_H_DATATOGGLE)
+                               ? 1 : 0);
+       }
+}
+
+/* caller owns controller lock, irqs are blocked */
+static struct musb_qh *
+musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
+{
+       int                     is_in;
+       struct musb_hw_ep       *ep = qh->hw_ep;
+       struct musb             *musb = ep->musb;
+       int                     ready = qh->is_ready;
+
+       if (ep->bIsSharedFifo)
+               is_in = 1;
+       else
+               is_in = usb_pipein(urb->pipe);
+
+       /* save toggle eagerly, for paranoia */
+       switch (qh->type) {
+       case USB_ENDPOINT_XFER_BULK:
+       case USB_ENDPOINT_XFER_INT:
+               musb_save_toggle(ep, is_in, urb);
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+               if (status == 0 && urb->error_count)
+                       status = -EXDEV;
+               break;
+       }
+
+       qh->is_ready = 0;
+       __musb_giveback(musb, urb, status);
+       qh->is_ready = ready;
+
+       /* reclaim resources (and bandwidth) ASAP; deschedule it, and
+        * invalidate qh as soon as list_empty(&hep->urb_list)
+        */
+       if (list_empty(&qh->hep->urb_list)) {
+               struct list_head        *head;
+
+               if (is_in)
+                       ep->rx_reinit = 1;
+               else
+                       ep->tx_reinit = 1;
+
+               /* clobber old pointers to this qh */
+               if (is_in || ep->bIsSharedFifo)
+                       ep->in_qh = NULL;
+               else
+                       ep->out_qh = NULL;
+               qh->hep->hcpriv = NULL;
+
+               switch (qh->type) {
+
+               case USB_ENDPOINT_XFER_ISOC:
+               case USB_ENDPOINT_XFER_INT:
+                       /* this is where periodic bandwidth should be
+                        * de-allocated if it's tracked and allocated;
+                        * and where we'd update the schedule tree...
+                        */
+                       musb->periodic[ep->bLocalEnd] = NULL;
+                       kfree(qh);
+                       qh = NULL;
+                       break;
+
+               case USB_ENDPOINT_XFER_CONTROL:
+               case USB_ENDPOINT_XFER_BULK:
+                       /* fifo policy for these lists, except that NAKing
+                        * should rotate a qh to the end (for fairness).
+                        */
+                       head = qh->ring.prev;
+                       list_del(&qh->ring);
+                       kfree(qh);
+                       qh = first_qh(head);
+                       break;
+               }
+       }
+       return qh;
+}
+
+/*
+ * Advance this hardware endpoint's queue, completing the specified urb and
+ * advancing to either the next urb queued to that qh, or else invalidating
+ * that qh and advancing to the next qh scheduled after the current one.
+ *
+ * Context: caller owns controller lock, irqs are blocked
+ */
+static void
+musb_advance_schedule(struct musb *pThis, struct urb *urb,
+               struct musb_hw_ep *pEnd, int is_in)
+{
+       struct musb_qh  *qh;
+
+       if (is_in || pEnd->bIsSharedFifo)
+               qh = pEnd->in_qh;
+       else
+               qh = pEnd->out_qh;
+       qh = musb_giveback(qh, urb, 0);
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+       /* REVISIT udelay reportedly works around issues in unmodified
+        * Mentor RTL before v1.5, where it doesn't disable the pull-up
+        * resisters in high speed mode.  That causes signal reflection
+        * and errors because inter packet IDLE time vanishes.
+        *
+        * Yes, this delay makes DMA-OUT a bit slower than PIO.  But
+        * without it, some devices are unusable.  But there seem to be
+        * other issues too, at least on DaVinci; the delay improves
+        * some full speed cases, and being DMA-coupled is strange...
+        */
+       if (is_dma_capable() && !is_in && pEnd->tx_channel)
+               udelay(15);     /* 10 usec ~= 1x 512byte packet */
+#endif
+
+       if (qh && qh->is_ready && !list_empty(&qh->hep->urb_list)) {
+               DBG(4, "... next ep%d %cX urb %p\n",
+                               pEnd->bLocalEnd, is_in ? 'R' : 'T',
+                               next_urb(qh));
+               musb_start_urb(pThis, is_in, qh);
+       }
+}
+
+static inline u16 musb_h_flush_rxfifo(struct musb_hw_ep *hw_ep, u16 csr)
+{
+       /* we don't want fifo to fill itself again;
+        * ignore dma (various models),
+        * leave toggle alone (may not have been saved yet)
+        */
+       csr |= MGC_M_RXCSR_FLUSHFIFO | MGC_M_RXCSR_RXPKTRDY;
+       csr &= ~( MGC_M_RXCSR_H_REQPKT
+               | MGC_M_RXCSR_H_AUTOREQ
+               | MGC_M_RXCSR_AUTOCLEAR
+               );
+
+       /* write 2x to allow double buffering */
+       musb_writew(hw_ep->regs, MGC_O_HDRC_RXCSR, csr);
+       musb_writew(hw_ep->regs, MGC_O_HDRC_RXCSR, csr);
+
+       /* flush writebuffer */
+       return musb_readw(hw_ep->regs, MGC_O_HDRC_RXCSR);
+}
+
+/*
+ * PIO RX for a packet (or part of it).
+ */
+static u8 musb_host_packet_rx(struct musb *pThis, struct urb *pUrb,
+               u8 bEnd, u8 bIsochError)
+{
+       u16 wRxCount;
+       u8 *pBuffer;
+       u16 wCsr;
+       u8 bDone = FALSE;
+       u32                     length;
+       int                     do_flush = 0;
+       struct musb_hw_ep       *pEnd = pThis->aLocalEnd + bEnd;
+       void __iomem            *epio = pEnd->regs;
+       struct musb_qh          *qh = pEnd->in_qh;
+       int                     nPipe = pUrb->pipe;
+       void                    *buffer = pUrb->transfer_buffer;
+
+       // MGC_SelectEnd(pBase, bEnd);
+       wRxCount = musb_readw(epio, MGC_O_HDRC_RXCOUNT);
+
+       /* unload FIFO */
+       if (usb_pipeisoc(nPipe)) {
+               int                                     status = 0;
+               struct usb_iso_packet_descriptor        *d;
+
+               if (bIsochError) {
+                       status = -EILSEQ;
+                       pUrb->error_count++;
+               }
+
+               d = pUrb->iso_frame_desc + qh->iso_idx;
+               pBuffer = buffer + d->offset;
+               length = d->length;
+               if (wRxCount > length) {
+                       if (status == 0) {
+                               status = -EOVERFLOW;
+                               pUrb->error_count++;
+                       }
+                       DBG(2, "** OVERFLOW %d into %d\n", wRxCount, length);
+                       do_flush = 1;
+               } else
+                       length = wRxCount;
+               pUrb->actual_length += length;
+               d->actual_length = length;
+
+               d->status = status;
+
+               /* see if we are done */
+               bDone = (++qh->iso_idx >= pUrb->number_of_packets);
+       } else {
+               /* non-isoch */
+               pBuffer = buffer + qh->offset;
+               length = pUrb->transfer_buffer_length - qh->offset;
+               if (wRxCount > length) {
+                       if (pUrb->status == -EINPROGRESS)
+                               pUrb->status = -EOVERFLOW;
+                       DBG(2, "** OVERFLOW %d into %d\n", wRxCount, length);
+                       do_flush = 1;
+               } else
+                       length = wRxCount;
+               pUrb->actual_length += length;
+               qh->offset += length;
+
+               /* see if we are done */
+               bDone = (pUrb->actual_length == pUrb->transfer_buffer_length)
+                       || (wRxCount < qh->maxpacket)
+                       || (pUrb->status != -EINPROGRESS);
+               if (bDone
+                               && (pUrb->status == -EINPROGRESS)
+                               && (pUrb->transfer_flags & URB_SHORT_NOT_OK)
+                               && (pUrb->actual_length
+                                       < pUrb->transfer_buffer_length))
+                       pUrb->status = -EREMOTEIO;
+       }
+
+       musb_read_fifo(pEnd, length, pBuffer);
+
+       wCsr = musb_readw(epio, MGC_O_HDRC_RXCSR);
+       wCsr |= MGC_M_RXCSR_H_WZC_BITS;
+       if (unlikely(do_flush))
+               musb_h_flush_rxfifo(pEnd, wCsr);
+       else {
+               /* REVISIT this assumes AUTOCLEAR is never set */
+               wCsr &= ~(MGC_M_RXCSR_RXPKTRDY | MGC_M_RXCSR_H_REQPKT);
+               if (!bDone)
+                       wCsr |= MGC_M_RXCSR_H_REQPKT;
+               musb_writew(epio, MGC_O_HDRC_RXCSR, wCsr);
+       }
+
+       return bDone;
+}
+
+/* we don't always need to reinit a given side of an endpoint...
+ * when we do, use tx/rx reinit routine and then construct a new CSR
+ * to address data toggle, NYET, and DMA or PIO.
+ *
+ * it's possible that driver bugs (especially for DMA) or aborting a
+ * transfer might have left the endpoint busier than it should be.
+ * the busy/not-empty tests are basically paranoia.
+ */
+static void
+musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep)
+{
+       u16     csr;
+
+       /* NOTE:  we know the "rx" fifo reinit never triggers for ep0.
+        * That always uses tx_reinit since ep0 repurposes TX register
+        * offsets; the initial SETUP packet is also a kind of OUT.
+        */
+
+       /* if programmed for Tx, put it in RX mode */
+       if (ep->bIsSharedFifo) {
+               csr = musb_readw(ep->regs, MGC_O_HDRC_TXCSR);
+               if (csr & MGC_M_TXCSR_MODE) {
+                       if (csr & MGC_M_TXCSR_FIFONOTEMPTY) {
+                               /* this shouldn't happen; irq?? */
+                               ERR("shared fifo not empty?\n");
+                               musb_writew(ep->regs, MGC_O_HDRC_TXCSR,
+                                               MGC_M_TXCSR_FLUSHFIFO);
+                               musb_writew(ep->regs, MGC_O_HDRC_TXCSR,
+                                               MGC_M_TXCSR_FRCDATATOG);
+                       }
+               }
+               /* clear mode (and everything else) to enable Rx */
+               musb_writew(ep->regs, MGC_O_HDRC_TXCSR, 0);
+
+       /* scrub all previous state, clearing toggle */
+       } else {
+               csr = musb_readw(ep->regs, MGC_O_HDRC_RXCSR);
+               if (csr & MGC_M_RXCSR_RXPKTRDY)
+                       WARN("rx%d, packet/%d ready?\n", ep->bLocalEnd,
+                               musb_readw(ep->regs, MGC_O_HDRC_RXCOUNT));
+
+               musb_h_flush_rxfifo(ep, MGC_M_RXCSR_CLRDATATOG);
+       }
+
+       /* target addr and (for multipoint) hub addr/port */
+       if (musb->bIsMultipoint) {
+               musb_writeb(ep->target_regs, MGC_O_HDRC_RXFUNCADDR,
+                       qh->addr_reg);
+               musb_writeb(ep->target_regs, MGC_O_HDRC_RXHUBADDR,
+                       qh->h_addr_reg);
+               musb_writeb(ep->target_regs, MGC_O_HDRC_RXHUBPORT,
+                       qh->h_port_reg);
+       } else
+               musb_writeb(musb->pRegs, MGC_O_HDRC_FADDR, qh->addr_reg);
+
+       /* protocol/endpoint, interval/NAKlimit, i/o size */
+       musb_writeb(ep->regs, MGC_O_HDRC_RXTYPE, qh->type_reg);
+       musb_writeb(ep->regs, MGC_O_HDRC_RXINTERVAL, qh->intv_reg);
+       /* NOTE: bulk combining rewrites high bits of maxpacket */
+       musb_writew(ep->regs, MGC_O_HDRC_RXMAXP, qh->maxpacket);
+
+       ep->rx_reinit = 0;
+}
+
+
+/*
+ * Program an HDRC endpoint as per the given URB
+ * Context: irqs blocked, controller lock held
+ */
+static void musb_ep_program(struct musb *pThis, u8 bEnd,
+                       struct urb *pUrb, unsigned int is_out,
+                       u8 * pBuffer, u32 dwLength)
+{
+       struct dma_controller   *pDmaController;
+       struct dma_channel      *pDmaChannel;
+       u8                      bDmaOk;
+       void __iomem            *pBase = pThis->pRegs;
+       struct musb_hw_ep       *pEnd = pThis->aLocalEnd + bEnd;
+       void __iomem            *epio = pEnd->regs;
+       struct musb_qh          *qh;
+       u16                     wPacketSize;
+
+       if (!is_out || pEnd->bIsSharedFifo)
+               qh = pEnd->in_qh;
+       else
+               qh = pEnd->out_qh;
+
+       wPacketSize = qh->maxpacket;
+
+       DBG(3, "%s hw%d urb %p spd%d dev%d ep%d%s "
+                               "h_addr%02x h_port%02x bytes %d\n",
+                       is_out ? "-->" : "<--",
+                       bEnd, pUrb, pUrb->dev->speed,
+                       qh->addr_reg, qh->epnum, is_out ? "out" : "in",
+                       qh->h_addr_reg, qh->h_port_reg,
+                       dwLength);
+
+       MGC_SelectEnd(pBase, bEnd);
+
+       /* candidate for DMA? */
+       pDmaController = pThis->pDmaController;
+       if (is_dma_capable() && bEnd && pDmaController) {
+               pDmaChannel = is_out ? pEnd->tx_channel : pEnd->rx_channel;
+               if (!pDmaChannel) {
+                       pDmaChannel = pDmaController->channel_alloc(
+                                       pDmaController, pEnd, is_out);
+                       if (is_out)
+                               pEnd->tx_channel = pDmaChannel;
+                       else
+                               pEnd->rx_channel = pDmaChannel;
+               }
+       } else
+               pDmaChannel = NULL;
+
+       /* make sure we clear DMAEnab, autoSet bits from previous run */
+
+       /* OUT/transmit/EP0 or IN/receive? */
+       if (is_out) {
+               u16     wCsr;
+               u16     wIntrTxE;
+               u16     wLoadCount;
+
+               wCsr = musb_readw(epio, MGC_O_HDRC_TXCSR);
+
+               /* disable interrupt in case we flush */
+               wIntrTxE = musb_readw(pBase, MGC_O_HDRC_INTRTXE);
+               musb_writew(pBase, MGC_O_HDRC_INTRTXE, wIntrTxE & ~(1 << bEnd));
+
+               /* general endpoint setup */
+               if (bEnd) {
+                       u16     csr = wCsr;
+
+                       /* ASSERT:  TXCSR_DMAENAB was already cleared */
+
+                       /* flush all old state, set default */
+                       if (csr & MGC_M_TXCSR_FIFONOTEMPTY)
+                               csr |= MGC_M_TXCSR_FLUSHFIFO;
+                       csr &= ~(MGC_M_TXCSR_H_NAKTIMEOUT
+                                       | MGC_M_TXCSR_DMAMODE
+                                       | MGC_M_TXCSR_FRCDATATOG
+                                       | MGC_M_TXCSR_H_RXSTALL
+                                       | MGC_M_TXCSR_H_ERROR
+                                       | MGC_M_TXCSR_FIFONOTEMPTY
+                                       | MGC_M_TXCSR_TXPKTRDY
+                                       );
+                       csr |= MGC_M_TXCSR_MODE;
+
+                       if (usb_gettoggle(pUrb->dev,
+                                       qh->epnum, 1))
+                               csr |= MGC_M_TXCSR_H_WR_DATATOGGLE
+                                       | MGC_M_TXCSR_H_DATATOGGLE;
+                       else
+                               csr |= MGC_M_TXCSR_CLRDATATOG;
+
+                       /* twice in case of double packet buffering */
+                       musb_writew(epio, MGC_O_HDRC_TXCSR, csr);
+                       /* REVISIT may need to clear FLUSHFIFO ... */
+                       musb_writew(epio, MGC_O_HDRC_TXCSR, csr);
+                       wCsr = musb_readw(epio, MGC_O_HDRC_TXCSR);
+               } else {
+                       /* endpoint 0: just flush */
+                       musb_writew(epio, MGC_O_HDRC_CSR0,
+                               wCsr | MGC_M_CSR0_FLUSHFIFO);
+                       musb_writew(epio, MGC_O_HDRC_CSR0,
+                               wCsr | MGC_M_CSR0_FLUSHFIFO);
+               }
+
+               /* target addr and (for multipoint) hub addr/port */
+               if (pThis->bIsMultipoint) {
+                       musb_writeb(pBase,
+                               MGC_BUSCTL_OFFSET(bEnd, MGC_O_HDRC_TXFUNCADDR),
+                               qh->addr_reg);
+                       musb_writeb(pBase,
+                               MGC_BUSCTL_OFFSET(bEnd, MGC_O_HDRC_TXHUBADDR),
+                               qh->h_addr_reg);
+                       musb_writeb(pBase,
+                               MGC_BUSCTL_OFFSET(bEnd, MGC_O_HDRC_TXHUBPORT),
+                               qh->h_port_reg);
+/* FIXME if !bEnd, do the same for RX ... */
+               } else
+                       musb_writeb(pBase, MGC_O_HDRC_FADDR, qh->addr_reg);
+
+               /* protocol/endpoint/interval/NAKlimit */
+               if (bEnd) {
+                       musb_writeb(epio, MGC_O_HDRC_TXTYPE, qh->type_reg);
+                       if (can_bulk_split(pThis, qh->type))
+                               musb_writew(epio, MGC_O_HDRC_TXMAXP,
+                                       wPacketSize
+                                       | ((pEnd->wMaxPacketSizeTx /
+                                               wPacketSize) - 1) << 11);
+                       else
+                               musb_writew(epio, MGC_O_HDRC_TXMAXP,
+                                       wPacketSize);
+                       musb_writeb(epio, MGC_O_HDRC_TXINTERVAL, qh->intv_reg);
+               } else {
+                       musb_writeb(epio, MGC_O_HDRC_NAKLIMIT0, qh->intv_reg);
+                       if (pThis->bIsMultipoint)
+                               musb_writeb(epio, MGC_O_HDRC_TYPE0,
+                                               qh->type_reg);
+               }
+
+               if (can_bulk_split(pThis, qh->type))
+                       wLoadCount = min((u32) pEnd->wMaxPacketSizeTx,
+                                               dwLength);
+               else
+                       wLoadCount = min((u32) wPacketSize, dwLength);
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+               if (pDmaChannel) {
+
+                       /* clear previous state */
+                       wCsr = musb_readw(epio, MGC_O_HDRC_TXCSR);
+                       wCsr &= ~(MGC_M_TXCSR_AUTOSET
+                               | MGC_M_TXCSR_DMAMODE
+                               | MGC_M_TXCSR_DMAENAB);
+                        wCsr |= MGC_M_TXCSR_MODE;
+                       musb_writew(epio, MGC_O_HDRC_TXCSR,
+                               wCsr | MGC_M_TXCSR_MODE);
+
+                       qh->segsize = min(dwLength, pDmaChannel->dwMaxLength);
+
+                       if (qh->segsize <= wPacketSize)
+                               pDmaChannel->bDesiredMode = 0;
+                       else
+                               pDmaChannel->bDesiredMode = 1;
+
+
+                       if (pDmaChannel->bDesiredMode == 0) {
+                               wCsr &= ~(MGC_M_TXCSR_AUTOSET
+                                       | MGC_M_TXCSR_DMAMODE);
+                               wCsr |= (MGC_M_TXCSR_DMAENAB);
+                                       // against programming guide
+                       } else
+                               wCsr |= (MGC_M_TXCSR_AUTOSET
+                                       | MGC_M_TXCSR_DMAENAB
+                                       | MGC_M_TXCSR_DMAMODE);
+
+                       musb_writew(epio, MGC_O_HDRC_TXCSR, wCsr);
+
+                       bDmaOk = pDmaController->channel_program(
+                                       pDmaChannel, wPacketSize,
+                                       pDmaChannel->bDesiredMode,
+                                       pUrb->transfer_dma,
+                                       qh->segsize);
+                       if (bDmaOk) {
+                               wLoadCount = 0;
+                       } else {
+                               pDmaController->channel_release(pDmaChannel);
+                               if (is_out)
+                                       pEnd->tx_channel = NULL;
+                               else
+                                       pEnd->rx_channel = NULL;
+                               pDmaChannel = NULL;
+                       }
+               }
+#endif
+
+               /* candidate for DMA */
+               if (is_cppi_enabled() && pDmaChannel) {
+
+                       /* program endpoint CSRs first, then setup DMA.
+                        * assume CPPI setup succeeds.
+                        * defer enabling dma.
+                        */
+                       wCsr = musb_readw(epio, MGC_O_HDRC_TXCSR);
+                       wCsr &= ~(MGC_M_TXCSR_AUTOSET
+                                       | MGC_M_TXCSR_DMAMODE
+                                       | MGC_M_TXCSR_DMAENAB);
+                       wCsr |= MGC_M_TXCSR_MODE;
+                       musb_writew(epio, MGC_O_HDRC_TXCSR,
+                               wCsr | MGC_M_TXCSR_MODE);
+
+                       pDmaChannel->dwActualLength = 0L;
+                       qh->segsize = dwLength;
+
+                       /* TX uses "rndis" mode automatically, but needs help
+                        * to identify the zero-length-final-packet case.
+                        */
+                       bDmaOk = pDmaController->channel_program(
+                                       pDmaChannel, wPacketSize,
+                                       (pUrb->transfer_flags
+                                                       & URB_ZERO_PACKET)
+                                               == URB_ZERO_PACKET,
+                                       pUrb->transfer_dma,
+                                       qh->segsize);
+                       if (bDmaOk) {
+                               wLoadCount = 0;
+                       } else {
+                               pDmaController->channel_release(pDmaChannel);
+                               pDmaChannel = pEnd->tx_channel = NULL;
+
+                               /* REVISIT there's an error path here that
+                                * needs handling:  can't do dma, but
+                                * there's no pio buffer address...
+                                */
+                       }
+               }
+
+               if (wLoadCount) {
+                       /* ASSERT:  TXCSR_DMAENAB was already cleared */
+
+                       /* PIO to load FIFO */
+                       qh->segsize = wLoadCount;
+                       musb_write_fifo(pEnd, wLoadCount, pBuffer);
+                       wCsr = musb_readw(epio, MGC_O_HDRC_TXCSR);
+                       wCsr &= ~(MGC_M_TXCSR_DMAENAB
+                               | MGC_M_TXCSR_DMAMODE
+                               | MGC_M_TXCSR_AUTOSET);
+                       /* write CSR */
+                       wCsr |= MGC_M_TXCSR_MODE;
+
+                       if (bEnd)
+                               musb_writew(epio, MGC_O_HDRC_TXCSR, wCsr);
+               }
+
+               /* re-enable interrupt */
+               musb_writew(pBase, MGC_O_HDRC_INTRTXE, wIntrTxE);
+
+       /* IN/receive */
+       } else {
+               u16     csr;
+
+               if (pEnd->rx_reinit) {
+                       musb_rx_reinit(pThis, qh, pEnd);
+
+                       /* init new state: toggle and NYET, maybe DMA later */
+                       if (usb_gettoggle(pUrb->dev, qh->epnum, 0))
+                               csr = MGC_M_RXCSR_H_WR_DATATOGGLE
+                                       | MGC_M_RXCSR_H_DATATOGGLE;
+                       else
+                               csr = 0;
+                       if (qh->type == USB_ENDPOINT_XFER_INT)
+                               csr |= MGC_M_RXCSR_DISNYET;
+
+               } else {
+                       csr = musb_readw(pEnd->regs, MGC_O_HDRC_RXCSR);
+
+                       if (csr & (MGC_M_RXCSR_RXPKTRDY
+                                       | MGC_M_RXCSR_DMAENAB
+                                       | MGC_M_RXCSR_H_REQPKT))
+                               ERR("broken !rx_reinit, ep%d csr %04x\n",
+                                               pEnd->bLocalEnd, csr);
+
+                       /* scrub any stale state, leaving toggle alone */
+                       csr &= MGC_M_RXCSR_DISNYET;
+               }
+
+               /* kick things off */
+
+               if (is_cppi_enabled()) {
+                       /* candidate for DMA */
+                       if (pDmaChannel) {
+                               pDmaChannel->dwActualLength = 0L;
+                               qh->segsize = dwLength;
+
+                               /* AUTOREQ is in a DMA register */
+                               musb_writew(pEnd->regs, MGC_O_HDRC_RXCSR, csr);
+                               csr = musb_readw(pEnd->regs,
+                                               MGC_O_HDRC_RXCSR);
+
+                               /* unless caller treats short rx transfers as
+                                * errors, we dare not queue multiple transfers.
+                                */
+                               bDmaOk = pDmaController->channel_program(
+                                               pDmaChannel, wPacketSize,
+                                               !(pUrb->transfer_flags
+                                                       & URB_SHORT_NOT_OK),
+                                               pUrb->transfer_dma,
+                                               qh->segsize);
+                               if (!bDmaOk) {
+                                       pDmaController->channel_release(
+                                                       pDmaChannel);
+                                       pDmaChannel = pEnd->rx_channel = NULL;
+                               } else
+                                       csr |= MGC_M_RXCSR_DMAENAB;
+                       }
+               }
+
+               csr |= MGC_M_RXCSR_H_REQPKT;
+               DBG(7, "RXCSR%d := %04x\n", bEnd, csr);
+               musb_writew(pEnd->regs, MGC_O_HDRC_RXCSR, csr);
+               csr = musb_readw(pEnd->regs, MGC_O_HDRC_RXCSR);
+       }
+}
+
+
+/*
+ * Service the default endpoint (ep0) as host.
+ * return TRUE if more packets are required for this transaction
+ */
+static u8 musb_h_ep0_continue(struct musb *pThis,
+                               u16 wCount, struct urb *pUrb)
+{
+       u8 bMore = FALSE;
+       u8 *pFifoDest = NULL;
+       u16 wFifoCount = 0;
+       struct musb_hw_ep       *pEnd = pThis->control_ep;
+       struct musb_qh          *qh = pEnd->in_qh;
+       struct usb_ctrlrequest  *pRequest;
+
+       pRequest = (struct usb_ctrlrequest *) pUrb->setup_packet;
+       if (MGC_END0_IN == pThis->bEnd0Stage) {
+               /* we are receiving from peripheral */
+               pFifoDest = pUrb->transfer_buffer + pUrb->actual_length;
+               wFifoCount = min(wCount, ((u16) (pUrb->transfer_buffer_length
+                                       - pUrb->actual_length)));
+               if (wFifoCount < wCount)
+                       pUrb->status = -EOVERFLOW;
+
+               musb_read_fifo(pEnd, wFifoCount, pFifoDest);
+
+               pUrb->actual_length += wFifoCount;
+               if (wCount < qh->maxpacket) {
+                       /* always terminate on short read; it's
+                        * rarely reported as an error.
+                        */
+                       if ((pUrb->transfer_flags & URB_SHORT_NOT_OK)
+                                       && (pUrb->actual_length <
+                                               pUrb->transfer_buffer_length))
+                               pUrb->status = -EREMOTEIO;
+               } else if (pUrb->actual_length <
+                               pUrb->transfer_buffer_length)
+                       bMore = TRUE;
+       } else {
+/*
+       DBG(3, "%s hw%d urb %p spd%d dev%d ep%d%s "
+                               "hub%d port%d%s bytes %d\n",
+                       is_out ? "-->" : "<--",
+                       bEnd, pUrb, pUrb->dev->speed,
+                       bAddress, qh->epnum, is_out ? "out" : "in",
+                       bHubAddr, bHubPort + 1,
+                       bIsMulti ? " multi" : "",
+                       dwLength);
+*/
+               if ((MGC_END0_START == pThis->bEnd0Stage)
+                               && (pRequest->bRequestType & USB_DIR_IN)) {
+                       /* this means we just did setup; switch to IN */
+                       DBG(4, "start IN-DATA\n");
+                       pThis->bEnd0Stage = MGC_END0_IN;
+                       bMore = TRUE;
+
+               } else if (pRequest->wLength
+                               && (MGC_END0_START == pThis->bEnd0Stage)) {
+                       pThis->bEnd0Stage = MGC_END0_OUT;
+                       pFifoDest = (u8 *) (pUrb->transfer_buffer
+                                       + pUrb->actual_length);
+                       wFifoCount = min(qh->maxpacket, ((u16)
+                                       (pUrb->transfer_buffer_length
+                                       - pUrb->actual_length)));
+                       DBG(3, "Sending %d bytes to %p\n",
+                                       wFifoCount, pFifoDest);
+                       musb_write_fifo(pEnd, wFifoCount, pFifoDest);
+
+                       qh->segsize = wFifoCount;
+                       pUrb->actual_length += wFifoCount;
+                       if (pUrb->actual_length
+                                       < pUrb->transfer_buffer_length) {
+                               bMore = TRUE;
+                       }
+               }
+       }
+
+       return bMore;
+}
+
+/*
+ * Handle default endpoint interrupt as host. Only called in IRQ time
+ * from the LinuxIsr() interrupt service routine.
+ *
+ * called with controller irqlocked
+ */
+irqreturn_t musb_h_ep0_irq(struct musb *pThis)
+{
+       struct urb              *pUrb;
+       u16                     wCsrVal, wCount;
+       int                     status = 0;
+       void __iomem            *pBase = pThis->pRegs;
+       struct musb_hw_ep       *pEnd = pThis->control_ep;
+       void __iomem            *epio = pEnd->regs;
+       struct musb_qh          *qh = pEnd->in_qh;
+       u8                      bComplete = FALSE;
+       irqreturn_t             retval = IRQ_NONE;
+
+       /* ep0 only has one queue, "in" */
+       pUrb = next_urb(qh);
+
+       MGC_SelectEnd(pBase, 0);
+       wCsrVal = musb_readw(epio, MGC_O_HDRC_CSR0);
+       wCount = musb_readb(epio, MGC_O_HDRC_COUNT0);
+
+       DBG(4, "<== csr0 %04x, qh %p, count %d, urb %p, stage %d\n",
+               wCsrVal, qh, wCount, pUrb, pThis->bEnd0Stage);
+
+       /* if we just did status stage, we are done */
+       if (MGC_END0_STATUS == pThis->bEnd0Stage) {
+               retval = IRQ_HANDLED;
+               bComplete = TRUE;
+       }
+
+       /* prepare status */
+       if (wCsrVal & MGC_M_CSR0_H_RXSTALL) {
+               DBG(6, "STALLING ENDPOINT\n");
+               status = -EPIPE;
+
+       } else if (wCsrVal & MGC_M_CSR0_H_ERROR) {
+               DBG(2, "no response, csr0 %04x\n", wCsrVal);
+               status = -EPROTO;
+
+       } else if (wCsrVal & MGC_M_CSR0_H_NAKTIMEOUT) {
+               DBG(2, "control NAK timeout\n");
+
+               /* NOTE:  this code path would be a good place to PAUSE a
+                * control transfer, if another one is queued, so that
+                * ep0 is more likely to stay busy.
+                *
+                * if (qh->ring.next != &musb->control), then
+                * we have a candidate... NAKing is *NOT* an error
+                */
+               musb_writew(epio, MGC_O_HDRC_CSR0, 0);
+               retval = IRQ_HANDLED;
+       }
+
+       if (status) {
+               DBG(6, "aborting\n");
+               retval = IRQ_HANDLED;
+               if (pUrb)
+                       pUrb->status = status;
+               bComplete = TRUE;
+
+               /* use the proper sequence to abort the transfer */
+               if (wCsrVal & MGC_M_CSR0_H_REQPKT) {
+                       wCsrVal &= ~MGC_M_CSR0_H_REQPKT;
+                       musb_writew(epio, MGC_O_HDRC_CSR0, wCsrVal);
+                       wCsrVal &= ~MGC_M_CSR0_H_NAKTIMEOUT;
+                       musb_writew(epio, MGC_O_HDRC_CSR0, wCsrVal);
+               } else {
+                       wCsrVal |= MGC_M_CSR0_FLUSHFIFO;
+                       musb_writew(epio, MGC_O_HDRC_CSR0, wCsrVal);
+                       musb_writew(epio, MGC_O_HDRC_CSR0, wCsrVal);
+                       wCsrVal &= ~MGC_M_CSR0_H_NAKTIMEOUT;
+                       musb_writew(epio, MGC_O_HDRC_CSR0, wCsrVal);
+               }
+
+               musb_writeb(epio, MGC_O_HDRC_NAKLIMIT0, 0);
+
+               /* clear it */
+               musb_writew(epio, MGC_O_HDRC_CSR0, 0);
+       }
+
+       if (unlikely(!pUrb)) {
+               /* stop endpoint since we have no place for its data, this
+                * SHOULD NEVER HAPPEN! */
+               ERR("no URB for end 0\n");
+
+               musb_writew(epio, MGC_O_HDRC_CSR0, MGC_M_CSR0_FLUSHFIFO);
+               musb_writew(epio, MGC_O_HDRC_CSR0, MGC_M_CSR0_FLUSHFIFO);
+               musb_writew(epio, MGC_O_HDRC_CSR0, 0);
+
+               goto done;
+       }
+
+       if (!bComplete) {
+               /* call common logic and prepare response */
+               if (musb_h_ep0_continue(pThis, wCount, pUrb)) {
+                       /* more packets required */
+                       wCsrVal = (MGC_END0_IN == pThis->bEnd0Stage)
+                               ?  MGC_M_CSR0_H_REQPKT : MGC_M_CSR0_TXPKTRDY;
+               } else {
+                       /* data transfer complete; perform status phase */
+                       wCsrVal = MGC_M_CSR0_H_STATUSPKT
+                               | (usb_pipeout(pUrb->pipe)
+                                       ? MGC_M_CSR0_H_REQPKT
+                                       : MGC_M_CSR0_TXPKTRDY);
+                       /* flag status stage */
+                       pThis->bEnd0Stage = MGC_END0_STATUS;
+
+                       DBG(5, "ep0 STATUS, csr %04x\n", wCsrVal);
+
+               }
+               musb_writew(epio, MGC_O_HDRC_CSR0, wCsrVal);
+               retval = IRQ_HANDLED;
+       }
+
+       /* call completion handler if done */
+       if (bComplete)
+               musb_advance_schedule(pThis, pUrb, pEnd, 1);
+done:
+       return retval;
+}
+
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+
+/* Host side TX (OUT) using Mentor DMA works as follows:
+       submit_urb ->
+               - if queue was empty, Program Endpoint
+               - ... which starts DMA to fifo in mode 1 or 0
+
+       DMA Isr (transfer complete) -> TxAvail()
+               - Stop DMA (~DmaEnab)   (<--- Alert ... currently happens
+                                       only in musb_cleanup_urb)
+               - TxPktRdy has to be set in mode 0 or for
+                       short packets in mode 1.
+*/
+
+#endif
+
+/* Service a Tx-Available or dma completion irq for the endpoint */
+void musb_host_tx(struct musb *pThis, u8 bEnd)
+{
+       int                     nPipe;
+       u8                      bDone = FALSE;
+       u16                     wTxCsrVal;
+       size_t                  wLength = 0;
+       u8                      *pBuffer = NULL;
+       struct urb              *pUrb;
+       struct musb_hw_ep       *pEnd = pThis->aLocalEnd + bEnd;
+       void __iomem            *epio = pEnd->regs;
+       struct musb_qh          *qh = pEnd->out_qh;
+       u32                     status = 0;
+       void __iomem            *pBase = pThis->pRegs;
+       struct dma_channel      *dma;
+
+       pUrb = next_urb(qh);
+
+       MGC_SelectEnd(pBase, bEnd);
+       wTxCsrVal = musb_readw(epio, MGC_O_HDRC_TXCSR);
+
+       /* with CPPI, DMA sometimes triggers "extra" irqs */
+       if (!pUrb) {
+               DBG(4, "extra TX%d ready, csr %04x\n", bEnd, wTxCsrVal);
+               goto finish;
+       }
+
+       nPipe = pUrb->pipe;
+       dma = is_dma_capable() ? pEnd->tx_channel : NULL;
+       DBG(4, "OUT/TX%d end, csr %04x%s\n", bEnd, wTxCsrVal,
+                       dma ? ", dma" : "");
+
+       /* check for errors */
+       if (wTxCsrVal & MGC_M_TXCSR_H_RXSTALL) {
+               /* dma was disabled, fifo flushed */
+               DBG(3, "TX end %d stall\n", bEnd);
+
+               /* stall; record URB status */
+               status = -EPIPE;
+
+       } else if (wTxCsrVal & MGC_M_TXCSR_H_ERROR) {
+               /* (NON-ISO) dma was disabled, fifo flushed */
+               DBG(3, "TX 3strikes on ep=%d\n", bEnd);
+
+               status = -ETIMEDOUT;
+
+       } else if (wTxCsrVal & MGC_M_TXCSR_H_NAKTIMEOUT) {
+               DBG(6, "TX end=%d device not responding\n", bEnd);
+
+               /* NOTE:  this code path would be a good place to PAUSE a
+                * transfer, if there's some other (nonperiodic) tx urb
+                * that could use this fifo.  (dma complicates it...)
+                *
+                * if (bulk && qh->ring.next != &musb->out_bulk), then
+                * we have a candidate... NAKing is *NOT* an error
+                */
+               MGC_SelectEnd(pBase, bEnd);
+               musb_writew(epio, MGC_O_HDRC_CSR0,
+                               MGC_M_TXCSR_H_WZC_BITS
+                               | MGC_M_TXCSR_TXPKTRDY);
+               goto finish;
+       }
+
+       if (status) {
+               if (dma_channel_status(dma) == MGC_DMA_STATUS_BUSY) {
+                       dma->bStatus = MGC_DMA_STATUS_CORE_ABORT;
+                       (void) pThis->pDmaController->channel_abort(dma);
+               }
+
+               /* do the proper sequence to abort the transfer in the
+                * usb core; the dma engine should already be stopped.
+                */
+// SCRUB (TX)
+               if (wTxCsrVal & MGC_M_TXCSR_FIFONOTEMPTY)
+                       wTxCsrVal |= MGC_M_TXCSR_FLUSHFIFO;
+               wTxCsrVal &= ~(MGC_M_TXCSR_FIFONOTEMPTY
+                               | MGC_M_TXCSR_AUTOSET
+                               | MGC_M_TXCSR_DMAENAB
+                               | MGC_M_TXCSR_H_ERROR
+                               | MGC_M_TXCSR_H_RXSTALL
+                               | MGC_M_TXCSR_H_NAKTIMEOUT
+                               );
+
+               MGC_SelectEnd(pBase, bEnd);
+               musb_writew(epio, MGC_O_HDRC_TXCSR, wTxCsrVal);
+               /* REVISIT may need to clear FLUSHFIFO ... */
+               musb_writew(epio, MGC_O_HDRC_TXCSR, wTxCsrVal);
+               musb_writeb(epio, MGC_O_HDRC_TXINTERVAL, 0);
+
+               bDone = TRUE;
+       }
+
+       /* second cppi case */
+       if (dma_channel_status(dma) == MGC_DMA_STATUS_BUSY) {
+               DBG(4, "extra TX%d ready, csr %04x\n", bEnd, wTxCsrVal);
+               goto finish;
+
+       }
+
+       /* REVISIT this looks wrong... */
+       if (!status || dma || usb_pipeisoc(nPipe)) {
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+               /* mode 0 or last short packet)
+                * REVISIT how about ZLP?
+                */
+               if ((dma->bDesiredMode == 0)
+                               || (dma->dwActualLength
+                                       & (qh->maxpacket - 1))) {
+                       /* Send out the packet first ... */
+                       MGC_SelectEnd(pBase, bEnd);
+                       musb_writew(epio, MGC_O_HDRC_TXCSR,
+                                       MGC_M_TXCSR_TXPKTRDY);
+               }
+#endif
+               if (dma)
+                       wLength = dma->dwActualLength;
+               else
+                       wLength = qh->segsize;
+               qh->offset += wLength;
+
+               if (usb_pipeisoc(nPipe)) {
+                       struct usb_iso_packet_descriptor        *d;
+
+                       d = pUrb->iso_frame_desc + qh->iso_idx;
+                       d->actual_length = qh->segsize;
+                       if (++qh->iso_idx >= pUrb->number_of_packets) {
+                               bDone = TRUE;
+                       } else if (!dma) {
+                               d++;
+                               pBuffer = pUrb->transfer_buffer + d->offset;
+                               wLength = d->length;
+                       }
+               } else if (dma) {
+                       bDone = TRUE;
+               } else {
+                       /* see if we need to send more data, or ZLP */
+                       if (qh->segsize < qh->maxpacket)
+                               bDone = TRUE;
+                       else if (qh->offset == pUrb->transfer_buffer_length
+                                       && !(pUrb-> transfer_flags
+                                                       & URB_ZERO_PACKET))
+                               bDone = TRUE;
+                       if (!bDone) {
+                               pBuffer = pUrb->transfer_buffer
+                                               + qh->offset;
+                               wLength = pUrb->transfer_buffer_length
+                                               - qh->offset;
+                       }
+               }
+       }
+
+       /* urb->status != -EINPROGRESS means request has been faulted,
+        * so we must abort this transfer after cleanup
+        */
+       if (pUrb->status != -EINPROGRESS) {
+               bDone = TRUE;
+               if (status == 0)
+                       status = pUrb->status;
+       }
+
+       if (bDone) {
+               /* set status */
+               pUrb->status = status;
+               pUrb->actual_length = qh->offset;
+               musb_advance_schedule(pThis, pUrb, pEnd, USB_DIR_OUT);
+
+       } else if (!(wTxCsrVal & MGC_M_TXCSR_DMAENAB)) {
+               // WARN_ON(!pBuffer);
+
+               /* REVISIT:  some docs say that when pEnd->tx_double_buffered,
+                * (and presumably, fifo is not half-full) we should write TWO
+                * packets before updating TXCSR ... other docs disagree ...
+                */
+               /* PIO:  start next packet in this URB */
+               wLength = min(qh->maxpacket, (u16) wLength);
+               musb_write_fifo(pEnd, wLength, pBuffer);
+               qh->segsize = wLength;
+
+               MGC_SelectEnd(pBase, bEnd);
+               musb_writew(epio, MGC_O_HDRC_TXCSR,
+                               MGC_M_TXCSR_H_WZC_BITS | MGC_M_TXCSR_TXPKTRDY);
+       } else
+               DBG(1, "not complete, but dma enabled?\n");
+
+finish:
+       return;
+}
+
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+
+/* Host side RX (IN) using Mentor DMA works as follows:
+       submit_urb ->
+               - if queue was empty, ProgramEndpoint
+               - first IN token is sent out (by setting ReqPkt)
+       LinuxIsr -> RxReady()
+       /\      => first packet is received
+       |       - Set in mode 0 (DmaEnab, ~ReqPkt)
+       |               -> DMA Isr (transfer complete) -> RxReady()
+       |                   - Ack receive (~RxPktRdy), turn off DMA (~DmaEnab)
+       |                   - if urb not complete, send next IN token (ReqPkt)
+       |                          |            else complete urb.
+       |                          |
+       ---------------------------
+ *
+ * Nuances of mode 1:
+ *     For short packets, no ack (+RxPktRdy) is sent automatically
+ *     (even if AutoClear is ON)
+ *     For full packets, ack (~RxPktRdy) and next IN token (+ReqPkt) is sent
+ *     automatically => major problem, as collecting the next packet becomes
+ *     difficult. Hence mode 1 is not used.
+ *
+ * REVISIT
+ *     All we care about at this driver level is that
+ *       (a) all URBs terminate with REQPKT cleared and fifo(s) empty;
+ *       (b) termination conditions are: short RX, or buffer full;
+ *       (c) fault modes include
+ *           - iff URB_SHORT_NOT_OK, short RX status is -EREMOTEIO.
+ *             (and that endpoint's dma queue stops immediately)
+ *           - overflow (full, PLUS more bytes in the terminal packet)
+ *
+ *     So for example, usb-storage sets URB_SHORT_NOT_OK, and would
+ *     thus be a great candidate for using mode 1 ... for all but the
+ *     last packet of one URB's transfer.
+ */
+
+#endif
+
+/*
+ * Service an RX interrupt for the given IN endpoint; docs cover bulk, iso,
+ * and high-bandwidth IN transfer cases.
+ */
+void musb_host_rx(struct musb *pThis, u8 bEnd)
+{
+       struct urb              *pUrb;
+       struct musb_hw_ep       *pEnd = pThis->aLocalEnd + bEnd;
+       void __iomem            *epio = pEnd->regs;
+       struct musb_qh          *qh = pEnd->in_qh;
+       size_t                  xfer_len;
+       void __iomem            *pBase = pThis->pRegs;
+       int                     nPipe;
+       u16                     wRxCsrVal, wVal;
+       u8                      bIsochError = FALSE;
+       u8                      bDone = FALSE;
+       u32                     status;
+       struct dma_channel      *dma;
+
+       MGC_SelectEnd(pBase, bEnd);
+
+       pUrb = next_urb(qh);
+       dma = is_dma_capable() ? pEnd->rx_channel : NULL;
+       status = 0;
+       xfer_len = 0;
+
+       wVal = wRxCsrVal = musb_readw(epio, MGC_O_HDRC_RXCSR);
+
+       if (unlikely(!pUrb)) {
+               /* REVISIT -- THIS SHOULD NEVER HAPPEN ... but, at least
+                * usbtest #11 (unlinks) triggers it regularly, sometimes
+                * with fifo full.  (Only with DMA??)
+                */
+               DBG(3, "BOGUS RX%d ready, csr %04x, count %d\n", bEnd, wVal,
+                       musb_readw(epio, MGC_O_HDRC_RXCOUNT));
+               musb_h_flush_rxfifo(pEnd, MGC_M_RXCSR_CLRDATATOG);
+               return;
+       }
+
+       nPipe = pUrb->pipe;
+
+       DBG(5, "<== hw %d rxcsr %04x, urb actual %d (+dma %zd)\n",
+               bEnd, wRxCsrVal, pUrb->actual_length,
+               dma ? dma->dwActualLength : 0);
+
+       /* check for errors, concurrent stall & unlink is not really
+        * handled yet! */
+       if (wRxCsrVal & MGC_M_RXCSR_H_RXSTALL) {
+               DBG(3, "RX end %d STALL\n", bEnd);
+
+               /* stall; record URB status */
+               status = -EPIPE;
+
+       } else if (wRxCsrVal & MGC_M_RXCSR_H_ERROR) {
+               DBG(3, "end %d RX proto error\n", bEnd);
+
+               status = -EPROTO;
+               musb_writeb(epio, MGC_O_HDRC_RXINTERVAL, 0);
+
+       } else if (wRxCsrVal & MGC_M_RXCSR_DATAERROR) {
+
+               if (USB_ENDPOINT_XFER_ISOC != qh->type) {
+                       /* NOTE this code path would be a good place to PAUSE a
+                        * transfer, if there's some other (nonperiodic) rx urb
+                        * that could use this fifo.  (dma complicates it...)
+                        *
+                        * if (bulk && qh->ring.next != &musb->in_bulk), then
+                        * we have a candidate... NAKing is *NOT* an error
+                        */
+                       DBG(6, "RX end %d NAK timeout\n", bEnd);
+                       MGC_SelectEnd(pBase, bEnd);
+                       musb_writew(epio, MGC_O_HDRC_RXCSR,
+                                       MGC_M_RXCSR_H_WZC_BITS
+                                       | MGC_M_RXCSR_H_REQPKT);
+
+                       goto finish;
+               } else {
+                       DBG(4, "RX end %d ISO data error\n", bEnd);
+                       /* packet error reported later */
+                       bIsochError = TRUE;
+               }
+       }
+
+       /* faults abort the transfer */
+       if (status) {
+               /* clean up dma and collect transfer count */
+               if (dma_channel_status(dma) == MGC_DMA_STATUS_BUSY) {
+                       dma->bStatus = MGC_DMA_STATUS_CORE_ABORT;
+                       (void) pThis->pDmaController->channel_abort(dma);
+                       xfer_len = dma->dwActualLength;
+               }
+               musb_h_flush_rxfifo(pEnd, 0);
+               musb_writeb(epio, MGC_O_HDRC_RXINTERVAL, 0);
+               bDone = TRUE;
+               goto finish;
+       }
+
+       if (unlikely(dma_channel_status(dma) == MGC_DMA_STATUS_BUSY)) {
+               /* SHOULD NEVER HAPPEN ... but at least DaVinci has done it */
+               ERR("RX%d dma busy, csr %04x\n", bEnd, wRxCsrVal);
+               goto finish;
+       }
+
+       /* thorough shutdown for now ... given more precise fault handling
+        * and better queueing support, we might keep a DMA pipeline going
+        * while processing this irq for earlier completions.
+        */
+
+       /* FIXME this is _way_ too much in-line logic for Mentor DMA */
+
+#ifndef CONFIG_USB_INVENTRA_DMA
+       if (wRxCsrVal & MGC_M_RXCSR_H_REQPKT)  {
+               /* REVISIT this happened for a while on some short reads...
+                * the cleanup still needs investigation... looks bad...
+                * and also duplicates dma cleanup code above ... plus,
+                * shouldn't this be the "half full" double buffer case?
+                */
+               if (dma_channel_status(dma) == MGC_DMA_STATUS_BUSY) {
+                       dma->bStatus = MGC_DMA_STATUS_CORE_ABORT;
+                       (void) pThis->pDmaController->channel_abort(dma);
+                       xfer_len = dma->dwActualLength;
+                       bDone = TRUE;
+               }
+
+               DBG(2, "RXCSR%d %04x, reqpkt, len %zd%s\n", bEnd, wRxCsrVal,
+                               xfer_len, dma ? ", dma" : "");
+               wRxCsrVal &= ~MGC_M_RXCSR_H_REQPKT;
+
+               MGC_SelectEnd(pBase, bEnd);
+               musb_writew(epio, MGC_O_HDRC_RXCSR,
+                               MGC_M_RXCSR_H_WZC_BITS | wRxCsrVal);
+       }
+#endif
+       if (dma && (wRxCsrVal & MGC_M_RXCSR_DMAENAB)) {
+               xfer_len = dma->dwActualLength;
+
+               wVal &= ~(MGC_M_RXCSR_DMAENAB
+                       | MGC_M_RXCSR_H_AUTOREQ
+                       | MGC_M_RXCSR_AUTOCLEAR
+                       | MGC_M_RXCSR_RXPKTRDY);
+               musb_writew(pEnd->regs, MGC_O_HDRC_RXCSR, wVal);
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+               pUrb->actual_length += xfer_len;
+               qh->offset += xfer_len;
+
+               /* bDone if pUrb buffer is full or short packet is recd */
+               bDone = (pUrb->actual_length >= pUrb->transfer_buffer_length)
+                       || (dma->dwActualLength & (qh->maxpacket - 1));
+
+               /* send IN token for next packet, without AUTOREQ */
+               if (!bDone) {
+                       wVal |= MGC_M_RXCSR_H_REQPKT;
+                       musb_writew(epio, MGC_O_HDRC_RXCSR,
+                               MGC_M_RXCSR_H_WZC_BITS | wVal);
+               }
+
+               DBG(4, "ep %d dma %s, rxcsr %04x, rxcount %d\n", bEnd,
+                       bDone ? "off" : "reset",
+                       musb_readw(epio, MGC_O_HDRC_RXCSR),
+                       musb_readw(epio, MGC_O_HDRC_RXCOUNT));
+#else
+               bDone = TRUE;
+#endif
+       } else if (pUrb->status == -EINPROGRESS) {
+               /* if no errors, be sure a packet is ready for unloading */
+               if (unlikely(!(wRxCsrVal & MGC_M_RXCSR_RXPKTRDY))) {
+                       status = -EPROTO;
+                       ERR("Rx interrupt with no errors or packet!\n");
+
+                       // FIXME this is another "SHOULD NEVER HAPPEN"
+
+// SCRUB (RX)
+                       /* do the proper sequence to abort the transfer */
+                       MGC_SelectEnd(pBase, bEnd);
+                       wVal &= ~MGC_M_RXCSR_H_REQPKT;
+                       musb_writew(epio, MGC_O_HDRC_RXCSR, wVal);
+                       goto finish;
+               }
+
+               /* we are expecting IN packets */
+#ifdef CONFIG_USB_INVENTRA_DMA
+               if (dma) {
+                       struct dma_controller   *c;
+                       u16                     wRxCount;
+                       int                     status;
+
+                       wRxCount = musb_readw(epio, MGC_O_HDRC_RXCOUNT);
+
+                       DBG(2, "RX%d count %d, buffer 0x%x len %d/%d\n",
+                                       bEnd, wRxCount,
+                                       pUrb->transfer_dma
+                                               + pUrb->actual_length,
+                                       qh->offset,
+                                       pUrb->transfer_buffer_length);
+
+                       c = pThis->pDmaController;
+
+                       dma->bDesiredMode = 0;
+#ifdef USE_MODE1
+                       /* because of the issue below, mode 1 will
+                        * only rarely behave with correct semantics.
+                        */
+                       if ((pUrb->transfer_flags &
+                                               URB_SHORT_NOT_OK)
+                               && (pUrb->transfer_buffer_length -
+                                               pUrb->actual_length)
+                                       > qh->maxpacket)
+                               dma->bDesiredMode = 1;
+#endif
+
+/* Disadvantage of using mode 1:
+ *     It's basically usable only for mass storage class; essentially all
+ *     other protocols also terminate transfers on short packets.
+ *
+ * Details:
+ *     An extra IN token is sent at the end of the transfer (due to AUTOREQ)
+ *     If you try to use mode 1 for (transfer_buffer_length - 512), and try
+ *     to use the extra IN token to grab the last packet using mode 0, then
+ *     the problem is that you cannot be sure when the device will send the
+ *     last packet and RxPktRdy set. Sometimes the packet is recd too soon
+ *     such that it gets lost when RxCSR is re-set at the end of the mode 1
+ *     transfer, while sometimes it is recd just a little late so that if you
+ *     try to configure for mode 0 soon after the mode 1 transfer is
+ *     completed, you will find rxcount 0. Okay, so you might think why not
+ *     wait for an interrupt when the pkt is recd. Well, you won't get any!
+ */
+
+                       wVal = musb_readw(epio, MGC_O_HDRC_RXCSR);
+                       wVal &= ~MGC_M_RXCSR_H_REQPKT;
+
+                       if (dma->bDesiredMode == 0)
+                               wVal &= ~MGC_M_RXCSR_H_AUTOREQ;
+                       else
+                               wVal |= MGC_M_RXCSR_H_AUTOREQ;
+                       wVal |= MGC_M_RXCSR_AUTOCLEAR | MGC_M_RXCSR_DMAENAB;
+
+                       musb_writew(epio, MGC_O_HDRC_RXCSR,
+                               MGC_M_RXCSR_H_WZC_BITS | wVal);
+
+                       /* REVISIT if when actual_length != 0,
+                        * transfer_buffer_length needs to be
+                        * adjusted first...
+                        */
+                       status = c->channel_program(
+                               dma, qh->maxpacket,
+                               dma->bDesiredMode,
+                               pUrb->transfer_dma
+                                       + pUrb->actual_length,
+                               (dma->bDesiredMode == 0)
+                                       ? wRxCount
+                                       : pUrb->transfer_buffer_length);
+
+                       if (!status) {
+                               c->channel_release(dma);
+                               dma = pEnd->rx_channel = NULL;
+                               /* REVISIT reset CSR */
+                       }
+               }
+#endif /* Mentor DMA */
+
+               if (!dma) {
+                       bDone = musb_host_packet_rx(pThis, pUrb,
+                                       bEnd, bIsochError);
+                       DBG(6, "read %spacket\n", bDone ? "last " : "");
+               }
+       }
+
+finish:
+       pUrb->actual_length += xfer_len;
+       qh->offset += xfer_len;
+       if (bDone) {
+               if (pUrb->status == -EINPROGRESS)
+                       pUrb->status = status;
+               musb_advance_schedule(pThis, pUrb, pEnd, USB_DIR_IN);
+       }
+}
+
+/* schedule nodes correspond to peripheral endpoints, like an OHCI QH.
+ * the software schedule associates multiple such nodes with a given
+ * host side hardware endpoint + direction; scheduling may activate
+ * that hardware endpoint.
+ */
+static int musb_schedule(
+       struct musb             *musb,
+       struct musb_qh          *qh,
+       int                     is_in)
+{
+       int                     idle;
+       int                     wBestDiff;
+       int                     nBestEnd, nEnd;
+       struct musb_hw_ep       *hw_ep = NULL;
+       struct list_head        *head = NULL;
+
+       /* use fixed hardware for control and bulk */
+       switch (qh->type) {
+       case USB_ENDPOINT_XFER_CONTROL:
+               head = &musb->control;
+               hw_ep = musb->control_ep;
+               break;
+       case USB_ENDPOINT_XFER_BULK:
+               hw_ep = musb->bulk_ep;
+               if (is_in)
+                       head = &musb->in_bulk;
+               else
+                       head = &musb->out_bulk;
+               break;
+       }
+       if (head) {
+               idle = list_empty(head);
+               list_add_tail(&qh->ring, head);
+               goto success;
+       }
+
+       /* else, periodic transfers get muxed to other endpoints */
+
+       /* FIXME this doesn't consider direction, so it can only
+        * work for one half of the endpoint hardware, and assumes
+        * the previous cases handled all non-shared endpoints...
+        */
+
+       /* we know this qh hasn't been scheduled, so all we need to do
+        * is choose which hardware endpoint to put it on ...
+        *
+        * REVISIT what we really want here is a regular schedule tree
+        * like e.g. OHCI uses, but for now musb->periodic is just an
+        * array of the _single_ logical endpoint associated with a
+        * given physical one (identity mapping logical->physical).
+        *
+        * that simplistic approach makes TT scheduling a lot simpler;
+        * there is none, and thus none of its complexity...
+        */
+       wBestDiff = 4096;
+       nBestEnd = -1;
+
+       for (nEnd = 1; nEnd < musb->bEndCount; nEnd++) {
+               int     diff;
+
+               if (musb->periodic[nEnd])
+                       continue;
+               hw_ep = &musb->aLocalEnd[nEnd];
+               if (hw_ep == musb->bulk_ep)
+                       continue;
+
+               if (is_in)
+                       diff = hw_ep->wMaxPacketSizeRx - qh->maxpacket;
+               else
+                       diff = hw_ep->wMaxPacketSizeTx - qh->maxpacket;
+
+               if (diff > 0 && wBestDiff > diff) {
+                       wBestDiff = diff;
+                       nBestEnd = nEnd;
+               }
+       }
+       if (nBestEnd < 0)
+               return -ENOSPC;
+
+       idle = 1;
+       hw_ep = musb->aLocalEnd + nBestEnd;
+       musb->periodic[nBestEnd] = qh;
+       DBG(4, "qh %p periodic slot %d\n", qh, nBestEnd);
+success:
+       qh->hw_ep = hw_ep;
+       qh->hep->hcpriv = qh;
+       if (idle)
+               musb_start_urb(musb, is_in, qh);
+       return 0;
+}
+
+static int musb_urb_enqueue(
+       struct usb_hcd                  *hcd,
+       struct usb_host_endpoint        *hep,
+       struct urb                      *urb,
+       gfp_t                           mem_flags)
+{
+       unsigned long                   flags;
+       struct musb                     *musb = hcd_to_musb(hcd);
+       struct musb_qh                  *qh = hep->hcpriv;
+       struct usb_endpoint_descriptor  *epd = &hep->desc;
+       int                             status;
+       unsigned                        type_reg;
+       unsigned                        interval;
+
+       /* host role must be active */
+       if (!is_host_active(musb) || !musb->is_active)
+               return -ENODEV;
+
+       /* DMA mapping was already done, if needed, and this urb is on
+        * hep->urb_list ... so there's little to do unless hep wasn't
+        * yet scheduled onto a live qh.
+        *
+        * REVISIT best to keep hep->hcpriv valid until the endpoint gets
+        * disabled, testing for empty qh->ring and avoiding qh setup costs
+        * except for the first urb queued after a config change.
+        */
+       if (qh) {
+               urb->hcpriv = qh;
+               return 0;
+       }
+
+       /* Allocate and initialize qh, minimizing the work done each time
+        * hw_ep gets reprogrammed, or with irqs blocked.  Then schedule it.
+        *
+        * REVISIT consider a dedicated qh kmem_cache, so it's harder
+        * for bugs in other kernel code to break this driver...
+        */
+       qh = kzalloc(sizeof *qh, mem_flags);
+       if (!qh)
+               return -ENOMEM;
+
+       qh->hep = hep;
+       qh->dev = urb->dev;
+       INIT_LIST_HEAD(&qh->ring);
+       qh->is_ready = 1;
+
+       qh->maxpacket = le16_to_cpu(epd->wMaxPacketSize);
+
+       /* no high bandwidth support yet */
+       if (qh->maxpacket & ~0x7ff) {
+               status = -EMSGSIZE;
+               goto done;
+       }
+
+       qh->epnum = epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+       qh->type = epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+       /* NOTE: urb->dev->devnum is wrong during SET_ADDRESS */
+       qh->addr_reg = (u8) usb_pipedevice(urb->pipe);
+
+       /* precompute rxtype/txtype/type0 register */
+       type_reg = (qh->type << 4) | qh->epnum;
+       switch (urb->dev->speed) {
+       case USB_SPEED_LOW:
+               type_reg |= 0xc0;
+               break;
+       case USB_SPEED_FULL:
+               type_reg |= 0x80;
+               break;
+       default:
+               type_reg |= 0x40;
+       }
+       qh->type_reg = type_reg;
+
+       /* precompute rxinterval/txinterval register */
+       interval = min((u8)16, epd->bInterval); /* log encoding */
+       switch (qh->type) {
+       case USB_ENDPOINT_XFER_INT:
+               /* fullspeed uses linear encoding */
+               if (USB_SPEED_FULL == urb->dev->speed) {
+                       interval = epd->bInterval;
+                       if (!interval)
+                               interval = 1;
+               }
+               /* FALLTHROUGH */
+       case USB_ENDPOINT_XFER_ISOC:
+               /* iso always uses log encoding */
+               break;
+       default:
+               /* REVISIT we actually want to use NAK limits, hinting to the
+                * transfer scheduling logic to try some other qh, e.g. try
+                * for 2 msec first:
+                *
+                * interval = (USB_SPEED_HIGH == pUrb->dev->speed) ? 16 : 2;
+                *
+                * The downside of disabling this is that transfer scheduling
+                * gets VERY unfair for nonperiodic transfers; a misbehaving
+                * peripheral could make that hurt.  Or for reads, one that's
+                * perfectly normal:  network and other drivers keep reads
+                * posted at all times, having one pending for a week should
+                * be perfectly safe.
+                *
+                * The upside of disabling it is avoidng transfer scheduling
+                * code to put this aside for while.
+                */
+               interval = 0;
+       }
+       qh->intv_reg = interval;
+
+       /* precompute addressing for external hub/tt ports */
+       if (musb->bIsMultipoint) {
+               struct usb_device       *parent = urb->dev->parent;
+
+               if (parent != hcd->self.root_hub) {
+                       qh->h_addr_reg = (u8) parent->devnum;
+
+                       /* set up tt info if needed */
+                       if (urb->dev->tt) {
+                               qh->h_port_reg = (u8) urb->dev->ttport;
+                               qh->h_addr_reg |= 0x80;
+                       }
+               }
+       }
+
+       /* invariant: hep->hcpriv is null OR the qh that's already scheduled.
+        * until we get real dma queues (with an entry for each urb/buffer),
+        * we only have work to do in the former case.
+        */
+       spin_lock_irqsave(&musb->Lock, flags);
+       if (hep->hcpriv) {
+               /* some concurrent activity submitted another urb to hep...
+                * odd, rare, error prone, but legal.
+                */
+               kfree(qh);
+               status = 0;
+       } else
+               status = musb_schedule(musb, qh,
+                               epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK);
+
+       if (status == 0) {
+               urb->hcpriv = qh;
+               /* FIXME set urb->start_frame for iso/intr, it's tested in
+                * musb_start_urb(), but otherwise only konicawc cares ...
+                */
+       }
+       spin_unlock_irqrestore(&musb->Lock, flags);
+
+done:
+       if (status != 0)
+               kfree(qh);
+       return status;
+}
+
+
+/*
+ * abort a transfer that's at the head of a hardware queue.
+ * called with controller locked, irqs blocked
+ * that hardware queue advances to the next transfer, unless prevented
+ */
+static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh, int is_in)
+{
+       struct musb_hw_ep       *ep = qh->hw_ep;
+       void __iomem            *epio = ep->regs;
+       unsigned                hw_end = ep->bLocalEnd;
+       void __iomem            *regs = ep->musb->pRegs;
+       u16                     csr;
+       int                     status = 0;
+
+       MGC_SelectEnd(regs, hw_end);
+
+       if (is_dma_capable()) {
+               struct dma_channel      *dma;
+
+               dma = is_in ? ep->rx_channel : ep->tx_channel;
+               if (dma) {
+                       status = ep->musb->pDmaController->channel_abort(dma);
+                       DBG(status ? 1 : 3,
+                               "abort %cX%d DMA for urb %p --> %d\n",
+                               is_in ? 'R' : 'T', ep->bLocalEnd,
+                               urb, status);
+                       urb->actual_length += dma->dwActualLength;
+               }
+       }
+
+       /* turn off DMA requests, discard state, stop polling ... */
+       if (is_in) {
+               /* giveback saves bulk toggle */
+               csr = musb_h_flush_rxfifo(ep, 0);
+
+               /* REVISIT we still get an irq; should likely clear the
+                * endpoint's irq status here to avoid bogus irqs.
+                * clearing that status is platform-specific...
+                */
+       } else {
+// SCRUB (TX)
+               csr = musb_readw(epio, MGC_O_HDRC_TXCSR);
+               if (csr & MGC_M_TXCSR_FIFONOTEMPTY)
+                       csr |= MGC_M_TXCSR_FLUSHFIFO;
+               csr &= ~( MGC_M_TXCSR_AUTOSET
+                       | MGC_M_TXCSR_DMAENAB
+                       | MGC_M_TXCSR_H_RXSTALL
+                       | MGC_M_TXCSR_H_NAKTIMEOUT
+                       | MGC_M_TXCSR_H_ERROR
+                       | MGC_M_TXCSR_FIFONOTEMPTY
+                       );
+               musb_writew(epio, MGC_O_HDRC_TXCSR, csr);
+               /* REVISIT may need to clear FLUSHFIFO ... */
+               musb_writew(epio, MGC_O_HDRC_TXCSR, csr);
+               /* flush cpu writebuffer */
+               csr = musb_readw(epio, MGC_O_HDRC_TXCSR);
+       }
+       if (status == 0)
+               musb_advance_schedule(ep->musb, urb, ep, is_in);
+       return status;
+}
+
+static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+{
+       struct musb             *musb = hcd_to_musb(hcd);
+       struct musb_qh          *qh;
+       struct list_head        *sched;
+       struct urb              *tmp;
+       unsigned long           flags;
+       int                     status = -ENOENT;
+
+       DBG(4, "urb=%p, dev%d ep%d%s\n", urb,
+                       usb_pipedevice(urb->pipe),
+                       usb_pipeendpoint(urb->pipe),
+                       usb_pipein(urb->pipe) ? "in" : "out");
+
+       spin_lock_irqsave(&musb->Lock, flags);
+
+       /* make sure the urb is still queued and not completed */
+       spin_lock(&urb->lock);
+       qh = urb->hcpriv;
+       if (qh) {
+               struct usb_host_endpoint        *hep;
+
+               hep = qh->hep;
+               list_for_each_entry(tmp, &hep->urb_list, urb_list) {
+                       if (urb == tmp) {
+                               status = 0;
+                               break;
+                       }
+               }
+       }
+       spin_unlock(&urb->lock);
+       if (status)
+               goto done;
+
+       /* Any URB not actively programmed into endpoint hardware can be
+        * immediately given back.  Such an URB must be at the head of its
+        * endpoint queue, unless someday we get real DMA queues.  And even
+        * then, it might not be known to the hardware...
+        *
+        * Otherwise abort current transfer, pending dma, etc.; urb->status
+        * has already been updated.  This is a synchronous abort; it'd be
+        * OK to hold off until after some IRQ, though.
+        */
+       if (!qh->is_ready || urb->urb_list.prev != &qh->hep->urb_list)
+               status = -EINPROGRESS;
+       else {
+               switch (qh->type) {
+               case USB_ENDPOINT_XFER_CONTROL:
+                       sched = &musb->control;
+                       break;
+               case USB_ENDPOINT_XFER_BULK:
+                       if (usb_pipein(urb->pipe))
+                               sched = &musb->in_bulk;
+                       else
+                               sched = &musb->out_bulk;
+                       break;
+               default:
+                       /* REVISIT when we get a schedule tree, periodic
+                        * transfers won't always be at the head of a
+                        * singleton queue...
+                        */
+                       sched = NULL;
+                       break;
+               }
+       }
+
+       /* NOTE:  qh is invalid unless !list_empty(&hep->urb_list) */
+       if (status < 0 || (sched && qh != first_qh(sched))) {
+               int     ready = qh->is_ready;
+
+               status = 0;
+               qh->is_ready = 0;
+               __musb_giveback(musb, urb, 0);
+               qh->is_ready = ready;
+       } else
+               status = musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
+done:
+       spin_unlock_irqrestore(&musb->Lock, flags);
+       return status;
+}
+
+/* disable an endpoint */
+static void
+musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
+{
+       u8                      epnum = hep->desc.bEndpointAddress;
+       unsigned long           flags;
+       struct musb             *musb = hcd_to_musb(hcd);
+       u8                      is_in = epnum & USB_DIR_IN;
+       struct musb_qh          *qh = hep->hcpriv;
+       struct urb              *urb, *tmp;
+       struct list_head        *sched;
+
+       if (!qh)
+               return;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+
+       switch (qh->type) {
+       case USB_ENDPOINT_XFER_CONTROL:
+               sched = &musb->control;
+               break;
+       case USB_ENDPOINT_XFER_BULK:
+               if (is_in)
+                       sched = &musb->in_bulk;
+               else
+                       sched = &musb->out_bulk;
+               break;
+       default:
+               /* REVISIT when we get a schedule tree, periodic transfers
+                * won't always be at the head of a singleton queue...
+                */
+               sched = NULL;
+               break;
+       }
+
+       /* NOTE:  qh is invalid unless !list_empty(&hep->urb_list) */
+
+       /* kick first urb off the hardware, if needed */
+       qh->is_ready = 0;
+       if (!sched || qh == first_qh(sched)) {
+               urb = next_urb(qh);
+
+               /* make software (then hardware) stop ASAP */
+               spin_lock(&urb->lock);
+               if (urb->status == -EINPROGRESS)
+                       urb->status = -ESHUTDOWN;
+               spin_unlock(&urb->lock);
+
+               /* cleanup */
+               musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
+       } else
+               urb = NULL;
+
+       /* then just nuke all the others */
+       list_for_each_entry_safe_from(urb, tmp, &hep->urb_list, urb_list)
+               musb_giveback(qh, urb, -ESHUTDOWN);
+
+       spin_unlock_irqrestore(&musb->Lock, flags);
+}
+
+static int musb_h_get_frame_number(struct usb_hcd *hcd)
+{
+       struct musb     *musb = hcd_to_musb(hcd);
+
+       return musb_readw(musb->pRegs, MGC_O_HDRC_FRAME);
+}
+
+static int musb_h_start(struct usb_hcd *hcd)
+{
+       /* NOTE: musb_start() is called when the hub driver turns
+        * on port power, or when (OTG) peripheral starts.
+        */
+       hcd->state = HC_STATE_RUNNING;
+       return 0;
+}
+
+static void musb_h_stop(struct usb_hcd *hcd)
+{
+       musb_stop(hcd_to_musb(hcd));
+       hcd->state = HC_STATE_HALT;
+}
+
+static int musb_bus_suspend(struct usb_hcd *hcd)
+{
+       struct musb     *musb = hcd_to_musb(hcd);
+
+       return musb->is_active ? -EBUSY : 0;
+}
+
+static int musb_bus_resume(struct usb_hcd *hcd)
+{
+       /* resuming child port does the work */
+       return 0;
+}
+
+const struct hc_driver musb_hc_driver = {
+       .description            = "musb-hcd",
+       .product_desc           = "MUSB HDRC host driver",
+       .hcd_priv_size          = sizeof (struct musb),
+       .flags                  = HCD_USB2 | HCD_MEMORY,
+
+       /* not using irq handler or reset hooks from usbcore, since
+        * those must be shared with peripheral code for OTG configs
+        */
+
+       .start                  = musb_h_start,
+       .stop                   = musb_h_stop,
+
+       .get_frame_number       = musb_h_get_frame_number,
+
+       .urb_enqueue            = musb_urb_enqueue,
+       .urb_dequeue            = musb_urb_dequeue,
+       .endpoint_disable       = musb_h_disable,
+
+       .hub_status_data        = musb_hub_status_data,
+       .hub_control            = musb_hub_control,
+       .bus_suspend            = musb_bus_suspend,
+       .bus_resume             = musb_bus_resume,
+//     .start_port_reset       = NULL,
+//     .hub_irq_enable         = NULL,
+};
diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h
new file mode 100644 (file)
index 0000000..556db74
--- /dev/null
@@ -0,0 +1,111 @@
+/******************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux 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.
+ *
+ * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+#ifndef _MUSB_HOST_H
+#define _MUSB_HOST_H
+
+static inline struct usb_hcd *musb_to_hcd(struct musb *musb)
+{
+       return (struct usb_hcd *) (((void *)musb)
+                       - offsetof(struct usb_hcd, hcd_priv));
+}
+
+static inline struct musb *hcd_to_musb(struct usb_hcd *hcd)
+{
+       return (void *) hcd->hcd_priv;
+}
+
+/* stored in "usb_host_endpoint.hcpriv" for scheduled endpoints
+ */
+struct musb_qh {
+       struct usb_host_endpoint *hep;          /* usbcore info */
+       struct usb_device       *dev;
+       struct musb_hw_ep       *hw_ep;         /* current binding */
+
+       struct list_head        ring;           /* of musb_qh */
+       //struct musb_qh                *next;          /* for periodic tree */
+
+       unsigned                offset;         /* in urb->transfer_buffer */
+       unsigned                segsize;        /* current xfer fragment */
+
+       u8                      type_reg;       /* {rx,tx} type register */
+       u8                      intv_reg;       /* {rx,tx} interval register */
+       u8                      addr_reg;       /* device address register */
+       u8                      h_addr_reg;     /* hub address register */
+       u8                      h_port_reg;     /* hub port register */
+
+       u8                      is_ready;       /* safe to modify hw_ep */
+       u8                      type;           /* XFERTYPE_* */
+       u8                      epnum;
+       u16                     maxpacket;
+       u16                     frame;          /* for periodic schedule */
+       unsigned                iso_idx;        /* in urb->iso_frame_desc[] */
+};
+
+/* map from control or bulk queue head to the first qh on that ring */
+static inline struct musb_qh *first_qh(struct list_head *q)
+{
+       if (list_empty(q))
+               return NULL;
+       return container_of(q->next, struct musb_qh, ring);
+}
+
+
+extern void musb_root_disconnect(struct musb *musb);
+
+struct usb_hcd;
+
+extern int musb_hub_status_data(struct usb_hcd *hcd, char *buf);
+extern int musb_hub_control(struct usb_hcd *hcd,
+                       u16 typeReq, u16 wValue, u16 wIndex,
+                       char *buf, u16 wLength);
+
+extern const struct hc_driver musb_hc_driver;
+
+static inline struct urb *next_urb(struct musb_qh *qh)
+{
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       struct list_head        *queue;
+
+       if (!qh)
+               return NULL;
+       queue = &qh->hep->urb_list;
+       if (list_empty(queue))
+               return NULL;
+       return container_of(queue->next, struct urb, urb_list);
+#else
+       return NULL;
+#endif
+}
+
+#endif                         /* _MUSB_HOST_H */
diff --git a/drivers/usb/musb/musb_procfs.c b/drivers/usb/musb/musb_procfs.c
new file mode 100644 (file)
index 0000000..e5c69d7
--- /dev/null
@@ -0,0 +1,843 @@
+/******************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux 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.
+ *
+ * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+/*
+ * Inventra Controller Driver (ICD) for Linux.
+ *
+ * The code managing debug files (currently in procfs).
+ */
+
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <asm/uaccess.h>       /* FIXME remove procfs writes */
+#include <asm/arch/hardware.h>
+
+#include "musbdefs.h"
+
+#include "davinci.h"
+
+
+const char *otg_state_string(struct musb *musb)
+{
+       switch (musb->xceiv.state) {
+       case OTG_STATE_A_IDLE:          return "a_idle";
+       case OTG_STATE_A_WAIT_VRISE:    return "a_wait_vrise";
+       case OTG_STATE_A_WAIT_BCON:     return "a_wait_bcon";
+       case OTG_STATE_A_HOST:          return "a_host";
+       case OTG_STATE_A_SUSPEND:       return "a_suspend";
+       case OTG_STATE_A_PERIPHERAL:    return "a_peripheral";
+       case OTG_STATE_A_WAIT_VFALL:    return "a_wait_vfall";
+       case OTG_STATE_A_VBUS_ERR:      return "a_vbus_err";
+       case OTG_STATE_B_IDLE:          return "b_idle";
+       case OTG_STATE_B_SRP_INIT:      return "b_srp_init";
+       case OTG_STATE_B_PERIPHERAL:    return "b_peripheral";
+       case OTG_STATE_B_WAIT_ACON:     return "b_wait_acon";
+       case OTG_STATE_B_HOST:          return "b_host";
+       default:                        return "UNDEFINED";
+       }
+}
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+
+static int dump_qh(struct musb_qh *qh, char *buf, unsigned max)
+{
+       int                             count;
+       int                             tmp;
+       struct usb_host_endpoint        *hep = qh->hep;
+       struct urb                      *urb;
+
+       count = snprintf(buf, max, "    qh %p dev%d ep%d%s max%d\n",
+                       qh, qh->dev->devnum, qh->epnum,
+                       ({ char *s; switch (qh->type) {
+                       case USB_ENDPOINT_XFER_BULK:
+                               s = "-bulk"; break;
+                       case USB_ENDPOINT_XFER_INT:
+                               s = "-int"; break;
+                       case USB_ENDPOINT_XFER_CONTROL:
+                               s = ""; break;
+                       default:
+                               s = "iso"; break;
+                       }; s; }),
+                       qh->maxpacket);
+       if (count <= 0)
+               return 0;
+       buf += count;
+       max -= count;
+
+       list_for_each_entry(urb, &hep->urb_list, urb_list) {
+               tmp = snprintf(buf, max, "\t%s urb %p %d/%d\n",
+                               usb_pipein(urb->pipe) ? "in" : "out",
+                               urb, urb->actual_length,
+                               urb->transfer_buffer_length);
+               if (tmp <= 0)
+                       break;
+               tmp = min(tmp, (int)max);
+               count += tmp;
+               buf += tmp;
+               max -= tmp;
+       }
+       return count;
+}
+
+static int
+dump_queue(struct list_head *q, char *buf, unsigned max)
+{
+       int             count = 0;
+       struct musb_qh  *qh;
+
+       list_for_each_entry(qh, q, ring) {
+               int     tmp;
+
+               tmp = dump_qh(qh, buf, max);
+               if (tmp <= 0)
+                       break;
+               tmp = min(tmp, (int)max);
+               count += tmp;
+               buf += tmp;
+               max -= tmp;
+       }
+       return count;
+}
+
+#endif /* HCD */
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+static int dump_ep(struct musb_ep *ep, char *buffer, unsigned max)
+{
+       char            *buf = buffer;
+       int             code = 0;
+       void __iomem    *regs = ep->hw_ep->regs;
+       char            *mode = "1buf";
+
+       if (ep->is_in) {
+               if (ep->hw_ep->tx_double_buffered)
+                       mode = "2buf";
+       } else {
+               if (ep->hw_ep->rx_double_buffered)
+                       mode = "2buf";
+       }
+
+       do {
+               struct usb_request      *req;
+
+               code = snprintf(buf, max,
+                               "\n%s (hw%d): %s%s, csr %04x maxp %04x\n",
+                               ep->name, ep->bEndNumber,
+                               mode, ep->dma ? " dma" : "",
+                               musb_readw(regs,
+                                       (ep->is_in || !ep->bEndNumber)
+                                               ? MGC_O_HDRC_TXCSR
+                                               : MGC_O_HDRC_RXCSR),
+                               musb_readw(regs, ep->is_in
+                                               ? MGC_O_HDRC_TXMAXP
+                                               : MGC_O_HDRC_RXMAXP)
+                               );
+               if (code <= 0)
+                       break;
+               code = min(code, (int) max);
+               buf += code;
+               max -= code;
+
+               if (is_cppi_enabled() && ep->bEndNumber) {
+                       unsigned        cppi = ep->bEndNumber - 1;
+                       void __iomem    *base = ep->pThis->ctrl_base;
+                       unsigned        off1 = cppi << 2;
+                       void __iomem    *ram = base;
+                       char            tmp[16];
+
+                       if (ep->is_in) {
+                               ram += DAVINCI_TXCPPI_STATERAM_OFFSET(cppi);
+                               tmp[0] = 0;
+                       } else {
+                               ram += DAVINCI_RXCPPI_STATERAM_OFFSET(cppi);
+                               snprintf(tmp, sizeof tmp, "%d left, ",
+                                       musb_readl(base,
+                                       DAVINCI_RXCPPI_BUFCNT0_REG + off1));
+                       }
+
+                       code = snprintf(buf, max, "%cX DMA%d: %s"
+                                       "%08x %08x, %08x %08x; "
+                                       "%08x %08x %08x .. %08x\n",
+                               ep->is_in ? 'T' : 'R',
+                               ep->bEndNumber - 1, tmp,
+                               musb_readl(ram, 0 * 4),
+                               musb_readl(ram, 1 * 4),
+                               musb_readl(ram, 2 * 4),
+                               musb_readl(ram, 3 * 4),
+                               musb_readl(ram, 4 * 4),
+                               musb_readl(ram, 5 * 4),
+                               musb_readl(ram, 6 * 4),
+                               musb_readl(ram, 7 * 4));
+                       if (code <= 0)
+                               break;
+                       code = min(code, (int) max);
+                       buf += code;
+                       max -= code;
+               }
+
+               if (list_empty(&ep->req_list)) {
+                       code = snprintf(buf, max, "\t(queue empty)\n");
+                       if (code <= 0)
+                               break;
+                       code = min(code, (int) max);
+                       buf += code;
+                       max -= code;
+                       break;
+               }
+               list_for_each_entry (req, &ep->req_list, list) {
+                       code = snprintf(buf, max, "\treq %p, %s%s%d/%d\n",
+                                       req,
+                                       req->zero ? "zero, " : "",
+                                       req->short_not_ok ? "!short, " : "",
+                                       req->actual, req->length);
+                       if (code <= 0)
+                               break;
+                       code = min(code, (int) max);
+                       buf += code;
+                       max -= code;
+               }
+       } while(0);
+       return buf - buffer;
+}
+#endif
+
+static int
+dump_end_info(struct musb *pThis, u8 bEnd, char *aBuffer, unsigned max)
+{
+       int                     code = 0;
+       char                    *buf = aBuffer;
+       struct musb_hw_ep       *pEnd = &pThis->aLocalEnd[bEnd];
+
+       do {
+               MGC_SelectEnd(pThis->pRegs, bEnd);
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+               if (is_host_active(pThis)) {
+                       int             dump_rx, dump_tx;
+                       void __iomem    *regs = pEnd->regs;
+
+                       /* TEMPORARY (!) until we have a real periodic
+                        * schedule tree ...
+                        */
+                       if (!bEnd) {
+                               /* control is shared, uses RX queue
+                                * but (mostly) shadowed tx registers
+                                */
+                               dump_tx = !list_empty(&pThis->control);
+                               dump_rx = 0;
+                       } else if (pEnd == pThis->bulk_ep) {
+                               dump_tx = !list_empty(&pThis->out_bulk);
+                               dump_rx = !list_empty(&pThis->in_bulk);
+                       } else if (pThis->periodic[bEnd]) {
+                               struct usb_host_endpoint        *hep;
+
+                               hep = pThis->periodic[bEnd]->hep;
+                               dump_rx = hep->desc.bEndpointAddress
+                                               & USB_ENDPOINT_DIR_MASK;
+                               dump_tx = !dump_rx;
+                       } else
+                               break;
+                       /* END TEMPORARY */
+
+
+                       if (dump_rx) {
+                               code = snprintf(buf, max,
+                                       "\nRX%d: %s rxcsr %04x interval %02x "
+                                       "max %04x type %02x; "
+                                       "dev %d hub %d port %d"
+                                       "\n",
+                                       bEnd,
+                                       pEnd->rx_double_buffered
+                                               ? "2buf" : "1buf",
+                                       musb_readw(regs, MGC_O_HDRC_RXCSR),
+                                       musb_readb(regs, MGC_O_HDRC_RXINTERVAL),
+                                       musb_readw(regs, MGC_O_HDRC_RXMAXP),
+                                       musb_readb(regs, MGC_O_HDRC_RXTYPE),
+                                       /* FIXME:  assumes multipoint */
+                                       musb_readb(pThis->pRegs,
+                                               MGC_BUSCTL_OFFSET(bEnd,
+                                               MGC_O_HDRC_RXFUNCADDR)),
+                                       musb_readb(pThis->pRegs,
+                                               MGC_BUSCTL_OFFSET(bEnd,
+                                               MGC_O_HDRC_RXHUBADDR)),
+                                       musb_readb(pThis->pRegs,
+                                               MGC_BUSCTL_OFFSET(bEnd,
+                                               MGC_O_HDRC_RXHUBPORT))
+                                       );
+                               if (code <= 0)
+                                       break;
+                               code = min(code, (int) max);
+                               buf += code;
+                               max -= code;
+
+                               if (is_cppi_enabled()
+                                               && bEnd
+                                               && pEnd->rx_channel) {
+                                       unsigned        cppi = bEnd - 1;
+                                       unsigned        off1 = cppi << 2;
+                                       void __iomem    *base;
+                                       void __iomem    *ram;
+                                       char            tmp[16];
+
+                                       base = pThis->ctrl_base;
+                                       ram = DAVINCI_RXCPPI_STATERAM_OFFSET(
+                                                       cppi) + base;
+                                       snprintf(tmp, sizeof tmp, "%d left, ",
+                                               musb_readl(base,
+                                               DAVINCI_RXCPPI_BUFCNT0_REG
+                                                               + off1));
+
+                                       code = snprintf(buf, max,
+                                               "    rx dma%d: %s"
+                                               "%08x %08x, %08x %08x; "
+                                               "%08x %08x %08x .. %08x\n",
+                                               cppi, tmp,
+                                               musb_readl(ram, 0 * 4),
+                                               musb_readl(ram, 1 * 4),
+                                               musb_readl(ram, 2 * 4),
+                                               musb_readl(ram, 3 * 4),
+                                               musb_readl(ram, 4 * 4),
+                                               musb_readl(ram, 5 * 4),
+                                               musb_readl(ram, 6 * 4),
+                                               musb_readl(ram, 7 * 4));
+                                       if (code <= 0)
+                                               break;
+                                       code = min(code, (int) max);
+                                       buf += code;
+                                       max -= code;
+                               }
+
+                               if (pEnd == pThis->bulk_ep
+                                               && !list_empty(
+                                                       &pThis->in_bulk)) {
+                                       code = dump_queue(&pThis->in_bulk,
+                                                       buf, max);
+                                       if (code <= 0)
+                                               break;
+                                       code = min(code, (int) max);
+                                       buf += code;
+                                       max -= code;
+                               } else if (pThis->periodic[bEnd]) {
+                                       code = dump_qh(pThis->periodic[bEnd],
+                                                       buf, max);
+                                       if (code <= 0)
+                                               break;
+                                       code = min(code, (int) max);
+                                       buf += code;
+                                       max -= code;
+                               }
+                       }
+
+                       if (dump_tx) {
+                               code = snprintf(buf, max,
+                                       "\nTX%d: %s txcsr %04x interval %02x "
+                                       "max %04x type %02x; "
+                                       "dev %d hub %d port %d"
+                                       "\n",
+                                       bEnd,
+                                       pEnd->tx_double_buffered
+                                               ? "2buf" : "1buf",
+                                       musb_readw(regs, MGC_O_HDRC_TXCSR),
+                                       musb_readb(regs, MGC_O_HDRC_TXINTERVAL),
+                                       musb_readw(regs, MGC_O_HDRC_TXMAXP),
+                                       musb_readb(regs, MGC_O_HDRC_TXTYPE),
+                                       /* FIXME:  assumes multipoint */
+                                       musb_readb(pThis->pRegs,
+                                               MGC_BUSCTL_OFFSET(bEnd,
+                                               MGC_O_HDRC_TXFUNCADDR)),
+                                       musb_readb(pThis->pRegs,
+                                               MGC_BUSCTL_OFFSET(bEnd,
+                                               MGC_O_HDRC_TXHUBADDR)),
+                                       musb_readb(pThis->pRegs,
+                                               MGC_BUSCTL_OFFSET(bEnd,
+                                               MGC_O_HDRC_TXHUBPORT))
+                                       );
+                               if (code <= 0)
+                                       break;
+                               code = min(code, (int) max);
+                               buf += code;
+                               max -= code;
+
+                               if (is_cppi_enabled()
+                                               && bEnd
+                                               && pEnd->tx_channel) {
+                                       unsigned        cppi = bEnd - 1;
+                                       void __iomem    *base;
+                                       void __iomem    *ram;
+
+                                       base = pThis->ctrl_base;
+                                       ram = DAVINCI_RXCPPI_STATERAM_OFFSET(
+                                                       cppi) + base;
+                                       code = snprintf(buf, max,
+                                               "    tx dma%d: "
+                                               "%08x %08x, %08x %08x; "
+                                               "%08x %08x %08x .. %08x\n",
+                                               cppi,
+                                               musb_readl(ram, 0 * 4),
+                                               musb_readl(ram, 1 * 4),
+                                               musb_readl(ram, 2 * 4),
+                                               musb_readl(ram, 3 * 4),
+                                               musb_readl(ram, 4 * 4),
+                                               musb_readl(ram, 5 * 4),
+                                               musb_readl(ram, 6 * 4),
+                                               musb_readl(ram, 7 * 4));
+                                       if (code <= 0)
+                                               break;
+                                       code = min(code, (int) max);
+                                       buf += code;
+                                       max -= code;
+                               }
+
+                               if (pEnd == pThis->control_ep
+                                               && !list_empty(
+                                                       &pThis->control)) {
+                                       code = dump_queue(&pThis->control,
+                                                       buf, max);
+                                       if (code <= 0)
+                                               break;
+                                       code = min(code, (int) max);
+                                       buf += code;
+                                       max -= code;
+                               } else if (pEnd == pThis->bulk_ep
+                                               && !list_empty(
+                                                       &pThis->out_bulk)) {
+                                       code = dump_queue(&pThis->out_bulk,
+                                                       buf, max);
+                                       if (code <= 0)
+                                               break;
+                                       code = min(code, (int) max);
+                                       buf += code;
+                                       max -= code;
+                               } else if (pThis->periodic[bEnd]) {
+                                       code = dump_qh(pThis->periodic[bEnd],
+                                                       buf, max);
+                                       if (code <= 0)
+                                               break;
+                                       code = min(code, (int) max);
+                                       buf += code;
+                                       max -= code;
+                               }
+                       }
+               }
+#endif
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+               if (is_peripheral_active(pThis)) {
+                       code = 0;
+
+                       if (pEnd->ep_in.desc || !bEnd) {
+                               code = dump_ep(&pEnd->ep_in, buf, max);
+                               if (code <= 0)
+                                       break;
+                               code = min(code, (int) max);
+                               buf += code;
+                               max -= code;
+                       }
+                       if (pEnd->ep_out.desc) {
+                               code = dump_ep(&pEnd->ep_out, buf, max);
+                               if (code <= 0)
+                                       break;
+                               code = min(code, (int) max);
+                               buf += code;
+                               max -= code;
+                       }
+               }
+#endif
+       } while (0);
+
+       return buf - aBuffer;
+}
+
+/** Dump the current status and compile options.
+ * @param pThis the device driver instance
+ * @param buffer where to dump the status; it must be big enough hold the
+ * result otherwise "BAD THINGS HAPPENS(TM)".
+ */
+static int dump_header_stats(struct musb *pThis, char *buffer)
+{
+       int code, count = 0;
+       const void __iomem *pBase = pThis->pRegs;
+
+       *buffer = 0;
+       count = sprintf(buffer, "Status: %sHDRC, Mode=%s "
+                               "(Power=%02x, DevCtl=%02x)\n",
+                       (pThis->bIsMultipoint ? "M" : ""), MUSB_MODE(pThis),
+                       musb_readb(pBase, MGC_O_HDRC_POWER),
+                       musb_readb(pBase, MGC_O_HDRC_DEVCTL));
+       if (count <= 0)
+               return 0;
+       buffer += count;
+
+       code = sprintf(buffer, "OTG state: %s; %sactive\n",
+                       otg_state_string(pThis),
+                       pThis->is_active ? "" : "in");
+       if (code <= 0)
+               goto done;
+       buffer += code;
+       count += code;
+
+       code = sprintf(buffer,
+                       "Options: "
+#ifdef CONFIG_USB_INVENTRA_FIFO
+                       "pio"
+#elif defined(CONFIG_USB_TI_CPPI_DMA)
+                       "cppi-dma"
+#elif defined(CONFIG_USB_INVENTRA_DMA)
+                       "musb-dma"
+#elif defined(CONFIG_USB_TUSB_OMAP_DMA)
+                       "tusb-omap-dma"
+#else
+                       "?dma?"
+#endif
+                       ", "
+#ifdef CONFIG_USB_MUSB_OTG
+                       "otg (peripheral+host)"
+#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
+                       "peripheral"
+#elif defined(CONFIG_USB_MUSB_HDRC_HCD)
+                       "host"
+#endif
+                       ", debug=%d [eps=%d]\n",
+               debug,
+               pThis->bEndCount);
+       if (code <= 0)
+               goto done;
+       count += code;
+       buffer += code;
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       code = sprintf(buffer, "Root port status: %08x\n",
+                       pThis->port1_status);
+       if (code <= 0)
+               goto done;
+       buffer += code;
+       count += code;
+#endif
+
+#ifdef CONFIG_ARCH_DAVINCI
+       code = sprintf(buffer,
+                       "DaVinci: ctrl=%02x stat=%1x phy=%03x\n"
+                       "\trndis=%05x auto=%04x intsrc=%08x intmsk=%08x"
+                       "\n",
+                       musb_readl(pThis->ctrl_base, DAVINCI_USB_CTRL_REG),
+                       musb_readl(pThis->ctrl_base, DAVINCI_USB_STAT_REG),
+                       __raw_readl(IO_ADDRESS(USBPHY_CTL_PADDR)),
+                       musb_readl(pThis->ctrl_base, DAVINCI_RNDIS_REG),
+                       musb_readl(pThis->ctrl_base, DAVINCI_AUTOREQ_REG),
+                       musb_readl(pThis->ctrl_base,
+                                       DAVINCI_USB_INT_SOURCE_REG),
+                       musb_readl(pThis->ctrl_base,
+                                       DAVINCI_USB_INT_MASK_REG));
+       if (code <= 0)
+               goto done;
+       count += code;
+       buffer += code;
+#endif /* DAVINCI */
+
+#ifdef CONFIG_USB_TUSB6010
+       code = sprintf(buffer,
+                       "TUSB6010: devconf %08x, phy enable %08x drive %08x"
+                       "\n\totg %03x timer %08x"
+                       "\n\tprcm conf %08x mgmt %08x; int src %08x mask %08x"
+                       "\n",
+                       musb_readl(pThis->ctrl_base, TUSB_DEV_CONF),
+                       musb_readl(pThis->ctrl_base, TUSB_PHY_OTG_CTRL_ENABLE),
+                       musb_readl(pThis->ctrl_base, TUSB_PHY_OTG_CTRL),
+                       musb_readl(pThis->ctrl_base, TUSB_DEV_OTG_STAT),
+                       musb_readl(pThis->ctrl_base, TUSB_DEV_OTG_TIMER),
+                       musb_readl(pThis->ctrl_base, TUSB_PRCM_CONF),
+                       musb_readl(pThis->ctrl_base, TUSB_PRCM_MNGMT),
+                       musb_readl(pThis->ctrl_base, TUSB_INT_SRC),
+                       musb_readl(pThis->ctrl_base, TUSB_INT_MASK));
+       if (code <= 0)
+               goto done;
+       count += code;
+       buffer += code;
+#endif /* DAVINCI */
+
+       if (is_cppi_enabled() && pThis->pDmaController) {
+               code = sprintf(buffer,
+                               "CPPI: txcr=%d txsrc=%01x txena=%01x; "
+                               "rxcr=%d rxsrc=%01x rxena=%01x "
+                               "\n",
+                               musb_readl(pThis->ctrl_base,
+                                               DAVINCI_TXCPPI_CTRL_REG),
+                               musb_readl(pThis->ctrl_base,
+                                               DAVINCI_TXCPPI_RAW_REG),
+                               musb_readl(pThis->ctrl_base,
+                                               DAVINCI_TXCPPI_INTENAB_REG),
+                               musb_readl(pThis->ctrl_base,
+                                               DAVINCI_RXCPPI_CTRL_REG),
+                               musb_readl(pThis->ctrl_base,
+                                               DAVINCI_RXCPPI_RAW_REG),
+                               musb_readl(pThis->ctrl_base,
+                                               DAVINCI_RXCPPI_INTENAB_REG));
+               if (code <= 0)
+                       goto done;
+               count += code;
+               buffer += code;
+       }
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+       if (is_peripheral_enabled(pThis)) {
+               code = sprintf(buffer, "Gadget driver: %s\n",
+                               pThis->pGadgetDriver
+                                       ? pThis->pGadgetDriver->driver.name
+                                       : "(none)");
+               if (code <= 0)
+                       goto done;
+               count += code;
+               buffer += code;
+       }
+#endif
+
+done:
+       return count;
+}
+
+/* Write to ProcFS
+ *
+ * C soft-connect
+ * c soft-disconnect
+ * I enable HS
+ * i disable HS
+ * s stop session
+ * F force session (OTG-unfriendly)
+ * E rElinquish bus (OTG)
+ * H request host mode
+ * h cancel host request
+ * T start sending TEST_PACKET
+ * D<num> set/query the debug level
+ */
+static int musb_proc_write(struct file *file, const char __user *buffer,
+                       unsigned long count, void *data)
+{
+       char cmd;
+       u8 bReg;
+       struct musb *musb = (struct musb *)data;
+       void __iomem *pBase = musb->pRegs;
+
+       /* MOD_INC_USE_COUNT; */
+
+       copy_from_user(&cmd, buffer, 1);
+       switch (cmd) {
+       case 'C':
+               if (pBase) {
+                       bReg = musb_readb(pBase, MGC_O_HDRC_POWER)
+                                       | MGC_M_POWER_SOFTCONN;
+                       musb_writeb(pBase, MGC_O_HDRC_POWER, bReg);
+               }
+               break;
+
+       case 'c':
+               if (pBase) {
+                       bReg = musb_readb(pBase, MGC_O_HDRC_POWER)
+                                       & ~MGC_M_POWER_SOFTCONN;
+                       musb_writeb(pBase, MGC_O_HDRC_POWER, bReg);
+               }
+               break;
+
+       case 'I':
+               if (pBase) {
+                       bReg = musb_readb(pBase, MGC_O_HDRC_POWER)
+                                       | MGC_M_POWER_HSENAB;
+                       musb_writeb(pBase, MGC_O_HDRC_POWER, bReg);
+               }
+               break;
+
+       case 'i':
+               if (pBase) {
+                       bReg = musb_readb(pBase, MGC_O_HDRC_POWER)
+                                       & ~MGC_M_POWER_HSENAB;
+                       musb_writeb(pBase, MGC_O_HDRC_POWER, bReg);
+               }
+               break;
+
+       case 'F':
+               bReg = musb_readb(pBase, MGC_O_HDRC_DEVCTL);
+               bReg |= MGC_M_DEVCTL_SESSION;
+               musb_writeb(pBase, MGC_O_HDRC_DEVCTL, bReg);
+               break;
+
+       case 'H':
+               if (pBase) {
+                       bReg = musb_readb(pBase, MGC_O_HDRC_DEVCTL);
+                       bReg |= MGC_M_DEVCTL_HR;
+                       musb_writeb(pBase, MGC_O_HDRC_DEVCTL, bReg);
+                       //MUSB_HST_MODE( ((struct musb*)data) );
+                       //WARN("Host Mode\n");
+               }
+               break;
+
+       case 'h':
+               if (pBase) {
+                       bReg = musb_readb(pBase, MGC_O_HDRC_DEVCTL);
+                       bReg &= ~MGC_M_DEVCTL_HR;
+                       musb_writeb(pBase, MGC_O_HDRC_DEVCTL, bReg);
+               }
+               break;
+
+       case 'T':
+               if (pBase) {
+                       musb_load_testpacket(musb);
+                       musb_writeb(pBase, MGC_O_HDRC_TESTMODE,
+                                       MGC_M_TEST_PACKET);
+               }
+               break;
+
+#if (MUSB_DEBUG>0)
+               /* set/read debug level */
+       case 'D':{
+                       if (count > 1) {
+                               char digits[8], *p = digits;
+                               int i = 0, level = 0, sign = 1;
+                               int len = min(count - 1, (unsigned long)8);
+
+                               copy_from_user(&digits, &buffer[1], len);
+
+                               /* optional sign */
+                               if (*p == '-') {
+                                       len -= 1;
+                                       sign = -sign;
+                                       p++;
+                               }
+
+                               /* read it */
+                               while (i++ < len && *p > '0' && *p < '9') {
+                                       level = level * 10 + (*p - '0');
+                                       p++;
+                               }
+
+                               level *= sign;
+                               DBG(1, "debug level %d\n", level);
+                               debug = level;
+                       }
+               }
+               break;
+
+
+       case '?':
+               INFO("?: you are seeing it\n");
+               INFO("C/c: soft connect enable/disable\n");
+               INFO("I/i: hispeed enable/disable\n");
+               INFO("F: force session start\n");
+               INFO("H: host mode\n");
+               INFO("T: start sending TEST_PACKET\n");
+               INFO("D: set/read dbug level\n");
+               break;
+#endif
+
+       default:
+               ERR("Command %c not implemented\n", cmd);
+               break;
+       }
+
+       musb_platform_try_idle(musb);
+
+       return count;
+}
+
+static int musb_proc_read(char *page, char **start,
+                       off_t off, int count, int *eof, void *data)
+{
+       char *buffer = page;
+       int code = 0;
+       unsigned long   flags;
+       struct musb     *pThis = data;
+       unsigned        bEnd;
+
+       count -= off;
+       count -= 1;             /* for NUL at end */
+       if (count <= 0)
+               return -EINVAL;
+
+       spin_lock_irqsave(&pThis->Lock, flags);
+
+       code = dump_header_stats(pThis, buffer);
+       if (code > 0) {
+               buffer += code;
+               count -= code;
+       }
+
+       /* generate the report for the end points */
+       // REVISIT ... not unless something's connected!
+       for (bEnd = 0; count >= 0 && bEnd < pThis->bEndCount;
+                       bEnd++) {
+               code = dump_end_info(pThis, bEnd, buffer, count);
+               if (code > 0) {
+                       buffer += code;
+                       count -= code;
+               }
+       }
+
+       musb_platform_try_idle(pThis);
+
+       spin_unlock_irqrestore(&pThis->Lock, flags);
+       *eof = 1;
+
+       return buffer - page;
+}
+
+void __devexit musb_debug_delete(char *name, struct musb *musb)
+{
+       if (musb->pProcEntry)
+               remove_proc_entry(name, NULL);
+}
+
+struct proc_dir_entry *__init
+musb_debug_create(char *name, struct musb *data)
+{
+       struct proc_dir_entry   *pde;
+
+       /* FIXME convert everything to seq_file; then later, debugfs */
+
+       if (!name)
+               return NULL;
+
+       data->pProcEntry = pde = create_proc_entry(name,
+                                       S_IFREG | S_IRUGO | S_IWUSR, NULL);
+       if (pde) {
+               pde->data = data;
+               // pde->owner = THIS_MODULE;
+
+               pde->read_proc = musb_proc_read;
+               pde->write_proc = musb_proc_write;
+
+               pde->size = 0;
+
+               pr_debug("Registered /proc/%s\n", name);
+       } else {
+               pr_debug("Cannot create a valid proc file entry");
+       }
+
+       return pde;
+}
diff --git a/drivers/usb/musb/musbdefs.h b/drivers/usb/musb/musbdefs.h
new file mode 100644 (file)
index 0000000..59b2eb9
--- /dev/null
@@ -0,0 +1,520 @@
+/******************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux 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.
+ *
+ * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+#ifndef __MUSB_MUSBDEFS_H__
+#define __MUSB_MUSBDEFS_H__
+
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+#include <linux/usb.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/musb.h>
+
+struct musb;
+struct musb_hw_ep;
+struct musb_ep;
+
+
+#include "debug.h"
+#include "dma.h"
+
+#ifdef CONFIG_USB_MUSB_SOC
+/*
+ * Get core configuration from a header converted (by cfg_conv)
+ * from the Verilog config file generated by the core config utility
+ *
+ * For now we assume that header is provided along with other
+ * arch-specific files.  Discrete chips will need a build tweak.
+ * So will using AHB IDs from silicon that provides them.
+ */
+#include <asm/arch/hdrc_cnf.h>
+#endif
+
+#include "plat_arc.h"
+#include "musbhdrc.h"
+
+#include "musb_gadget.h"
+#include "../core/hcd.h"
+#include "musb_host.h"
+
+
+
+#ifdef CONFIG_USB_MUSB_OTG
+
+#define        is_peripheral_enabled(musb)     ((musb)->board_mode != MUSB_HOST)
+#define        is_host_enabled(musb)           ((musb)->board_mode != MUSB_PERIPHERAL)
+#define        is_otg_enabled(musb)            ((musb)->board_mode == MUSB_OTG)
+
+/* NOTE:  otg and peripheral-only state machines start at B_IDLE.
+ * OTG or host-only go to A_IDLE when ID is sensed.
+ */
+#define is_peripheral_active(m)                (!(m)->bIsHost)
+#define is_host_active(m)              ((m)->bIsHost)
+
+#else
+#define        is_peripheral_enabled(musb)     is_peripheral_capable()
+#define        is_host_enabled(musb)           is_host_capable()
+#define        is_otg_enabled(musb)            0
+
+#define        is_peripheral_active(musb)      is_peripheral_capable()
+#define        is_host_active(musb)            is_host_capable()
+#endif
+
+#if defined(CONFIG_USB_MUSB_OTG) || defined(CONFIG_USB_MUSB_PERIPHERAL)
+/* for some reason, the "select USB_GADGET_MUSB_HDRC" doesn't always
+ * override that choice selection (often USB_GADGET_DUMMY_HCD).
+ */
+#ifndef CONFIG_USB_GADGET_MUSB_HDRC
+#error bogus Kconfig output ... select CONFIG_USB_GADGET_MUSB_HDRC
+#endif
+#endif /* need MUSB gadget selection */
+
+
+#ifdef CONFIG_PROC_FS
+#include <linux/fs.h>
+#define MUSB_CONFIG_PROC_FS
+#endif
+
+/****************************** PERIPHERAL ROLE *****************************/
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+
+#define        is_peripheral_capable() (1)
+
+extern irqreturn_t musb_g_ep0_irq(struct musb *);
+extern void musb_g_tx(struct musb *, u8);
+extern void musb_g_rx(struct musb *, u8);
+extern void musb_g_reset(struct musb *);
+extern void musb_g_suspend(struct musb *);
+extern void musb_g_resume(struct musb *);
+extern void musb_g_disconnect(struct musb *);
+
+#else
+
+#define        is_peripheral_capable() (0)
+
+static inline irqreturn_t musb_g_ep0_irq(struct musb *m) { return IRQ_NONE; }
+static inline void musb_g_reset(struct musb *m) {}
+static inline void musb_g_suspend(struct musb *m) {}
+static inline void musb_g_resume(struct musb *m) {}
+static inline void musb_g_disconnect(struct musb *m) {}
+
+#endif
+
+/****************************** HOST ROLE ***********************************/
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+
+#define        is_host_capable()       (1)
+
+extern irqreturn_t musb_h_ep0_irq(struct musb *);
+extern void musb_host_tx(struct musb *, u8);
+extern void musb_host_rx(struct musb *, u8);
+
+#else
+
+#define        is_host_capable()       (0)
+
+static inline irqreturn_t musb_h_ep0_irq(struct musb *m) { return IRQ_NONE; }
+static inline void musb_host_tx(struct musb *m, u8 e) {}
+static inline void musb_host_rx(struct musb *m, u8 e) {}
+
+#endif
+
+
+/****************************** CONSTANTS ********************************/
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef MUSB_C_NUM_EPS
+#define MUSB_C_NUM_EPS ((u8)16)
+#endif
+
+#ifndef MUSB_MAX_END0_PACKET
+#define MUSB_MAX_END0_PACKET ((u16)MGC_END0_FIFOSIZE)
+#endif
+
+/* host side ep0 states */
+#define MGC_END0_START  0x0
+#define MGC_END0_OUT    0x2
+#define MGC_END0_IN     0x4
+#define MGC_END0_STATUS 0x8
+
+/* peripheral side ep0 states */
+enum musb_g_ep0_state {
+       MGC_END0_STAGE_SETUP,           /* idle, waiting for setup */
+       MGC_END0_STAGE_TX,              /* IN data */
+       MGC_END0_STAGE_RX,              /* OUT data */
+       MGC_END0_STAGE_STATUSIN,        /* (after OUT data) */
+       MGC_END0_STAGE_STATUSOUT,       /* (after IN data) */
+       MGC_END0_STAGE_ACKWAIT,         /* after zlp, before statusin */
+} __attribute__ ((packed));
+
+/* OTG protocol constants */
+#define OTG_TIME_A_WAIT_VRISE  100             /* msec (max) */
+#define OTG_TIME_A_WAIT_BCON   0               /* 0=infinite; min 1000 msec */
+#define OTG_TIME_A_IDLE_BDIS   200             /* msec (min) */
+
+/*************************** REGISTER ACCESS ********************************/
+
+/* Endpoint registers (other than dynfifo setup) can be accessed either
+ * directly with the "flat" model, or after setting up an index register.
+ */
+
+#if defined(CONFIG_ARCH_DAVINCI) || defined(CONFIG_ARCH_OMAP243X)
+/* REVISIT indexed access seemed to
+ * misbehave (on DaVinci) for at least peripheral IN ...
+ */
+#define        MUSB_FLAT_REG
+#endif
+
+/* TUSB mapping: "flat" plus ep0 special cases */
+#if    defined(CONFIG_USB_TUSB6010)
+#define MGC_SelectEnd(_pBase, _bEnd) \
+       musb_writeb((_pBase), MGC_O_HDRC_INDEX, (_bEnd))
+#define        MGC_END_OFFSET                  MGC_TUSB_OFFSET
+
+/* "flat" mapping: each endpoint has its own i/o address */
+#elif  defined(MUSB_FLAT_REG)
+#define MGC_SelectEnd(_pBase, _bEnd)   (((void)(_pBase)),((void)(_bEnd)))
+#define        MGC_END_OFFSET                  MGC_FLAT_OFFSET
+
+/* "indexed" mapping: INDEX register controls register bank select */
+#else
+#define MGC_SelectEnd(_pBase, _bEnd) \
+       musb_writeb((_pBase), MGC_O_HDRC_INDEX, (_bEnd))
+#define        MGC_END_OFFSET                  MGC_INDEXED_OFFSET
+#endif
+
+/****************************** FUNCTIONS ********************************/
+
+#define MUSB_HST_MODE(_pthis)\
+       { (_pthis)->bIsHost=TRUE; }
+#define MUSB_DEV_MODE(_pthis) \
+       { (_pthis)->bIsHost=FALSE; }
+
+#define test_devctl_hst_mode(_x) \
+       (musb_readb((_x)->pRegs, MGC_O_HDRC_DEVCTL)&MGC_M_DEVCTL_HM)
+
+#define MUSB_MODE(musb) ((musb)->bIsHost ? "Host" : "Peripheral")
+
+/************************** Ep Configuration ********************************/
+
+/** The End point descriptor */
+struct MUSB_EpFifoDescriptor {
+       u8 bType;               /* 0 for autoconfig, CNTR, ISOC, BULK, INTR */
+       u8 bDir;                /* 0 for autoconfig, INOUT, IN, OUT */
+       int wSize;              /* 0 for autoconfig, or the size */
+};
+
+#define MUSB_EPD_AUTOCONFIG    0
+
+#define MUSB_EPD_T_CNTRL       1
+#define MUSB_EPD_T_ISOC                2
+#define MUSB_EPD_T_BULK                3
+#define MUSB_EPD_T_INTR                4
+
+#define MUSB_EPD_D_INOUT       0
+#define MUSB_EPD_D_TX          1
+#define MUSB_EPD_D_RX          2
+
+/******************************** TYPES *************************************/
+
+/*
+ * struct musb_hw_ep - endpoint hardware (bidirectional)
+ *
+ * Ordered slightly for better cacheline locality.
+ */
+struct musb_hw_ep {
+       struct musb             *musb;
+       void __iomem            *fifo;
+       void __iomem            *regs;
+
+#ifdef CONFIG_USB_TUSB6010
+       void __iomem            *conf;
+#endif
+
+       /* index in musb->aLocalEnd[]  */
+       u8                      bLocalEnd;
+
+       /* hardware configuration, possibly dynamic */
+       u8                      bIsSharedFifo;
+       u8                      tx_double_buffered;
+       u8                      rx_double_buffered;
+       u16                     wMaxPacketSizeTx;
+       u16                     wMaxPacketSizeRx;
+
+       struct dma_channel      *tx_channel;
+       struct dma_channel      *rx_channel;
+
+#ifdef CONFIG_USB_TUSB6010
+       /* TUSB has "asynchronous" and "synchronous" dma modes */
+       dma_addr_t              fifo_async;
+       dma_addr_t              fifo_sync;
+#endif
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       void __iomem            *target_regs;
+
+       /* currently scheduled peripheral endpoint */
+       struct musb_qh          *in_qh;
+       struct musb_qh          *out_qh;
+
+       u8                      rx_reinit;
+       u8                      tx_reinit;
+#endif
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+       /* peripheral side */
+       struct musb_ep          ep_in;                  /* TX */
+       struct musb_ep          ep_out;                 /* RX */
+#endif
+};
+
+static inline struct usb_request *next_in_request(struct musb_hw_ep *hw_ep)
+{
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+       return next_request(&hw_ep->ep_in);
+#else
+       return NULL;
+#endif
+}
+
+static inline struct usb_request *next_out_request(struct musb_hw_ep *hw_ep)
+{
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+       return next_request(&hw_ep->ep_out);
+#else
+       return NULL;
+#endif
+}
+
+/*
+ * struct musb - Driver instance data.
+ */
+struct musb {
+       spinlock_t              Lock;
+       struct clk              *clock;
+       irqreturn_t             (*isr)(int, void *);
+       struct work_struct      irq_work;
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+
+/* this hub status bit is reserved by USB 2.0 and not seen by usbcore */
+#define MUSB_PORT_STAT_RESUME  (1 << 31)
+
+       u32                     port1_status;
+       unsigned long           rh_timer;
+
+       u8 bEnd0Stage;          /* end0 stage while in host */
+
+       /* bulk traffic normally dedicates endpoint hardware, and each
+        * direction has its own ring of host side endpoints.
+        * we try to progress the transfer at the head of each endpoint's
+        * queue until it completes or NAKs too much; then we try the next
+        * endpoint.
+        */
+       struct musb_hw_ep       *bulk_ep;
+
+       struct list_head        control;        /* of musb_qh */
+       struct list_head        in_bulk;        /* of musb_qh */
+       struct list_head        out_bulk;       /* of musb_qh */
+       struct musb_qh          *periodic[32];  /* tree of interrupt+iso */
+#endif
+
+       /* called with IRQs blocked; ON/nonzero implies starting a session,
+        * and waiting at least a_wait_vrise_tmout.
+        */
+       void                    (*board_set_vbus)(struct musb *, int is_on);
+
+       struct dma_controller   *pDmaController;
+
+       struct device           *controller;
+       void __iomem            *ctrl_base;
+       void __iomem            *pRegs;
+
+#ifdef CONFIG_USB_TUSB6010
+       dma_addr_t              async;
+       dma_addr_t              sync;
+#endif
+
+       /* passed down from chip/board specific irq handlers */
+       u8                      int_usb;
+       u16                     int_rx;
+       u16                     int_tx;
+
+       struct otg_transceiver  xceiv;
+
+       int nIrq;
+
+       struct musb_hw_ep        aLocalEnd[MUSB_C_NUM_EPS];
+#define control_ep             aLocalEnd
+
+#define VBUSERR_RETRY_COUNT    3
+       u16                     vbuserr_retry;
+       u16 wEndMask;
+       u8 bEndCount;
+
+       u8 board_mode;          /* enum musb_mode */
+       int                     (*board_set_power)(int state);
+
+       u8                      min_power;      /* vbus for periph, in mA/2 */
+
+       /* active means connected and not suspended */
+       unsigned is_active:1;
+
+       unsigned bIsMultipoint:1;
+       unsigned bIsHost:1;
+       unsigned bIgnoreDisconnect:1;   /* during bus resets */
+
+#ifdef C_MP_TX
+       unsigned bBulkSplit:1;
+#define        can_bulk_split(musb,type) \
+               (((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bBulkSplit)
+#else
+#define        can_bulk_split(musb,type)       0
+#endif
+
+#ifdef C_MP_RX
+       unsigned bBulkCombine:1;
+       /* REVISIT allegedly doesn't work reliably */
+#if 0
+#define        can_bulk_combine(musb,type) \
+               (((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bBulkCombine)
+#else
+#define        can_bulk_combine(musb,type)     0
+#endif
+#else
+#define        can_bulk_combine(musb,type)     0
+#endif
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+       unsigned bIsSelfPowered:1;
+       unsigned bMayWakeup:1;
+       unsigned bSetAddress:1;
+       unsigned bTestMode:1;
+       unsigned softconnect:1;
+
+       enum musb_g_ep0_state   ep0_state;
+       u8                      bAddress;
+       u8                      bTestModeValue;
+       u16                     ackpend;                /* ep0 */
+       struct usb_gadget       g;                      /* the gadget */
+       struct usb_gadget_driver *pGadgetDriver;        /* its driver */
+#endif
+
+#ifdef CONFIG_USB_MUSB_OTG
+       /* FIXME this can't be OTG-specific ... ? */
+       u8 bDelayPortPowerOff;
+#endif
+
+#ifdef MUSB_CONFIG_PROC_FS
+       struct proc_dir_entry *pProcEntry;
+#endif
+};
+
+static inline void musb_set_vbus(struct musb *musb, int is_on)
+{
+       musb->board_set_vbus(musb, is_on);
+}
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+static inline struct musb *gadget_to_musb(struct usb_gadget *g)
+{
+       return container_of(g, struct musb, g);
+}
+#endif
+
+
+/***************************** Glue it together *****************************/
+
+extern const char musb_driver_name[];
+
+extern void musb_start(struct musb *pThis);
+extern void musb_stop(struct musb *pThis);
+
+extern void musb_write_fifo(struct musb_hw_ep *ep,
+                            u16 wCount, const u8 * pSource);
+extern void musb_read_fifo(struct musb_hw_ep *ep,
+                              u16 wCount, u8 * pDest);
+
+extern void musb_load_testpacket(struct musb *);
+
+extern irqreturn_t musb_interrupt(struct musb *);
+
+extern void musb_platform_enable(struct musb *musb);
+extern void musb_platform_disable(struct musb *musb);
+
+#ifdef CONFIG_USB_TUSB6010
+extern void musb_platform_try_idle(struct musb *musb);
+extern int musb_platform_get_vbus_status(struct musb *musb);
+#else
+#define musb_platform_try_idle(x)              do {} while (0)
+#define musb_platform_get_vbus_status(x)       0
+#endif
+
+extern int __init musb_platform_init(struct musb *musb);
+extern int musb_platform_exit(struct musb *musb);
+
+/*-------------------------- ProcFS definitions ---------------------*/
+
+struct proc_dir_entry;
+
+#if (MUSB_DEBUG > 0) && defined(MUSB_CONFIG_PROC_FS)
+extern struct proc_dir_entry *musb_debug_create(char *name,
+                                                   struct musb *data);
+extern void musb_debug_delete(char *name, struct musb *data);
+
+#else
+static inline struct proc_dir_entry *musb_debug_create(char *name,
+                                                          struct musb *data)
+{
+       return NULL;
+}
+static inline void musb_debug_delete(char *name, struct musb *data)
+{
+}
+#endif
+
+#endif /* __MUSB_MUSBDEFS_H__ */
diff --git a/drivers/usb/musb/musbhdrc.h b/drivers/usb/musb/musbhdrc.h
new file mode 100644 (file)
index 0000000..59fbbd7
--- /dev/null
@@ -0,0 +1,321 @@
+/******************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux 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.
+ *
+ * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+#ifndef __MUSB_HDRC_DEFS_H__
+#define __MUSB_HDRC_DEFS_H__
+
+/*
+ * HDRC-specific definitions
+ */
+
+#define MGC_MAX_USB_ENDS       16
+
+#define MGC_END0_FIFOSIZE      64      /* this is non-configurable */
+
+/*
+ *     MUSBMHDRC Register map
+ */
+
+/* Common USB registers */
+
+#define MGC_O_HDRC_FADDR       0x00    /* 8-bit */
+#define MGC_O_HDRC_POWER       0x01    /* 8-bit */
+
+#define MGC_O_HDRC_INTRTX      0x02    /* 16-bit */
+#define MGC_O_HDRC_INTRRX       0x04
+#define MGC_O_HDRC_INTRTXE      0x06
+#define MGC_O_HDRC_INTRRXE      0x08
+#define MGC_O_HDRC_INTRUSB      0x0A   /* 8 bit */
+#define MGC_O_HDRC_INTRUSBE     0x0B   /* 8 bit */
+#define MGC_O_HDRC_FRAME        0x0C
+#define MGC_O_HDRC_INDEX        0x0E   /* 8 bit */
+#define MGC_O_HDRC_TESTMODE     0x0F   /* 8 bit */
+
+/* Get offset for a given FIFO from musb->pRegs */
+#ifdef CONFIG_USB_TUSB6010
+#define MUSB_FIFO_OFFSET(epnum)        (0x200 + ((epnum) * 0x20))
+#else
+#define MUSB_FIFO_OFFSET(epnum)        (0x20 + ((epnum) * 4))
+#endif
+
+/* Additional Control Registers */
+
+#define MGC_O_HDRC_DEVCTL      0x60    /* 8 bit */
+
+/* These are always controlled through the INDEX register */
+#define MGC_O_HDRC_TXFIFOSZ    0x62    /* 8-bit (see masks) */
+#define MGC_O_HDRC_RXFIFOSZ    0x63    /* 8-bit (see masks) */
+#define MGC_O_HDRC_TXFIFOADD   0x64    /* 16-bit offset shifted right 3 */
+#define MGC_O_HDRC_RXFIFOADD   0x66    /* 16-bit offset shifted right 3 */
+
+// vctrl/vstatus:  optional vendor utmi+phy register at 0x68
+#define MGC_O_HDRC_HWVERS      0x6C    /* 8 bit */
+
+#define MGC_O_HDRC_EPINFO      0x78    /* 8 bit */
+#define MGC_O_HDRC_RAMINFO     0x79    /* 8 bit */
+#define MGC_O_HDRC_LINKINFO    0x7a    /* 8 bit */
+#define MGC_O_HDRC_VPLEN       0x7b    /* 8 bit */
+#define MGC_O_HDRC_HS_EOF1     0x7c    /* 8 bit */
+#define MGC_O_HDRC_FS_EOF1     0x7d    /* 8 bit */
+#define MGC_O_HDRC_LS_EOF1     0x7e    /* 8 bit */
+
+/* offsets to endpoint registers */
+#define MGC_O_HDRC_TXMAXP      0x00
+#define MGC_O_HDRC_TXCSR       0x02
+#define MGC_O_HDRC_CSR0                MGC_O_HDRC_TXCSR        /* re-used for EP0 */
+#define MGC_O_HDRC_RXMAXP      0x04
+#define MGC_O_HDRC_RXCSR       0x06
+#define MGC_O_HDRC_RXCOUNT     0x08
+#define MGC_O_HDRC_COUNT0      MGC_O_HDRC_RXCOUNT      /* re-used for EP0 */
+#define MGC_O_HDRC_TXTYPE      0x0A
+#define MGC_O_HDRC_TYPE0       MGC_O_HDRC_TXTYPE       /* re-used for EP0 */
+#define MGC_O_HDRC_TXINTERVAL  0x0B
+#define MGC_O_HDRC_NAKLIMIT0   MGC_O_HDRC_TXINTERVAL   /* re-used for EP0 */
+#define MGC_O_HDRC_RXTYPE      0x0C
+#define MGC_O_HDRC_RXINTERVAL  0x0D
+#define MGC_O_HDRC_FIFOSIZE    0x0F
+#define MGC_O_HDRC_CONFIGDATA  MGC_O_HDRC_FIFOSIZE     /* re-used for EP0 */
+
+/* offsets to endpoint registers in indexed model (using INDEX register) */
+#define MGC_INDEXED_OFFSET(_bEnd, _bOffset)    \
+       (0x10                   + (_bOffset))
+
+/* offsets to endpoint registers in flat models */
+#define MGC_FLAT_OFFSET(_bEnd, _bOffset)       \
+       (0x100 + (0x10*(_bEnd)) + (_bOffset))
+
+#ifdef CONFIG_USB_TUSB6010
+/* TUSB6010 EP0 configuration register is special */
+#define MGC_TUSB_OFFSET(_bEnd, _bOffset)       \
+       (0x10 + _bOffset)
+#include "tusb6010.h"          /* needed "only" for TUSB_EP0_CONF */
+#endif
+
+/* "bus control"/target registers, for host side multipoint (external hubs) */
+#define MGC_O_HDRC_TXFUNCADDR  0x00
+#define MGC_O_HDRC_TXHUBADDR   0x02
+#define MGC_O_HDRC_TXHUBPORT   0x03
+
+#define MGC_O_HDRC_RXFUNCADDR  0x04
+#define MGC_O_HDRC_RXHUBADDR   0x06
+#define MGC_O_HDRC_RXHUBPORT   0x07
+
+#define MGC_BUSCTL_OFFSET(_bEnd, _bOffset) \
+       (0x80 + (8*(_bEnd)) + (_bOffset))
+
+/*
+ *     MUSBHDRC Register bit masks
+ */
+
+/* POWER */
+
+#define MGC_M_POWER_ISOUPDATE   0x80
+#define MGC_M_POWER_SOFTCONN    0x40
+#define MGC_M_POWER_HSENAB     0x20
+#define MGC_M_POWER_HSMODE     0x10
+#define MGC_M_POWER_RESET       0x08
+#define MGC_M_POWER_RESUME      0x04
+#define MGC_M_POWER_SUSPENDM    0x02
+#define MGC_M_POWER_ENSUSPEND   0x01
+
+/* INTRUSB */
+#define MGC_M_INTR_SUSPEND    0x01
+#define MGC_M_INTR_RESUME     0x02
+#define MGC_M_INTR_RESET      0x04
+#define MGC_M_INTR_BABBLE     0x04
+#define MGC_M_INTR_SOF        0x08
+#define MGC_M_INTR_CONNECT    0x10
+#define MGC_M_INTR_DISCONNECT 0x20
+#define MGC_M_INTR_SESSREQ    0x40
+#define MGC_M_INTR_VBUSERROR  0x80     /* FOR SESSION END */
+
+/* DEVCTL */
+#define MGC_M_DEVCTL_BDEVICE    0x80
+#define MGC_M_DEVCTL_FSDEV      0x40
+#define MGC_M_DEVCTL_LSDEV      0x20
+#define MGC_M_DEVCTL_VBUS       0x18
+#define MGC_S_DEVCTL_VBUS       3
+#define MGC_M_DEVCTL_HM         0x04
+#define MGC_M_DEVCTL_HR         0x02
+#define MGC_M_DEVCTL_SESSION    0x01
+
+/* TESTMODE */
+
+#define MGC_M_TEST_FORCE_HOST   0x80
+#define MGC_M_TEST_FIFO_ACCESS  0x40
+#define MGC_M_TEST_FORCE_FS     0x20
+#define MGC_M_TEST_FORCE_HS     0x10
+#define MGC_M_TEST_PACKET       0x08
+#define MGC_M_TEST_K            0x04
+#define MGC_M_TEST_J            0x02
+#define MGC_M_TEST_SE0_NAK      0x01
+
+/* allocate for double-packet buffering (effectively doubles assigned _SIZE) */
+#define MGC_M_FIFOSZ_DPB       0x10
+/* allocation size (8, 16, 32, ... 4096) */
+#define MGC_M_FIFOSZ_SIZE      0x0f
+
+/* CSR0 */
+#define MGC_M_CSR0_FLUSHFIFO      0x0100
+#define MGC_M_CSR0_TXPKTRDY       0x0002
+#define MGC_M_CSR0_RXPKTRDY       0x0001
+
+/* CSR0 in Peripheral mode */
+#define MGC_M_CSR0_P_SVDSETUPEND  0x0080
+#define MGC_M_CSR0_P_SVDRXPKTRDY  0x0040
+#define MGC_M_CSR0_P_SENDSTALL    0x0020
+#define MGC_M_CSR0_P_SETUPEND     0x0010
+#define MGC_M_CSR0_P_DATAEND      0x0008
+#define MGC_M_CSR0_P_SENTSTALL    0x0004
+
+/* CSR0 in Host mode */
+#define MGC_M_CSR0_H_DIS_PING  0x0800
+#define MGC_M_CSR0_H_WR_DATATOGGLE   0x0400    /* set to allow setting: */
+#define MGC_M_CSR0_H_DATATOGGLE            0x0200      /* data toggle control */
+#define MGC_M_CSR0_H_NAKTIMEOUT   0x0080
+#define MGC_M_CSR0_H_STATUSPKT    0x0040
+#define MGC_M_CSR0_H_REQPKT       0x0020
+#define MGC_M_CSR0_H_ERROR        0x0010
+#define MGC_M_CSR0_H_SETUPPKT     0x0008
+#define MGC_M_CSR0_H_RXSTALL      0x0004
+
+/* CSR0 bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MGC_M_CSR0_P_WZC_BITS  \
+       ( MGC_M_CSR0_P_SENTSTALL )
+#define MGC_M_CSR0_H_WZC_BITS  \
+       ( MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_RXSTALL \
+       | MGC_M_CSR0_RXPKTRDY )
+
+
+/* TxType/RxType */
+#define MGC_M_TYPE_SPEED       0xc0
+#define MGC_S_TYPE_SPEED       6
+#define MGC_TYPE_SPEED_HIGH    1
+#define MGC_TYPE_SPEED_FULL    2
+#define MGC_TYPE_SPEED_LOW     3
+#define MGC_M_TYPE_PROTO       0x30    /* implicitly zero for ep0 */
+#define MGC_S_TYPE_PROTO       4
+#define MGC_M_TYPE_REMOTE_END  0xf     /* implicitly zero for ep0 */
+
+/* CONFIGDATA */
+
+#define MGC_M_CONFIGDATA_MPRXE      0x80       /* auto bulk pkt combining */
+#define MGC_M_CONFIGDATA_MPTXE      0x40       /* auto bulk pkt splitting */
+#define MGC_M_CONFIGDATA_BIGENDIAN  0x20
+#define MGC_M_CONFIGDATA_HBRXE      0x10       /* HB-ISO for RX */
+#define MGC_M_CONFIGDATA_HBTXE      0x08       /* HB-ISO for TX */
+#define MGC_M_CONFIGDATA_DYNFIFO    0x04       /* dynamic FIFO sizing */
+#define MGC_M_CONFIGDATA_SOFTCONE   0x02       /* SoftConnect */
+#define MGC_M_CONFIGDATA_UTMIDW     0x01       /* data width 0/1 => 8/16bits */
+
+/* TXCSR in Peripheral and Host mode */
+
+#define MGC_M_TXCSR_AUTOSET       0x8000
+#define MGC_M_TXCSR_MODE          0x2000
+#define MGC_M_TXCSR_DMAENAB       0x1000
+#define MGC_M_TXCSR_FRCDATATOG    0x0800
+#define MGC_M_TXCSR_DMAMODE       0x0400
+#define MGC_M_TXCSR_CLRDATATOG    0x0040
+#define MGC_M_TXCSR_FLUSHFIFO     0x0008
+#define MGC_M_TXCSR_FIFONOTEMPTY  0x0002
+#define MGC_M_TXCSR_TXPKTRDY      0x0001
+
+/* TXCSR in Peripheral mode */
+
+#define MGC_M_TXCSR_P_ISO         0x4000
+#define MGC_M_TXCSR_P_INCOMPTX    0x0080
+#define MGC_M_TXCSR_P_SENTSTALL   0x0020
+#define MGC_M_TXCSR_P_SENDSTALL   0x0010
+#define MGC_M_TXCSR_P_UNDERRUN    0x0004
+
+/* TXCSR in Host mode */
+
+#define MGC_M_TXCSR_H_WR_DATATOGGLE   0x0200
+#define MGC_M_TXCSR_H_DATATOGGLE      0x0100
+#define MGC_M_TXCSR_H_NAKTIMEOUT  0x0080
+#define MGC_M_TXCSR_H_RXSTALL     0x0020
+#define MGC_M_TXCSR_H_ERROR       0x0004
+
+/* TXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MGC_M_TXCSR_P_WZC_BITS \
+       ( MGC_M_TXCSR_P_INCOMPTX | MGC_M_TXCSR_P_SENTSTALL \
+       | MGC_M_TXCSR_P_UNDERRUN | MGC_M_TXCSR_FIFONOTEMPTY )
+#define MGC_M_TXCSR_H_WZC_BITS \
+       ( MGC_M_TXCSR_H_NAKTIMEOUT | MGC_M_TXCSR_H_RXSTALL \
+       | MGC_M_TXCSR_H_ERROR | MGC_M_TXCSR_FIFONOTEMPTY )
+
+
+/* RXCSR in Peripheral and Host mode */
+
+#define MGC_M_RXCSR_AUTOCLEAR     0x8000
+#define MGC_M_RXCSR_DMAENAB       0x2000
+#define MGC_M_RXCSR_DISNYET       0x1000
+#define MGC_M_RXCSR_PID_ERR       0x1000
+#define MGC_M_RXCSR_DMAMODE       0x0800
+#define MGC_M_RXCSR_INCOMPRX      0x0100
+#define MGC_M_RXCSR_CLRDATATOG    0x0080
+#define MGC_M_RXCSR_FLUSHFIFO     0x0010
+#define MGC_M_RXCSR_DATAERROR     0x0008
+#define MGC_M_RXCSR_FIFOFULL      0x0002
+#define MGC_M_RXCSR_RXPKTRDY      0x0001
+
+/* RXCSR in Peripheral mode */
+
+#define MGC_M_RXCSR_P_ISO         0x4000
+#define MGC_M_RXCSR_P_SENTSTALL   0x0040
+#define MGC_M_RXCSR_P_SENDSTALL   0x0020
+#define MGC_M_RXCSR_P_OVERRUN     0x0004
+
+/* RXCSR in Host mode */
+
+#define MGC_M_RXCSR_H_AUTOREQ     0x4000
+#define MGC_M_RXCSR_H_WR_DATATOGGLE   0x0400
+#define MGC_M_RXCSR_H_DATATOGGLE        0x0200
+#define MGC_M_RXCSR_H_RXSTALL     0x0040
+#define MGC_M_RXCSR_H_REQPKT      0x0020
+#define MGC_M_RXCSR_H_ERROR       0x0004
+
+/* RXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MGC_M_RXCSR_P_WZC_BITS \
+       ( MGC_M_RXCSR_P_SENTSTALL | MGC_M_RXCSR_P_OVERRUN \
+       | MGC_M_RXCSR_RXPKTRDY )
+#define MGC_M_RXCSR_H_WZC_BITS \
+       ( MGC_M_RXCSR_H_RXSTALL | MGC_M_RXCSR_H_ERROR \
+       | MGC_M_RXCSR_DATAERROR | MGC_M_RXCSR_RXPKTRDY )
+
+
+/* HUBADDR */
+#define MGC_M_HUBADDR_MULTI_TT         0x80
+
+
+#endif /* __MUSB_HDRC_DEFS_H__ */
diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
new file mode 100644 (file)
index 0000000..ea39d0c
--- /dev/null
@@ -0,0 +1,393 @@
+/******************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux 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.
+ *
+ * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+/*
+ * Interface to Mentor's DMA engine
+ */
+
+#include <linux/platform_device.h>
+
+#include "musbdefs.h"
+
+
+/****************************** CONSTANTS ********************************/
+
+#define MGC_O_HSDMA_BASE    0x200
+#define MGC_O_HSDMA_INTR    0x200
+
+#define MGC_O_HSDMA_CONTROL 4
+#define MGC_O_HSDMA_ADDRESS 8
+#define MGC_O_HSDMA_COUNT   0xc
+
+#define MGC_HSDMA_CHANNEL_OFFSET(_bChannel, _bOffset)          \
+               (MGC_O_HSDMA_BASE + (_bChannel << 4) + _bOffset)
+
+/* control register (16-bit): */
+#define MGC_S_HSDMA_ENABLE     0
+#define MGC_S_HSDMA_TRANSMIT   1
+#define MGC_S_HSDMA_MODE1      2
+#define MGC_S_HSDMA_IRQENABLE  3
+#define MGC_S_HSDMA_ENDPOINT   4
+#define MGC_S_HSDMA_BUSERROR   8
+#define MGC_S_HSDMA_BURSTMODE  9
+#define MGC_M_HSDMA_BURSTMODE  (3 << MGC_S_HSDMA_BURSTMODE)
+#define MGC_HSDMA_BURSTMODE_UNSPEC  0
+#define MGC_HSDMA_BURSTMODE_INCR4   1
+#define MGC_HSDMA_BURSTMODE_INCR8   2
+#define MGC_HSDMA_BURSTMODE_INCR16  3
+
+#define MGC_HSDMA_CHANNELS 8
+
+/******************************* Types ********************************/
+
+struct hsdma_channel {
+       struct dma_channel Channel;
+       struct hsdma *pController;
+       u32 dwStartAddress;
+       u32 dwCount;
+       u8 bIndex;
+       u8 bEnd;
+       u8 bTransmit;
+};
+
+struct hsdma {
+       struct dma_controller Controller;
+       struct hsdma_channel aChannel[MGC_HSDMA_CHANNELS];
+       void *pDmaPrivate;
+       void __iomem *pCoreBase;
+       u8 bChannelCount;
+       u8 bmUsedChannels;
+};
+
+/****************************** FUNCTIONS ********************************/
+
+static int hsdma_start(struct dma_controller *c)
+{
+       /* nothing to do */
+       return 0;
+}
+
+static int hsdma_stop(struct dma_controller *c)
+{
+       /* nothing to do */
+       return 0;
+}
+
+static struct dma_channel *
+hsdma_channel_alloc(struct dma_controller *c,
+               struct musb_hw_ep *hw_ep,
+               u8 bTransmit)
+{
+       u8 bBit;
+       struct dma_channel *pChannel = NULL;
+       struct hsdma_channel *pImplChannel = NULL;
+       struct hsdma *pController;
+
+       pController = container_of(c, struct hsdma, Controller);
+       for (bBit = 0; bBit < MGC_HSDMA_CHANNELS; bBit++) {
+               if (!(pController->bmUsedChannels & (1 << bBit))) {
+                       pController->bmUsedChannels |= (1 << bBit);
+                       pImplChannel = &(pController->aChannel[bBit]);
+                       pImplChannel->pController = pController;
+                       pImplChannel->bIndex = bBit;
+                       pImplChannel->bEnd = hw_ep->bLocalEnd;
+                       pImplChannel->bTransmit = bTransmit;
+                       pChannel = &(pImplChannel->Channel);
+                       pChannel->pPrivateData = pImplChannel;
+                       pChannel->bStatus = MGC_DMA_STATUS_FREE;
+                       pChannel->dwMaxLength = 0x10000;
+                       /* Tx => mode 1; Rx => mode 0 */
+                       pChannel->bDesiredMode = bTransmit;
+                       pChannel->dwActualLength = 0;
+                       break;
+               }
+       }
+       return pChannel;
+}
+
+static void hsdma_channel_release(struct dma_channel *pChannel)
+{
+       struct hsdma_channel *pImplChannel = pChannel->pPrivateData;
+
+       pImplChannel->pController->bmUsedChannels &=
+           ~(1 << pImplChannel->bIndex);
+       pChannel->bStatus = MGC_DMA_STATUS_FREE;
+}
+
+static void clear_state(struct dma_channel *pChannel)
+{
+       struct hsdma_channel *pImplChannel = pChannel->pPrivateData;
+       struct hsdma *pController = pImplChannel->pController;
+       u8 *pBase = pController->pCoreBase;
+       u8 bChannel = pImplChannel->bIndex;
+
+       musb_writew(pBase,
+                   MGC_HSDMA_CHANNEL_OFFSET(bChannel, MGC_O_HSDMA_CONTROL),
+                   0);
+       musb_writel(pBase,
+                   MGC_HSDMA_CHANNEL_OFFSET(bChannel, MGC_O_HSDMA_ADDRESS),
+                   0);
+       musb_writel(pBase,
+                   MGC_HSDMA_CHANNEL_OFFSET(bChannel, MGC_O_HSDMA_COUNT),
+                   0);
+
+       pChannel->dwActualLength = 0L;
+       pImplChannel->dwStartAddress = 0;
+       pImplChannel->dwCount = 0;
+}
+
+static u8 configure_channel(struct dma_channel *pChannel,
+                                 u16 wPacketSize, u8 bMode,
+                                 dma_addr_t dma_addr, u32 dwLength)
+{
+       struct hsdma_channel *pImplChannel = pChannel->pPrivateData;
+       struct hsdma *pController = pImplChannel->pController;
+       u8 *pBase = pController->pCoreBase;
+       u8 bChannel = pImplChannel->bIndex;
+       u16 wCsr = 0;
+
+       DBG(2, "%p, pkt_sz %d, addr 0x%x, len %d, mode %d\n",
+           pChannel, wPacketSize, dma_addr, dwLength, bMode);
+
+       if (bMode) {
+               wCsr |= 1 << MGC_S_HSDMA_MODE1;
+               if (dwLength < wPacketSize) {
+                       return FALSE;
+               }
+               if (wPacketSize >= 64) {
+                       wCsr |=
+                           MGC_HSDMA_BURSTMODE_INCR16 << MGC_S_HSDMA_BURSTMODE;
+               } else if (wPacketSize >= 32) {
+                       wCsr |=
+                           MGC_HSDMA_BURSTMODE_INCR8 << MGC_S_HSDMA_BURSTMODE;
+               } else if (wPacketSize >= 16) {
+                       wCsr |=
+                           MGC_HSDMA_BURSTMODE_INCR4 << MGC_S_HSDMA_BURSTMODE;
+               }
+       }
+
+       wCsr |= (pImplChannel->bEnd << MGC_S_HSDMA_ENDPOINT)
+               | (1 << MGC_S_HSDMA_ENABLE)
+               | (1 << MGC_S_HSDMA_IRQENABLE)
+               | (pImplChannel->bTransmit ? (1 << MGC_S_HSDMA_TRANSMIT) : 0);
+
+       /* address/count */
+       musb_writel(pBase,
+                   MGC_HSDMA_CHANNEL_OFFSET(bChannel, MGC_O_HSDMA_ADDRESS),
+                   dma_addr);
+       musb_writel(pBase,
+                   MGC_HSDMA_CHANNEL_OFFSET(bChannel, MGC_O_HSDMA_COUNT),
+                   dwLength);
+
+       /* control (this should start things) */
+       musb_writew(pBase,
+                   MGC_HSDMA_CHANNEL_OFFSET(bChannel, MGC_O_HSDMA_CONTROL),
+                   wCsr);
+
+       return TRUE;
+}
+
+static int hsdma_channel_program(struct dma_channel * pChannel,
+                                 u16 wPacketSize, u8 bMode,
+                                 dma_addr_t dma_addr, u32 dwLength)
+{
+       struct hsdma_channel *pImplChannel = pChannel->pPrivateData;
+
+       DBG(2, "pkt_sz %d, dma_addr 0x%x length %d, mode %d\n",
+              wPacketSize, dma_addr, dwLength, bMode);
+
+       BUG_ON(pChannel->bStatus != MGC_DMA_STATUS_FREE);
+
+       pChannel->dwActualLength = 0L;
+       pImplChannel->dwStartAddress = dma_addr;
+       pImplChannel->dwCount = dwLength;
+
+       pChannel->bStatus = MGC_DMA_STATUS_BUSY;
+
+       if ((bMode == 1) && (dwLength >= wPacketSize)) {
+
+#if 0
+               /* mode 1 sends an extra IN token at the end of
+                * full packet transfer in host Rx
+                */
+               if (dwLength % wPacketSize == 0)
+                       dwLength -= wPacketSize;
+
+               /* mode 1 doesn't give an interrupt on short packet */
+               configure_channel(pChannel, wPacketSize, 1, dma_addr,
+                                 dwLength & ~(wPacketSize - 1));
+               /* the rest (<= pkt_size) will be transferred in mode 0 */
+#endif
+
+               configure_channel(pChannel, wPacketSize, 1, dma_addr,
+                                 dwLength);
+
+       } else
+               configure_channel(pChannel, wPacketSize, 0, dma_addr,
+                                 dwLength);
+
+       return TRUE;
+}
+
+// REVISIT...
+static int hsdma_channel_abort(struct dma_channel *pChannel)
+{
+       clear_state(pChannel);
+       pChannel->bStatus = MGC_DMA_STATUS_FREE;
+       return 0;
+}
+
+static irqreturn_t hsdma_irq(int irq, void *pPrivateData)
+{
+       u8 bChannel;
+       u16 wCsr;
+       u32 dwAddress;
+       struct hsdma_channel *pImplChannel;
+       struct hsdma *pController = pPrivateData;
+       u8 *pBase = pController->pCoreBase;
+       struct dma_channel *pChannel;
+       u8 bIntr = musb_readb(pBase, MGC_O_HSDMA_INTR);
+
+       if (!bIntr)
+               return IRQ_NONE;
+
+       for (bChannel = 0; bChannel < MGC_HSDMA_CHANNELS; bChannel++) {
+               if (bIntr & (1 << bChannel)) {
+
+                       pImplChannel = &pController->aChannel[bChannel];
+                       pChannel = &pImplChannel->Channel;
+
+                       wCsr = musb_readw(pBase,
+                                      MGC_HSDMA_CHANNEL_OFFSET(bChannel,
+                                                       MGC_O_HSDMA_CONTROL));
+
+                       if (wCsr & (1 << MGC_S_HSDMA_BUSERROR)) {
+                               pImplChannel->Channel.bStatus =
+                                   MGC_DMA_STATUS_BUS_ABORT;
+                       } else {
+                               dwAddress = musb_readl(pBase,
+                                                      MGC_HSDMA_CHANNEL_OFFSET
+                                                      (bChannel,
+                                                       MGC_O_HSDMA_ADDRESS));
+                               pChannel->dwActualLength =
+                                   dwAddress - pImplChannel->dwStartAddress;
+
+                               DBG(2, "ch %p, 0x%x -> 0x%x (%d / %d) %s\n",
+                                   pChannel, pImplChannel->dwStartAddress,
+                                   dwAddress, pChannel->dwActualLength,
+                                   pImplChannel->dwCount,
+                                   (pChannel->dwActualLength <
+                                       pImplChannel->dwCount) ?
+                                       "=> reconfig 0": "=> complete");
+#if 0
+                               if (pChannel->dwActualLength <
+                                   pImplChannel->dwCount) {
+                                       /* mode 1 sends an extra IN request if
+                                       the last packet is a complete packet */
+                                       u16 newcsr = MGC_ReadCsr16(pBase,
+                                                       MGC_O_HDRC_RXCSR,
+                                                       pImplChannel->bEnd);
+                                       newcsr &= ~(MGC_M_RXCSR_H_AUTOREQ |
+                                                   MGC_M_RXCSR_H_REQPKT);
+                                       MGC_WriteCsr16(pBase, MGC_O_HDRC_RXCSR,
+                                                      pImplChannel->bEnd,
+                                                      MGC_M_RXCSR_H_WZC_BITS |
+                                                               newcsr);
+
+                                       configure_channel(pChannel,
+                                               pImplChannel->wMaxPacketSize,
+                                               0, dwAddress,
+                                               pImplChannel->dwCount -
+                                                   pChannel->dwActualLength);
+                               }
+                               else
+#endif
+                               {
+                                       pChannel->bStatus = MGC_DMA_STATUS_FREE;
+                                       /* completed */
+                                       musb_dma_completion(
+                                               pController->pDmaPrivate,
+                                               pImplChannel->bEnd,
+                                               pImplChannel->bTransmit);
+                               }
+                       }
+               }
+       }
+       return IRQ_HANDLED;
+}
+
+void dma_controller_destroy(struct dma_controller *pController)
+{
+       struct hsdma *pHsController = pController->pPrivateData;
+
+       pHsController->Controller.pPrivateData = NULL;
+       kfree(pHsController);
+}
+
+struct dma_controller *__init
+dma_controller_create(struct musb *pThis, void __iomem *pCoreBase)
+{
+       struct hsdma *pController;
+       struct device *dev = pThis->controller;
+       struct platform_device *pdev = to_platform_device(dev);
+       int irq = platform_get_irq(pdev, 1);
+
+       if (irq == 0) {
+               dev_err(dev, "No DMA interrupt line!\n");
+               return NULL;
+       }
+
+       if (!(pController = kzalloc(sizeof *pController, GFP_KERNEL)))
+               return NULL;
+
+       pController->bChannelCount = MGC_HSDMA_CHANNELS;
+       pController->pDmaPrivate = pThis;
+       pController->pCoreBase = pCoreBase;
+
+       pController->Controller.pPrivateData = pController;
+       pController->Controller.start = hsdma_start;
+       pController->Controller.stop = hsdma_stop;
+       pController->Controller.channel_alloc = hsdma_channel_alloc;
+       pController->Controller.channel_release = hsdma_channel_release;
+       pController->Controller.channel_program = hsdma_channel_program;
+       pController->Controller.channel_abort = hsdma_channel_abort;
+
+       if (request_irq(irq, hsdma_irq, IRQF_DISABLED,
+                       pThis->controller->bus_id, &pController->Controller)) {
+               dev_err(dev, "request_irq %d failed!\n", irq);
+               kfree(pController);
+               return NULL;
+       }
+
+       return &pController->Controller;
+}
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
new file mode 100644 (file)
index 0000000..87a7014
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux 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.
+ *
+ * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/mux.h>
+
+#include "musbdefs.h"
+#include "omap2430.h"
+
+
+static int dma_off;
+
+void musb_platform_enable(struct musb *musb)
+{
+       if (is_dma_capable() && dma_off)
+               printk(KERN_WARNING "%s %s: dma not reactivated\n",
+                               __FILE__, __FUNCTION__);
+       else
+               dma_off = 1;
+}
+
+void musb_platform_disable(struct musb *musb)
+{
+       if (is_dma_capable()) {
+               printk(KERN_WARNING "%s %s: dma still active\n",
+                               __FILE__, __FUNCTION__);
+               dma_off = 1;
+       }
+}
+
+static void omap_vbus_power(struct musb *musb, int is_on, int sleeping)
+{
+}
+
+int __init musb_platform_init(struct musb *musb)
+{
+       /* Erratum - reset value of STP has pull-down.
+          Change it to pull-up. */
+       omap_cfg_reg(AE5_2430_USB0HS_STP);
+
+       /* start clock */
+       musb->clock = clk_get((struct device *)musb->controller, "usbhs_ick");
+       clk_enable(musb->clock);
+
+       omap_writel(omap_readl(OTG_INTERFSEL) | (1<<0), OTG_INTERFSEL);
+       omap_writel(omap_readl(OTG_SYSCONFIG) |
+                   ((1 << 12) | (1 << 3) | (1 << 2)),
+                   OTG_SYSCONFIG);
+
+       pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, "
+                       "sysstatus 0x%x, intrfsel 0x%x, simenable  0x%x\n",
+                       omap_readl(OTG_REVISION), omap_readl(OTG_SYSCONFIG),
+                       omap_readl(OTG_SYSSTATUS), omap_readl(OTG_INTERFSEL),
+                       omap_readl(OTG_SIMENABLE));
+
+       omap_vbus_power(musb, musb->board_mode == MUSB_HOST, 1);
+
+       return 0;
+}
+
+int __exit musb_platform_exit(struct musb *musb)
+{
+       omap_vbus_power(musb, 0 /*off*/, 1);
+       clk_disable(musb->clock);
+
+       return 0;
+}
diff --git a/drivers/usb/musb/omap2430.h b/drivers/usb/musb/omap2430.h
new file mode 100644 (file)
index 0000000..e634808
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * The Inventra Controller Driver for Linux 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 __MUSB_OMAP243X_H__
+#define __MUSB_OMAP243X_H__
+
+#ifdef CONFIG_ARCH_OMAP2430
+/*
+ * OMAP2430-specific definitions
+ */
+
+#define MENTOR_BASE_OFFSET     0
+#define HS_OTG(offset)         (OMAP243X_HS_BASE + (offset))
+#define OTG_REVISION           HS_OTG(0x400)
+#define OTG_SYSCONFIG          HS_OTG(0x404)
+#define OTG_SYSSTATUS          HS_OTG(0x408)
+#define OTG_INTERFSEL          HS_OTG(0x40c)
+#define OTG_SIMENABLE          HS_OTG(0x410)
+
+#endif /* CONFIG_ARCH_OMAP243X */
+
+#endif /* __MUSB_OMAP243X_H__ */
diff --git a/drivers/usb/musb/plat_arc.h b/drivers/usb/musb/plat_arc.h
new file mode 100644 (file)
index 0000000..06d3f37
--- /dev/null
@@ -0,0 +1,118 @@
+/******************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux 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.
+ *
+ * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+/*
+ * Linux-specific architecture definitions
+ */
+
+#ifndef __MUSB_LINUX_PLATFORM_ARCH_H__
+#define __MUSB_LINUX_PLATFORM_ARCH_H__
+
+#include <asm/io.h>
+
+#ifndef        CONFIG_ARM
+static inline void readsl(const void __iomem *addr, void *buf, int len)
+       { insl((unsigned long)addr, buf, len); }
+static inline void readsw(const void __iomem *addr, void *buf, int len)
+       { insw((unsigned long)addr, buf, len); }
+static inline void readsb(const void __iomem *addr, void *buf, int len)
+       { insb((unsigned long)addr, buf, len); }
+
+static inline void writesl(const void __iomem *addr, const void *buf, int len)
+       { outsl((unsigned long)addr, buf, len); }
+static inline void writesw(const void __iomem *addr, const void *buf, int len)
+       { outsw((unsigned long)addr, buf, len); }
+static inline void writesb(const void __iomem *addr, const void *buf, int len)
+       { outsb((unsigned long)addr, buf, len); }
+
+#endif
+
+/* NOTE:  these offsets are all in bytes */
+
+static inline u16 musb_readw(const void __iomem *addr, unsigned offset)
+       { return __raw_readw(addr + offset); }
+
+static inline u32 musb_readl(const void __iomem *addr, unsigned offset)
+       { return __raw_readl(addr + offset); }
+
+
+static inline void musb_writew(void __iomem *addr, unsigned offset, u16 data)
+       { __raw_writew(data, addr + offset); }
+
+static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data)
+       { __raw_writel(data, addr + offset); }
+
+
+#ifdef CONFIG_USB_TUSB6010
+
+/*
+ * TUSB6010 doesn't allow 8-bit access; 16-bit access is the minimum.
+ */
+static inline u8 musb_readb(const void __iomem *addr, unsigned offset)
+{
+       u16 tmp;
+       u8 val;
+
+       tmp = __raw_readw(addr + (offset & ~1));
+       if (offset & 1)
+               val = (tmp >> 8);
+       else
+               val = tmp & 0xff;
+
+       return val;
+}
+
+static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)
+{
+       u16 tmp;
+
+       tmp = __raw_readw(addr + (offset & ~1));
+       if (offset & 1)
+               tmp = (data << 8) | (tmp & 0xff);
+       else
+               tmp = (tmp & 0xff00) | data;
+
+       __raw_writew(tmp, addr + (offset & ~1));
+}
+
+#else
+
+static inline u8 musb_readb(const void __iomem *addr, unsigned offset)
+       { return __raw_readb(addr + offset); }
+
+static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)
+       { __raw_writeb(data, addr + offset); }
+
+#endif /* CONFIG_USB_TUSB6010 */
+
+#endif
diff --git a/drivers/usb/musb/plat_uds.c b/drivers/usb/musb/plat_uds.c
new file mode 100644 (file)
index 0000000..152c979
--- /dev/null
@@ -0,0 +1,2003 @@
+/*****************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006 by Nokia Corporation
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux 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.
+ *
+ * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+/*
+ * Inventra (Multipoint) Dual-Role Controller Driver for Linux.
+ *
+ * This consists of a Host Controller Driver (HCD) and a peripheral
+ * controller driver implementing the "Gadget" API; OTG support is
+ * in the works.  These are normal Linux-USB controller drivers which
+ * use IRQs and have no dedicated thread.
+ *
+ * This version of the driver has only been used with products from
+ * Texas Instruments.  Those products integrate the Inventra logic
+ * with other DMA, IRQ, and bus modules, as well as other logic that
+ * needs to be reflected in this driver.
+ *
+ *
+ * NOTE:  the original Mentor code here was pretty much a collection
+ * of mechanisms that don't seem to have been fully integrated/working
+ * for *any* Linux kernel version.  This version aims at Linux 2.6.now,
+ * Key open issues include:
+ *
+ *  - Lack of host-side transaction scheduling, for all transfer types.
+ *    The hardware doesn't do it; instead, software must.
+ *
+ *    This is not an issue for OTG devices that don't support external
+ *    hubs, but for more "normal" USB hosts it's a user issue that the
+ *    "multipoint" support doesn't scale in the expected ways.  That
+ *    includes DaVinci EVM in a common non-OTG mode.
+ *
+ *      * Control and bulk use dedicated endpoints, and there's as
+ *        yet no mechanism to either (a) reclaim the hardware when
+ *        peripherals are NAKing, which gets complicated with bulk
+ *        endpoints, or (b) use more than a single bulk endpoint in
+ *        each direction.
+ *
+ *        RESULT:  one device may be perceived as blocking another one.
+ *
+ *      * Interrupt and isochronous will dynamically allocate endpoint
+ *        hardware, but (a) there's no record keeping for bandwidth;
+ *        (b) in the common case that few endpoints are available, there
+ *        is no mechanism to reuse endpoints to talk to multiple devices.
+ *
+ *        RESULT:  At one extreme, bandwidth can be overcommitted in
+ *        some hardware configurations, no faults will be reported.
+ *        At the other extreme, the bandwidth capabilities which do
+ *        exist tend to be severely undercommitted.  You can't yet hook
+ *        up both a keyboard and a mouse to an external USB hub.
+ */
+
+/*
+ * This gets many kinds of configuration information:
+ *     - Kconfig for everything user-configurable
+ *     - <asm/arch/hdrc_cnf.h> for SOC or family details
+ *     - platform_device for addressing, irq, and platform_data
+ *     - platform_data is mostly for board-specific informarion
+ *
+ * Most of the conditional compilation will (someday) vanish.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/kobject.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+
+#ifdef CONFIG_ARM
+#include <asm/arch/hardware.h>
+#include <asm/arch/memory.h>
+#include <asm/mach-types.h>
+#endif
+
+#include "musbdefs.h"
+
+
+#ifdef CONFIG_ARCH_DAVINCI
+#include "davinci.h"
+#endif
+
+
+
+#if MUSB_DEBUG > 0
+unsigned debug = MUSB_DEBUG;
+module_param(debug, uint, 0);
+MODULE_PARM_DESC(debug, "initial debug message level");
+
+#define MUSB_VERSION_SUFFIX    "/dbg"
+#else
+
+const char *otg_state_string(struct musb *musb)
+{
+       static char buf[8];
+
+       snprintf(buf, sizeof buf, "otg-%d", musb->xceiv.state);
+       return buf;
+}
+#endif
+
+#define DRIVER_AUTHOR "Mentor Graphics, Texas Instruments, Nokia"
+#define DRIVER_DESC "Inventra Dual-Role USB Controller Driver"
+
+#define MUSB_VERSION_BASE "2.2a/db-0.5.2"
+
+#ifndef MUSB_VERSION_SUFFIX
+#define MUSB_VERSION_SUFFIX    ""
+#endif
+#define MUSB_VERSION   MUSB_VERSION_BASE MUSB_VERSION_SUFFIX
+
+#define DRIVER_INFO DRIVER_DESC ", v" MUSB_VERSION
+
+const char musb_driver_name[] = "musb_hdrc";
+
+MODULE_DESCRIPTION(DRIVER_INFO);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_LICENSE("GPL");
+
+
+/*-------------------------------------------------------------------------*/
+
+static inline struct musb *dev_to_musb(struct device *dev)
+{
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       /* usbcore insists dev->driver_data is a "struct hcd *" */
+       return hcd_to_musb(dev_get_drvdata(dev));
+#else
+       return dev_get_drvdata(dev);
+#endif
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifndef CONFIG_USB_TUSB6010
+/*
+ * Load an endpoint's FIFO
+ */
+void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 wCount, const u8 *pSource)
+{
+       void __iomem *fifo = hw_ep->fifo;
+
+       prefetch((u8 *)pSource);
+
+       DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
+                       'T', hw_ep->bLocalEnd, fifo, wCount, pSource);
+
+       /* we can't assume unaligned reads work */
+       if (likely((0x01 & (unsigned long) pSource) == 0)) {
+               u16     index = 0;
+
+               /* best case is 32bit-aligned source address */
+               if ((0x02 & (unsigned long) pSource) == 0) {
+                       if (wCount >= 4) {
+                               writesl(fifo, pSource + index, wCount >> 2);
+                               index += wCount & ~0x03;
+                       }
+                       if (wCount & 0x02) {
+                               musb_writew(fifo, 0, *(u16*)&pSource[index]);
+                               index += 2;
+                       }
+               } else {
+                       if (wCount >= 2) {
+                               writesw(fifo, pSource + index, wCount >> 1);
+                               index += wCount & ~0x01;
+                       }
+               }
+               if (wCount & 0x01)
+                       musb_writeb(fifo, 0, pSource[index]);
+       } else  {
+               /* byte aligned */
+               writesb(fifo, pSource, wCount);
+       }
+}
+
+/*
+ * Unload an endpoint's FIFO
+ */
+void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 wCount, u8 *pDest)
+{
+       void __iomem *fifo = hw_ep->fifo;
+
+       DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
+                       'R', hw_ep->bLocalEnd, fifo, wCount, pDest);
+
+       /* we can't assume unaligned writes work */
+       if (likely((0x01 & (unsigned long) pDest) == 0)) {
+               u16     index = 0;
+
+               /* best case is 32bit-aligned destination address */
+               if ((0x02 & (unsigned long) pDest) == 0) {
+                       if (wCount >= 4) {
+                               readsl(fifo, pDest, wCount >> 2);
+                               index = wCount & ~0x03;
+                       }
+                       if (wCount & 0x02) {
+                               *(u16*)&pDest[index] = musb_readw(fifo, 0);
+                               index += 2;
+                       }
+               } else {
+                       if (wCount >= 2) {
+                               readsw(fifo, pDest, wCount >> 1);
+                               index = wCount & ~0x01;
+                       }
+               }
+               if (wCount & 0x01)
+                       pDest[index] = musb_readb(fifo, 0);
+       } else  {
+               /* byte aligned */
+               readsb(fifo, pDest, wCount);
+       }
+}
+
+#endif /* normal PIO */
+
+
+/*-------------------------------------------------------------------------*/
+
+/* for high speed test mode; see USB 2.0 spec 7.1.20 */
+static const u8 musb_test_packet[53] = {
+       /* implicit SYNC then DATA0 to start */
+
+       /* JKJKJKJK x9 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       /* JJKKJJKK x8 */
+       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+       /* JJJJKKKK x8 */
+       0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+       /* JJJJJJJKKKKKKK x8 */
+       0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       /* JJJJJJJK x8 */
+       0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd,
+       /* JKKKKKKK x10, JK */
+       0xfc, 0x7e, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0x7e
+
+       /* implicit CRC16 then EOP to end */
+};
+
+void musb_load_testpacket(struct musb *musb)
+{
+       void __iomem    *regs = musb->aLocalEnd[0].regs;
+
+       MGC_SelectEnd(musb->pRegs, 0);
+       musb_write_fifo(musb->control_ep,
+                       sizeof(musb_test_packet), musb_test_packet);
+       musb_writew(regs, MGC_O_HDRC_CSR0, MGC_M_CSR0_TXPKTRDY);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Interrupt Service Routine to record USB "global" interrupts.
+ * Since these do not happen often and signify things of
+ * paramount importance, it seems OK to check them individually;
+ * the order of the tests is specified in the manual
+ *
+ * @param pThis instance pointer
+ * @param bIntrUSB register contents
+ * @param devctl
+ * @param power
+ */
+
+#define STAGE0_MASK (MGC_M_INTR_RESUME | MGC_M_INTR_SESSREQ \
+               | MGC_M_INTR_VBUSERROR | MGC_M_INTR_CONNECT \
+               | MGC_M_INTR_RESET )
+
+static irqreturn_t musb_stage0_irq(struct musb * pThis, u8 bIntrUSB,
+                               u8 devctl, u8 power)
+{
+       irqreturn_t handled = IRQ_NONE;
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       void __iomem *pBase = pThis->pRegs;
+#endif
+
+       DBG(3, "<== Power=%02x, DevCtl=%02x, bIntrUSB=0x%x\n", power, devctl,
+               bIntrUSB);
+
+       /* in host mode, the peripheral may issue remote wakeup.
+        * in peripheral mode, the host may resume the link.
+        * spurious RESUME irqs happen too, paired with SUSPEND.
+        */
+       if (bIntrUSB & MGC_M_INTR_RESUME) {
+               handled = IRQ_HANDLED;
+               DBG(3, "RESUME (%s)\n", otg_state_string(pThis));
+
+               if (devctl & MGC_M_DEVCTL_HM) {
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+                       switch (pThis->xceiv.state) {
+                       case OTG_STATE_A_SUSPEND:
+                               /* remote wakeup?  later, GetPortStatus
+                                * will stop RESUME signaling
+                                */
+                               if (power & MGC_M_POWER_RESUME) {
+                                       power &= ~MGC_M_POWER_SUSPENDM;
+                                       musb_writeb(pBase, MGC_O_HDRC_POWER,
+                                               power | MGC_M_POWER_RESUME);
+
+                                       pThis->port1_status |=
+                                                 MUSB_PORT_STAT_RESUME
+                                               | USB_PORT_STAT_C_SUSPEND;
+                                       pThis->rh_timer = jiffies
+                                               + msecs_to_jiffies(20);
+
+                                       pThis->xceiv.state = OTG_STATE_A_HOST;
+                                       pThis->is_active = 1;
+                                       usb_hcd_resume_root_hub(
+                                                       musb_to_hcd(pThis));
+
+                               } else if (power & MGC_M_POWER_SUSPENDM) {
+                                       /* spurious */
+                                       pThis->int_usb &= ~MGC_M_INTR_SUSPEND;
+                               }
+                               break;
+                       case OTG_STATE_B_WAIT_ACON:
+                               pThis->xceiv.state = OTG_STATE_B_PERIPHERAL;
+                               pThis->is_active = 1;
+                               MUSB_DEV_MODE(pThis);
+                               break;
+                       default:
+                               WARN("bogus %s RESUME (%s)\n",
+                                       "host",
+                                       otg_state_string(pThis));
+                       }
+#endif
+               } else {
+                       switch (pThis->xceiv.state) {
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+                       case OTG_STATE_A_SUSPEND:
+                               /* possibly DISCONNECT is upcoming */
+                               pThis->xceiv.state = OTG_STATE_A_HOST;
+                               usb_hcd_resume_root_hub(musb_to_hcd(pThis));
+                               break;
+#endif
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+                       case OTG_STATE_B_WAIT_ACON:
+                       case OTG_STATE_B_PERIPHERAL:
+                               musb_g_resume(pThis);
+                               break;
+                       case OTG_STATE_B_IDLE:
+                               pThis->int_usb &= ~MGC_M_INTR_SUSPEND;
+                               break;
+#endif
+                       default:
+                               WARN("bogus %s RESUME (%s)\n",
+                                       "peripheral",
+                                       otg_state_string(pThis));
+                       }
+               }
+       }
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       /* see manual for the order of the tests */
+       if (bIntrUSB & MGC_M_INTR_SESSREQ) {
+               DBG(1, "SESSION_REQUEST (%s)\n", otg_state_string(pThis));
+
+               /* IRQ arrives from ID pin sense or (later, if VBUS power
+                * is removed) SRP.  responses are time critical:
+                *  - turn on VBUS (with silicon-specific mechanism)
+                *  - go through A_WAIT_VRISE
+                *  - ... to A_WAIT_BCON.
+                * a_wait_vrise_tmout triggers VBUS_ERROR transitions
+                */
+               musb_writeb(pBase, MGC_O_HDRC_DEVCTL, MGC_M_DEVCTL_SESSION);
+               pThis->bEnd0Stage = MGC_END0_START;
+               pThis->xceiv.state = OTG_STATE_A_IDLE;
+               MUSB_HST_MODE(pThis);
+               musb_set_vbus(pThis, 1);
+
+               handled = IRQ_HANDLED;
+       }
+
+       if (bIntrUSB & MGC_M_INTR_VBUSERROR) {
+               int     ignore = 0;
+
+               /* During connection as an A-Device, we may see a short
+                * current spikes causing voltage drop, because of cable
+                * and peripheral capacitance combined with vbus draw.
+                * (So: less common with truly self-powered devices, where
+                * vbus doesn't act like a power supply.)
+                *
+                * Such spikes are short; usually less than ~500 usec, max
+                * of ~2 msec.  That is, they're not sustained overcurrent
+                * errors, though they're reported using VBUSERROR irqs.
+                *
+                * Workarounds:  (a) hardware: use self powered devices.
+                * (b) software:  ignore non-repeated VBUS errors.
+                *
+                * REVISIT:  do delays from lots of DEBUG_KERNEL checks
+                * make trouble here, keeping VBUS < 4.4V ?
+                */
+               switch (pThis->xceiv.state) {
+               case OTG_STATE_A_HOST:
+                       /* recovery is dicey once we've gotten past the
+                        * initial stages of enumeration, but if VBUS
+                        * stayed ok at the other end of the link, and
+                        * another reset is due (at least for high speed,
+                        * to redo the chirp etc), it might work OK...
+                        */
+               case OTG_STATE_A_WAIT_BCON:
+               case OTG_STATE_A_WAIT_VRISE:
+                       if (pThis->vbuserr_retry) {
+                               pThis->vbuserr_retry--;
+                               ignore = 1;
+                               devctl |= MGC_M_DEVCTL_SESSION;
+                               musb_writeb(pBase, MGC_O_HDRC_DEVCTL, devctl);
+                       } else {
+                               pThis->port1_status |=
+                                         (1 << USB_PORT_FEAT_OVER_CURRENT)
+                                       | (1 << USB_PORT_FEAT_C_OVER_CURRENT);
+                       }
+                       break;
+               default:
+                       break;
+               }
+
+               DBG(1, "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n",
+                               otg_state_string(pThis),
+                               devctl,
+                               ({ char *s;
+                               switch (devctl & MGC_M_DEVCTL_VBUS) {
+                               case 0 << MGC_S_DEVCTL_VBUS:
+                                       s = "<SessEnd"; break;
+                               case 1 << MGC_S_DEVCTL_VBUS:
+                                       s = "<AValid"; break;
+                               case 2 << MGC_S_DEVCTL_VBUS:
+                                       s = "<VBusValid"; break;
+                               //case 3 << MGC_S_DEVCTL_VBUS:
+                               default:
+                                       s = "VALID"; break;
+                               }; s; }),
+                               VBUSERR_RETRY_COUNT - pThis->vbuserr_retry,
+                               pThis->port1_status);
+
+               /* go through A_WAIT_VFALL then start a new session */
+               if (!ignore)
+                       musb_set_vbus(pThis, 0);
+               handled = IRQ_HANDLED;
+       }
+
+       if (bIntrUSB & MGC_M_INTR_CONNECT) {
+               struct usb_hcd *hcd = musb_to_hcd(pThis);
+
+               handled = IRQ_HANDLED;
+               pThis->is_active = 1;
+               set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
+
+               pThis->bEnd0Stage = MGC_END0_START;
+
+#ifdef CONFIG_USB_MUSB_OTG
+               /* flush endpoints when transitioning from Device Mode */
+               if (is_peripheral_active(pThis)) {
+                       // REVISIT HNP; just force disconnect
+               }
+               pThis->bDelayPortPowerOff = FALSE;
+#endif
+               pThis->port1_status &= ~(USB_PORT_STAT_LOW_SPEED
+                                       |USB_PORT_STAT_HIGH_SPEED
+                                       |USB_PORT_STAT_ENABLE
+                                       );
+               pThis->port1_status |= USB_PORT_STAT_CONNECTION
+                                       |(USB_PORT_STAT_C_CONNECTION << 16);
+
+               /* high vs full speed is just a guess until after reset */
+               if (devctl & MGC_M_DEVCTL_LSDEV)
+                       pThis->port1_status |= USB_PORT_STAT_LOW_SPEED;
+
+               if (hcd->status_urb)
+                       usb_hcd_poll_rh_status(hcd);
+               else
+                       usb_hcd_resume_root_hub(hcd);
+
+               MUSB_HST_MODE(pThis);
+
+               /* indicate new connection to OTG machine */
+               switch (pThis->xceiv.state) {
+               case OTG_STATE_B_WAIT_ACON:
+                       pThis->xceiv.state = OTG_STATE_B_HOST;
+                       break;
+               default:
+                       if ((devctl & MGC_M_DEVCTL_VBUS)
+                                       == (3 << MGC_S_DEVCTL_VBUS))
+                               pThis->xceiv.state = OTG_STATE_A_HOST;
+                       break;
+               }
+               DBG(1, "CONNECT (%s) devctl %02x\n",
+                               otg_state_string(pThis), devctl);
+       }
+#endif /* CONFIG_USB_MUSB_HDRC_HCD */
+
+       /* mentor saves a bit: bus reset and babble share the same irq.
+        * only host sees babble; only peripheral sees bus reset.
+        */
+       if (bIntrUSB & MGC_M_INTR_RESET) {
+               if (devctl & MGC_M_DEVCTL_HM) {
+                       DBG(1, "BABBLE\n");
+
+                       /* REVISIT it's unclear how to handle this.  Mentor's
+                        * code stopped the whole USB host, which is clearly
+                        * very wrong.  Docs say (15.1) that babble ends the
+                        * current sesssion, so shutdown _with restart_ would
+                        * be appropriate ... except that seems to be wrong,
+                        * at least some lowspeed enumerations trigger the
+                        * babbles without aborting the session!
+                        *
+                        * (A "babble" IRQ seems quite pointless...)
+                        */
+
+               } else {
+                       DBG(1, "BUS RESET\n");
+
+                       musb_g_reset(pThis);
+                       schedule_work(&pThis->irq_work);
+               }
+
+               handled = IRQ_HANDLED;
+       }
+
+       return handled;
+}
+
+/*
+ * Interrupt Service Routine to record USB "global" interrupts.
+ * Since these do not happen often and signify things of
+ * paramount importance, it seems OK to check them individually;
+ * the order of the tests is specified in the manual
+ *
+ * @param pThis instance pointer
+ * @param bIntrUSB register contents
+ * @param devctl
+ * @param power
+ */
+static irqreturn_t musb_stage2_irq(struct musb * pThis, u8 bIntrUSB,
+                               u8 devctl, u8 power)
+{
+       irqreturn_t handled = IRQ_NONE;
+
+#if 0
+/* REVISIT ... this would be for multiplexing periodic endpoints, or
+ * supporting transfer phasing to prevent exceeding ISO bandwidth
+ * limits of a given frame or microframe.
+ *
+ * It's not needed for peripheral side, which dedicates endpoints;
+ * though it _might_ use SOF irqs for other purposes.
+ *
+ * And it's not currently needed for host side, which also dedicates
+ * endpoints, relies on TX/RX interval registers, and isn't claimed
+ * to support ISO transfers yet.
+ */
+       if (bIntrUSB & MGC_M_INTR_SOF) {
+               void __iomem *pBase = pThis->pRegs;
+               struct musb_hw_ep       *ep;
+               u8 bEnd;
+               u16 wFrame;
+
+               DBG(6, "START_OF_FRAME\n");
+               handled = IRQ_HANDLED;
+
+               /* start any periodic Tx transfers waiting for current frame */
+               wFrame = musb_readw(pBase, MGC_O_HDRC_FRAME);
+               ep = pThis->aLocalEnd;
+               for (bEnd = 1; (bEnd < pThis->bEndCount)
+                                       && (pThis->wEndMask >= (1 << bEnd));
+                               bEnd++, ep++) {
+                       // FIXME handle framecounter wraps (12 bits)
+                       // eliminate duplicated StartUrb logic
+                       if (ep->dwWaitFrame >= wFrame) {
+                               ep->dwWaitFrame = 0;
+                               printk("SOF --> periodic TX%s on %d\n",
+                                       ep->tx_channel ? " DMA" : "",
+                                       bEnd);
+                               if (!ep->tx_channel)
+                                       musb_h_tx_start(pThis, bEnd);
+                               else
+                                       cppi_hostdma_start(pThis, bEnd);
+                       }
+               }               /* end of for loop */
+       }
+#endif
+
+       if ((bIntrUSB & MGC_M_INTR_DISCONNECT) && !pThis->bIgnoreDisconnect) {
+               DBG(1, "DISCONNECT (%s) as %s, devctl %02x\n",
+                               otg_state_string(pThis),
+                               MUSB_MODE(pThis), devctl);
+               handled = IRQ_HANDLED;
+
+               switch (pThis->xceiv.state) {
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+               case OTG_STATE_A_HOST:
+               case OTG_STATE_A_SUSPEND:
+                       musb_root_disconnect(pThis);
+                       break;
+#endif /* HOST */
+#ifdef CONFIG_USB_MUSB_OTG
+               case OTG_STATE_A_PERIPHERAL:
+               case OTG_STATE_B_HOST:
+                       musb_root_disconnect(pThis);
+                       /* FALLTHROUGH */
+               case OTG_STATE_B_WAIT_ACON:
+#endif /* OTG */
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+               case OTG_STATE_B_PERIPHERAL:
+                       musb_g_disconnect(pThis);
+                       break;
+#endif /* GADGET */
+               default:
+                       WARN("unhandled DISCONNECT transition (%s)\n",
+                               otg_state_string(pThis));
+                       break;
+               }
+
+               schedule_work(&pThis->irq_work);
+       }
+
+       if (bIntrUSB & MGC_M_INTR_SUSPEND) {
+               DBG(1, "SUSPEND (%s) devctl %02x\n",
+                               otg_state_string(pThis), devctl);
+               handled = IRQ_HANDLED;
+
+               switch (pThis->xceiv.state) {
+               case OTG_STATE_B_PERIPHERAL:
+                       musb_g_suspend(pThis);
+                       pThis->is_active = is_otg_enabled(pThis)
+                                       && pThis->xceiv.gadget->b_hnp_enable;
+                       if (pThis->is_active) {
+                               pThis->xceiv.state = OTG_STATE_B_WAIT_ACON;
+                               /* REVISIT timeout for b_ase0_brst, etc */
+                       }
+                       break;
+               case OTG_STATE_A_HOST:
+                       pThis->xceiv.state = OTG_STATE_A_SUSPEND;
+                       pThis->is_active = is_otg_enabled(pThis)
+                                       && pThis->xceiv.host->b_hnp_enable;
+                       break;
+               default:
+                       /* "should not happen" */
+                       pThis->is_active = 0;
+                       break;
+               }
+       }
+
+
+       return handled;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+* Program the HDRC to start (enable interrupts, dma, etc.).
+*/
+void musb_start(struct musb *musb)
+{
+       void __iomem    *regs = musb->pRegs;
+       u8              devctl = musb_readb(regs, MGC_O_HDRC_DEVCTL);
+
+       DBG(2, "<== devctl %02x\n", devctl);
+
+       /*  Set INT enable registers, enable interrupts */
+       musb_writew(regs, MGC_O_HDRC_INTRTXE, musb->wEndMask);
+       musb_writew(regs, MGC_O_HDRC_INTRRXE, musb->wEndMask & 0xfffe);
+       musb_writeb(regs, MGC_O_HDRC_INTRUSBE, 0xf7);
+
+       musb_writeb(regs, MGC_O_HDRC_TESTMODE, 0);
+
+       /* put into basic highspeed mode and start session */
+       musb_writeb(regs, MGC_O_HDRC_POWER, MGC_M_POWER_ISOUPDATE
+                                               | MGC_M_POWER_SOFTCONN
+                                               | MGC_M_POWER_HSENAB
+                                               /* ENSUSPEND wedges tusb */
+                                               // | MGC_M_POWER_ENSUSPEND
+                                               );
+
+       musb->is_active = 0;
+       devctl = musb_readb(regs, MGC_O_HDRC_DEVCTL);
+       devctl &= ~MGC_M_DEVCTL_SESSION;
+
+       if (is_otg_enabled(musb)) {
+               /* session started after:
+                * (a) ID-grounded irq, host mode;
+                * (b) vbus present/connect IRQ, peripheral mode;
+                * (c) peripheral initiates, using SRP
+                */
+               if ((devctl & MGC_M_DEVCTL_VBUS) == MGC_M_DEVCTL_VBUS)
+                       musb->is_active = 1;
+               else
+                       devctl |= MGC_M_DEVCTL_SESSION;
+
+       } else if (is_host_enabled(musb)) {
+               /* assume ID pin is hard-wired to ground */
+               devctl |= MGC_M_DEVCTL_SESSION;
+
+       } else /* peripheral is enabled */ {
+               if ((devctl & MGC_M_DEVCTL_VBUS) == MGC_M_DEVCTL_VBUS)
+                       musb->is_active = 1;
+       }
+       musb_platform_enable(musb);
+       musb_writeb(regs, MGC_O_HDRC_DEVCTL, devctl);
+}
+
+
+static void musb_generic_disable(struct musb *pThis)
+{
+       void __iomem    *pBase = pThis->pRegs;
+       u16     temp;
+
+       /* disable interrupts */
+       musb_writeb(pBase, MGC_O_HDRC_INTRUSBE, 0);
+       musb_writew(pBase, MGC_O_HDRC_INTRTX, 0);
+       musb_writew(pBase, MGC_O_HDRC_INTRRX, 0);
+
+       /* off */
+       musb_writeb(pBase, MGC_O_HDRC_DEVCTL, 0);
+
+       /*  flush pending interrupts */
+       temp = musb_readb(pBase, MGC_O_HDRC_INTRUSB);
+       temp = musb_readw(pBase, MGC_O_HDRC_INTRTX);
+       temp = musb_readw(pBase, MGC_O_HDRC_INTRRX);
+
+}
+
+/*
+ * Make the HDRC stop (disable interrupts, etc.);
+ * reversible by musb_start
+ * called on gadget driver unregister
+ * with controller locked, irqs blocked
+ * acts as a NOP unless some role activated the hardware
+ */
+void musb_stop(struct musb *musb)
+{
+       /* stop IRQs, timers, ... */
+       musb_platform_disable(musb);
+       musb_generic_disable(musb);
+       DBG(3, "HDRC disabled\n");
+
+       /* FIXME
+        *  - mark host and/or peripheral drivers unusable/inactive
+        *  - disable DMA (and enable it in HdrcStart)
+        *  - make sure we can musb_start() after musb_stop(); with
+        *    OTG mode, gadget driver module rmmod/modprobe cycles that
+        *  - ...
+        */
+       musb_platform_try_idle(musb);
+}
+
+static void musb_shutdown(struct platform_device *pdev)
+{
+       struct musb     *musb = dev_to_musb(&pdev->dev);
+       unsigned long   flags;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+       musb_platform_disable(musb);
+       musb_generic_disable(musb);
+       spin_unlock_irqrestore(&musb->Lock, flags);
+
+       /* FIXME power down */
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * The silicon either has hard-wired endpoint configurations, or else
+ * "dynamic fifo" sizing.  The driver has support for both, though at this
+ * writing only the dynamic sizing is very well tested.   We use normal
+ * idioms to so both modes are compile-tested, but dead code elimination
+ * leaves only the relevant one in the object file.
+ *
+ * We don't currently use dynamic fifo setup capability to do anything
+ * more than selecting one of a bunch of predefined configurations.
+ */
+#ifdef MUSB_C_DYNFIFO_DEF
+#define        can_dynfifo()   1
+#else
+#define        can_dynfifo()   0
+#endif
+
+#ifdef CONFIG_USB_TUSB6010
+static ushort __initdata fifo_mode = 4;
+#else
+static ushort __initdata fifo_mode = 2;
+#endif
+
+/* "modprobe ... fifo_mode=1" etc */
+module_param(fifo_mode, ushort, 0);
+MODULE_PARM_DESC(fifo_mode, "initial endpoint configuration");
+
+
+#define DYN_FIFO_SIZE (1<<(MUSB_C_RAM_BITS+2))
+
+enum fifo_style { FIFO_RXTX, FIFO_TX, FIFO_RX } __attribute__ ((packed));
+enum buf_mode { BUF_SINGLE, BUF_DOUBLE } __attribute__ ((packed));
+
+struct fifo_cfg {
+       u8              hw_ep_num;
+       enum fifo_style style;
+       enum buf_mode   mode;
+       u16             maxpacket;
+};
+
+/*
+ * tables defining fifo_mode values.  define more if you like.
+ * for host side, make sure both halves of ep1 are set up.
+ */
+
+/* mode 0 - fits in 2KB */
+static struct fifo_cfg __initdata mode_0_cfg[] = {
+{ .hw_ep_num = 1, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num = 1, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, },
+{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, },
+{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, },
+};
+
+/* mode 1 - fits in 4KB */
+static struct fifo_cfg __initdata mode_1_cfg[] = {
+{ .hw_ep_num = 1, .style = FIFO_TX,   .maxpacket = 512, .mode = BUF_DOUBLE, },
+{ .hw_ep_num = 1, .style = FIFO_RX,   .maxpacket = 512, .mode = BUF_DOUBLE, },
+{ .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, .mode = BUF_DOUBLE, },
+{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, },
+{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, },
+};
+
+/* mode 2 - fits in 4KB */
+static struct fifo_cfg __initdata mode_2_cfg[] = {
+{ .hw_ep_num = 1, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num = 1, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num = 2, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num = 2, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, },
+{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, },
+};
+
+/* mode 3 - fits in 4KB */
+static struct fifo_cfg __initdata mode_3_cfg[] = {
+{ .hw_ep_num = 1, .style = FIFO_TX,   .maxpacket = 512, .mode = BUF_DOUBLE, },
+{ .hw_ep_num = 1, .style = FIFO_RX,   .maxpacket = 512, .mode = BUF_DOUBLE, },
+{ .hw_ep_num = 2, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num = 2, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, },
+{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, },
+};
+
+/* mode 4 - fits in 16KB */
+static struct fifo_cfg __initdata mode_4_cfg[] = {
+{ .hw_ep_num =  1, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  1, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  2, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  2, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  3, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  3, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  4, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  4, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  5, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  5, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  6, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  6, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  7, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  7, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  8, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  8, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  9, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  9, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num = 10, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num = 10, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num = 11, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num = 11, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num = 12, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num = 12, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num = 13, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num = 13, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num = 14, .style = FIFO_RXTX, .maxpacket = 1024, },
+{ .hw_ep_num = 15, .style = FIFO_RXTX, .maxpacket = 1024, },
+};
+
+
+/*
+ * configure a fifo; for non-shared endpoints, this may be called
+ * once for a tx fifo and once for an rx fifo.
+ *
+ * returns negative errno or offset for next fifo.
+ */
+static int __init
+fifo_setup(struct musb *musb, struct musb_hw_ep  *hw_ep,
+               const struct fifo_cfg *cfg, u16 offset)
+{
+       void __iomem    *mbase = musb->pRegs;
+       int     size = 0;
+       u16     maxpacket = cfg->maxpacket;
+       u16     c_off = offset >> 3;
+       u8      c_size;
+
+       /* expect hw_ep has already been zero-initialized */
+
+       size = ffs(max(maxpacket, (u16) 8)) - 1;
+       maxpacket = 1 << size;
+
+       c_size = size - 3;
+       if (cfg->mode == BUF_DOUBLE) {
+               if ((offset + (maxpacket << 1)) > DYN_FIFO_SIZE)
+                       return -EMSGSIZE;
+               c_size |= MGC_M_FIFOSZ_DPB;
+       } else {
+               if ((offset + maxpacket) > DYN_FIFO_SIZE)
+                       return -EMSGSIZE;
+       }
+
+       /* configure the FIFO */
+       musb_writeb(mbase, MGC_O_HDRC_INDEX, hw_ep->bLocalEnd);
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       /* EP0 reserved endpoint for control, bidirectional;
+        * EP1 reserved for bulk, two unidirection halves.
+        */
+       if (hw_ep->bLocalEnd == 1)
+               musb->bulk_ep = hw_ep;
+       /* REVISIT error check:  be sure ep0 can both rx and tx ... */
+#endif
+       switch (cfg->style) {
+       case FIFO_TX:
+               musb_writeb(mbase, MGC_O_HDRC_TXFIFOSZ, c_size);
+               musb_writew(mbase, MGC_O_HDRC_TXFIFOADD, c_off);
+               hw_ep->tx_double_buffered = !!(c_size & MGC_M_FIFOSZ_DPB);
+               hw_ep->wMaxPacketSizeTx = maxpacket;
+               break;
+       case FIFO_RX:
+               musb_writeb(mbase, MGC_O_HDRC_RXFIFOSZ, c_size);
+               musb_writew(mbase, MGC_O_HDRC_RXFIFOADD, c_off);
+               hw_ep->rx_double_buffered = !!(c_size & MGC_M_FIFOSZ_DPB);
+               hw_ep->wMaxPacketSizeRx = maxpacket;
+               break;
+       case FIFO_RXTX:
+               musb_writeb(mbase, MGC_O_HDRC_TXFIFOSZ, c_size);
+               musb_writew(mbase, MGC_O_HDRC_TXFIFOADD, c_off);
+               hw_ep->rx_double_buffered = !!(c_size & MGC_M_FIFOSZ_DPB);
+               hw_ep->wMaxPacketSizeRx = maxpacket;
+
+               musb_writeb(mbase, MGC_O_HDRC_RXFIFOSZ, c_size);
+               musb_writew(mbase, MGC_O_HDRC_RXFIFOADD, c_off);
+               hw_ep->tx_double_buffered = hw_ep->rx_double_buffered;
+               hw_ep->wMaxPacketSizeTx = maxpacket;
+
+               hw_ep->bIsSharedFifo = TRUE;
+               break;
+       }
+
+       /* NOTE rx and tx endpoint irqs aren't managed separately,
+        * which happens to be ok
+        */
+       musb->wEndMask |= (1 << hw_ep->bLocalEnd);
+
+       return offset + (maxpacket << ((c_size & MGC_M_FIFOSZ_DPB) ? 1 : 0));
+}
+
+static struct fifo_cfg __initdata ep0_cfg = {
+       .style = FIFO_RXTX, .maxpacket = 64,
+};
+
+static int __init ep_config_from_table(struct musb *musb)
+{
+       const struct fifo_cfg   *cfg;
+       unsigned                i, n;
+       int                     offset;
+       struct musb_hw_ep       *hw_ep = musb->aLocalEnd;
+
+       switch (fifo_mode) {
+       default:
+               fifo_mode = 0;
+               /* FALLTHROUGH */
+       case 0:
+               cfg = mode_0_cfg;
+               n = ARRAY_SIZE(mode_0_cfg);
+               break;
+       case 1:
+               cfg = mode_1_cfg;
+               n = ARRAY_SIZE(mode_1_cfg);
+               break;
+       case 2:
+               cfg = mode_2_cfg;
+               n = ARRAY_SIZE(mode_2_cfg);
+               break;
+       case 3:
+               cfg = mode_3_cfg;
+               n = ARRAY_SIZE(mode_3_cfg);
+               break;
+       case 4:
+               cfg = mode_4_cfg;
+               n = ARRAY_SIZE(mode_4_cfg);
+               break;
+       }
+
+       printk(KERN_DEBUG "%s: setup fifo_mode %d\n",
+                       musb_driver_name, fifo_mode);
+
+
+       offset = fifo_setup(musb, hw_ep, &ep0_cfg, 0);
+       // assert(offset > 0)
+
+       /* NOTE:  for RTL versions >= 1.400 EPINFO and RAMINFO would
+        * be better than static MUSB_C_NUM_EPS and DYN_FIFO_SIZE...
+        */
+
+       for (i = 0; i < n; i++) {
+               u8      epn = cfg->hw_ep_num;
+
+               if (epn >= MUSB_C_NUM_EPS) {
+                       pr_debug( "%s: invalid ep %d\n",
+                                       musb_driver_name, epn);
+                       continue;
+               }
+               offset = fifo_setup(musb, hw_ep + epn, cfg++, offset);
+               if (offset < 0) {
+                       pr_debug( "%s: mem overrun, ep %d\n",
+                                       musb_driver_name, epn);
+                       return -EINVAL;
+               }
+               epn++;
+               musb->bEndCount = max(epn, musb->bEndCount);
+       }
+
+       printk(KERN_DEBUG "%s: %d/%d max ep, %d/%d memory\n",
+                       musb_driver_name,
+                       n + 1, MUSB_C_NUM_EPS * 2 - 1,
+                       offset, DYN_FIFO_SIZE);
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       if (!musb->bulk_ep) {
+               pr_debug( "%s: missing bulk\n", musb_driver_name);
+               return -EINVAL;
+       }
+#endif
+
+       return 0;
+}
+
+
+/*
+ * ep_config_from_hw - when MUSB_C_DYNFIFO_DEF is false
+ * @param pThis the controller
+ */
+static int __init ep_config_from_hw(struct musb *musb)
+{
+       u8 bEnd = 0, reg;
+       struct musb_hw_ep *pEnd;
+       void *pBase = musb->pRegs;
+
+       DBG(2, "<== static silicon ep config\n");
+
+       /* FIXME pick up ep0 maxpacket size */
+
+       for (bEnd = 1; bEnd < MUSB_C_NUM_EPS; bEnd++) {
+               MGC_SelectEnd(pBase, bEnd);
+               pEnd = musb->aLocalEnd + bEnd;
+
+               /* read from core using indexed model */
+               reg = musb_readb(pEnd->regs, 0x10 + MGC_O_HDRC_FIFOSIZE);
+               if (!reg) {
+                       /* 0's returned when no more endpoints */
+                       break;
+               }
+               musb->bEndCount++;
+               musb->wEndMask |= (1 << bEnd);
+
+               pEnd->wMaxPacketSizeTx = 1 << (reg & 0x0f);
+
+               /* shared TX/RX FIFO? */
+               if ((reg & 0xf0) == 0xf0) {
+                       pEnd->wMaxPacketSizeRx = pEnd->wMaxPacketSizeTx;
+                       pEnd->bIsSharedFifo = TRUE;
+                       continue;
+               } else {
+                       pEnd->wMaxPacketSizeRx = 1 << ((reg & 0xf0) >> 4);
+                       pEnd->bIsSharedFifo = FALSE;
+               }
+
+               /* FIXME set up pEnd->{rx,tx}_double_buffered */
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+               /* pick an RX/TX endpoint for bulk */
+               if (pEnd->wMaxPacketSizeTx < 512
+                               || pEnd->wMaxPacketSizeRx < 512)
+                       continue;
+
+               /* REVISIT:  this algorithm is lazy, we should at least
+                * try to pick a double buffered endpoint.
+                */
+               if (musb->bulk_ep)
+                       continue;
+               musb->bulk_ep = pEnd;
+#endif
+       }
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       if (!musb->bulk_ep) {
+               pr_debug( "%s: missing bulk\n", musb_driver_name);
+               return -EINVAL;
+       }
+#endif
+
+       return 0;
+}
+
+enum { MUSB_CONTROLLER_MHDRC, MUSB_CONTROLLER_HDRC, };
+
+/* Initialize MUSB (M)HDRC part of the USB hardware subsystem;
+ * configure endpoints, or take their config from silicon
+ */
+static int __init musb_core_init(u16 wType, struct musb *pThis)
+{
+#ifdef MUSB_AHB_ID
+       u32 dwData;
+#endif
+       u8 reg;
+       char *type;
+       u16 wRelease, wRelMajor, wRelMinor;
+       char aInfo[78], aRevision[32], aDate[12];
+       void __iomem    *pBase = pThis->pRegs;
+       int             status = 0;
+       int             i;
+
+       /* log core options (read using indexed model) */
+       MGC_SelectEnd(pBase, 0);
+       reg = musb_readb(pBase, 0x10 + MGC_O_HDRC_CONFIGDATA);
+
+       strcpy(aInfo, (reg & MGC_M_CONFIGDATA_UTMIDW) ? "UTMI-16" : "UTMI-8");
+       if (reg & MGC_M_CONFIGDATA_DYNFIFO) {
+               strcat(aInfo, ", dyn FIFOs");
+       }
+       if (reg & MGC_M_CONFIGDATA_MPRXE) {
+               strcat(aInfo, ", bulk combine");
+#ifdef C_MP_RX
+               pThis->bBulkCombine = TRUE;
+#else
+               strcat(aInfo, " (X)");          /* no driver support */
+#endif
+       }
+       if (reg & MGC_M_CONFIGDATA_MPTXE) {
+               strcat(aInfo, ", bulk split");
+#ifdef C_MP_TX
+               pThis->bBulkSplit = TRUE;
+#else
+               strcat(aInfo, " (X)");          /* no driver support */
+#endif
+       }
+       if (reg & MGC_M_CONFIGDATA_HBRXE) {
+               strcat(aInfo, ", HB-ISO Rx");
+               strcat(aInfo, " (X)");          /* no driver support */
+       }
+       if (reg & MGC_M_CONFIGDATA_HBTXE) {
+               strcat(aInfo, ", HB-ISO Tx");
+               strcat(aInfo, " (X)");          /* no driver support */
+       }
+       if (reg & MGC_M_CONFIGDATA_SOFTCONE) {
+               strcat(aInfo, ", SoftConn");
+       }
+
+       printk(KERN_DEBUG "%s: ConfigData=0x%02x (%s)\n",
+                       musb_driver_name, reg, aInfo);
+
+#ifdef MUSB_AHB_ID
+       dwData = musb_readl(pBase, 0x404);
+       sprintf(aDate, "%04d-%02x-%02x", (dwData & 0xffff),
+               (dwData >> 16) & 0xff, (dwData >> 24) & 0xff);
+       /* FIXME ID2 and ID3 are unused */
+       dwData = musb_readl(pBase, 0x408);
+       printk("ID2=%lx\n", (long unsigned)dwData);
+       dwData = musb_readl(pBase, 0x40c);
+       printk("ID3=%lx\n", (long unsigned)dwData);
+       reg = musb_readb(pBase, 0x400);
+       wType = ('M' == reg) ? MUSB_CONTROLLER_MHDRC : MUSB_CONTROLLER_HDRC;
+#else
+       aDate[0] = 0;
+#endif
+       if (MUSB_CONTROLLER_MHDRC == wType) {
+               pThis->bIsMultipoint = 1;
+               type = "M";
+       } else {
+               pThis->bIsMultipoint = 0;
+               type = "";
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+#ifndef        CONFIG_USB_OTG_BLACKLIST_HUB
+               printk(KERN_ERR
+                       "%s: kernel must blacklist external hubs\n",
+                       musb_driver_name);
+#endif
+#endif
+       }
+
+       /* log release info */
+       wRelease = musb_readw(pBase, MGC_O_HDRC_HWVERS);
+       wRelMajor = (wRelease >> 10) & 0x1f;
+       wRelMinor = wRelease & 0x3ff;
+       snprintf(aRevision, 32, "%d.%d%s", wRelMajor,
+               wRelMinor, (wRelease & 0x8000) ? "RC" : "");
+       printk(KERN_DEBUG "%s: %sHDRC RTL version %s %s\n",
+                       musb_driver_name, type, aRevision, aDate);
+
+       /* configure ep0 */
+       pThis->aLocalEnd[0].wMaxPacketSizeTx = MGC_END0_FIFOSIZE;
+       pThis->aLocalEnd[0].wMaxPacketSizeRx = MGC_END0_FIFOSIZE;
+
+       /* discover endpoint configuration */
+       pThis->bEndCount = 1;
+       pThis->wEndMask = 1;
+
+       if (reg & MGC_M_CONFIGDATA_DYNFIFO) {
+               if (can_dynfifo())
+                       status = ep_config_from_table(pThis);
+               else {
+                       ERR("reconfigure software for Dynamic FIFOs\n");
+                       status = -ENODEV;
+               }
+       } else {
+               if (!can_dynfifo())
+                       status = ep_config_from_hw(pThis);
+               else {
+                       ERR("reconfigure software for static FIFOs\n");
+                       return -ENODEV;
+               }
+       }
+
+       if (status < 0)
+               return status;
+
+       /* finish init, and print endpoint config */
+       for (i = 0; i < pThis->bEndCount; i++) {
+               struct musb_hw_ep       *hw_ep = pThis->aLocalEnd + i;
+
+               hw_ep->fifo = MUSB_FIFO_OFFSET(i) + pBase;
+#ifdef CONFIG_USB_TUSB6010
+               hw_ep->fifo_async = pThis->async + 0x400 + MUSB_FIFO_OFFSET(i);
+               hw_ep->fifo_sync = pThis->sync + 0x400 + MUSB_FIFO_OFFSET(i);
+               if (i == 0)
+                       hw_ep->conf = pBase - 0x400 + TUSB_EP0_CONF;
+               else
+                       hw_ep->conf = pBase + 0x400 + (((i - 1) & 0xf) << 2);
+#endif
+
+               hw_ep->regs = MGC_END_OFFSET(i, 0) + pBase;
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+               hw_ep->target_regs = MGC_BUSCTL_OFFSET(i, 0) + pBase;
+               hw_ep->rx_reinit = 1;
+               hw_ep->tx_reinit = 1;
+#endif
+
+               if (hw_ep->wMaxPacketSizeTx) {
+                       printk(KERN_DEBUG
+                               "%s: hw_ep %d%s, %smax %d\n",
+                               musb_driver_name, i,
+                               hw_ep->bIsSharedFifo ? "shared" : "tx",
+                               hw_ep->tx_double_buffered
+                                       ? "doublebuffer, " : "",
+                               hw_ep->wMaxPacketSizeTx);
+               }
+               if (hw_ep->wMaxPacketSizeRx && !hw_ep->bIsSharedFifo) {
+                       printk(KERN_DEBUG
+                               "%s: hw_ep %d%s, %smax %d\n",
+                               musb_driver_name, i,
+                               "rx",
+                               hw_ep->rx_double_buffered
+                                       ? "doublebuffer, " : "",
+                               hw_ep->wMaxPacketSizeRx);
+               }
+               if (!(hw_ep->wMaxPacketSizeTx || hw_ep->wMaxPacketSizeRx))
+                       DBG(1, "hw_ep %d not configured\n", i);
+       }
+
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_ARCH_OMAP243X
+
+static irqreturn_t generic_interrupt(int irq, void *__hci)
+{
+       unsigned long   flags;
+       irqreturn_t     retval = IRQ_NONE;
+       struct musb     *musb = __hci;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+
+       musb->int_usb = musb_readb(musb->pRegs, MGC_O_HDRC_INTRUSB);
+       musb->int_tx = musb_readw(musb->pRegs, MGC_O_HDRC_INTRTX);
+       musb->int_rx = musb_readw(musb->pRegs, MGC_O_HDRC_INTRRX);
+
+       if (musb->int_usb || musb->int_tx || musb->int_rx)
+               retval = musb_interrupt(musb);
+
+       spin_unlock_irqrestore(&musb->Lock, flags);
+
+       /* REVISIT we sometimes get spurious IRQs on g_ep0
+        * not clear why...
+        */
+       if (retval != IRQ_HANDLED)
+               DBG(5, "spurious?\n");
+
+       return IRQ_HANDLED;
+}
+
+#else
+#define generic_interrupt      NULL
+#endif
+
+/*
+ * handle all the irqs defined by the HDRC core. for now we expect:  other
+ * irq sources (phy, dma, etc) will be handled first, musb->int_* values
+ * will be assigned, and the irq will already have been acked.
+ *
+ * called in irq context with spinlock held, irqs blocked
+ */
+irqreturn_t musb_interrupt(struct musb *musb)
+{
+       irqreturn_t     retval = IRQ_NONE;
+       u8              devctl, power;
+       int             ep_num;
+       u32             reg;
+
+       devctl = musb_readb(musb->pRegs, MGC_O_HDRC_DEVCTL);
+       power = musb_readb(musb->pRegs, MGC_O_HDRC_POWER);
+
+       DBG(4, "** IRQ %s usb%04x tx%04x rx%04x\n",
+               (devctl & MGC_M_DEVCTL_HM) ? "host" : "peripheral",
+               musb->int_usb, musb->int_tx, musb->int_rx);
+
+       /* the core can interrupt us for multiple reasons; docs have
+        * a generic interrupt flowchart to follow
+        */
+       if (musb->int_usb & STAGE0_MASK)
+               retval |= musb_stage0_irq(musb, musb->int_usb,
+                               devctl, power);
+
+       /* "stage 1" is handling endpoint irqs */
+
+       /* handle endpoint 0 first */
+       if (musb->int_tx & 1) {
+               if (devctl & MGC_M_DEVCTL_HM)
+                       retval |= musb_h_ep0_irq(musb);
+               else
+                       retval |= musb_g_ep0_irq(musb);
+       }
+
+       /* RX on endpoints 1-15 */
+       reg = musb->int_rx >> 1;
+       ep_num = 1;
+       while (reg) {
+               if (reg & 1) {
+                       // MGC_SelectEnd(musb->pRegs, ep_num);
+                       /* REVISIT just retval = ep->rx_irq(...) */
+                       retval = IRQ_HANDLED;
+                       if (devctl & MGC_M_DEVCTL_HM) {
+                               if (is_host_capable())
+                                       musb_host_rx(musb, ep_num);
+                       } else {
+                               if (is_peripheral_capable())
+                                       musb_g_rx(musb, ep_num);
+                       }
+               }
+
+               reg >>= 1;
+               ep_num++;
+       }
+
+       /* TX on endpoints 1-15 */
+       reg = musb->int_tx >> 1;
+       ep_num = 1;
+       while (reg) {
+               if (reg & 1) {
+                       // MGC_SelectEnd(musb->pRegs, ep_num);
+                       /* REVISIT just retval |= ep->tx_irq(...) */
+                       retval = IRQ_HANDLED;
+                       if (devctl & MGC_M_DEVCTL_HM) {
+                               if (is_host_capable())
+                                       musb_host_tx(musb, ep_num);
+                       } else {
+                               if (is_peripheral_capable())
+                                       musb_g_tx(musb, ep_num);
+                       }
+               }
+               reg >>= 1;
+               ep_num++;
+       }
+
+       /* finish handling "global" interrupts after handling fifos */
+       if (musb->int_usb)
+               retval |= musb_stage2_irq(musb,
+                               musb->int_usb, devctl, power);
+
+       return retval;
+}
+
+
+#ifndef CONFIG_USB_INVENTRA_FIFO
+static int __initdata use_dma = 1;
+
+/* "modprobe ... use_dma=0" etc */
+module_param(use_dma, bool, 0);
+MODULE_PARM_DESC(use_dma, "enable/disable use of DMA");
+
+void musb_dma_completion(struct musb *musb, u8 bLocalEnd, u8 bTransmit)
+{
+       u8      devctl = musb_readb(musb->pRegs, MGC_O_HDRC_DEVCTL);
+
+       /* called with controller lock already held */
+
+       if (!bLocalEnd) {
+#ifndef CONFIG_USB_TUSB_OMAP_DMA
+               if (!is_cppi_enabled()) {
+                       /* endpoint 0 */
+                       if (devctl & MGC_M_DEVCTL_HM)
+                               musb_h_ep0_irq(musb);
+                       else
+                               musb_g_ep0_irq(musb);
+               }
+#endif
+       } else {
+               /* endpoints 1..15 */
+               if (bTransmit) {
+                       if (devctl & MGC_M_DEVCTL_HM) {
+                               if (is_host_capable())
+                                       musb_host_tx(musb, bLocalEnd);
+                       } else {
+                               if (is_peripheral_capable())
+                                       musb_g_tx(musb, bLocalEnd);
+                       }
+               } else {
+                       /* receive */
+                       if (devctl & MGC_M_DEVCTL_HM) {
+                               if (is_host_capable())
+                                       musb_host_rx(musb, bLocalEnd);
+                       } else {
+                               if (is_peripheral_capable())
+                                       musb_g_rx(musb, bLocalEnd);
+                       }
+               }
+       }
+}
+
+#else
+#define use_dma                        0
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_SYSFS
+
+static ssize_t
+musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct musb *musb = dev_to_musb(dev);
+       unsigned long flags;
+       int ret = -EINVAL;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+       switch (musb->board_mode) {
+       case MUSB_HOST:
+               ret = sprintf(buf, "host\n");
+               break;
+       case MUSB_PERIPHERAL:
+               ret = sprintf(buf, "peripheral\n");
+               break;
+       case MUSB_OTG:
+               ret = sprintf(buf, "otg\n");
+               break;
+       }
+       spin_unlock_irqrestore(&musb->Lock, flags);
+
+       return ret;
+}
+static DEVICE_ATTR(mode, S_IRUGO, musb_mode_show, NULL);
+
+static ssize_t
+musb_cable_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct musb *musb = dev_to_musb(dev);
+       char *v1= "", *v2 = "?";
+       unsigned long flags;
+       int vbus;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+#if defined(CONFIG_USB_TUSB6010) && !defined(CONFIG_USB_MUSB_OTG)
+       /* REVISIT: connect-A != connect-B ... */
+       vbus = musb_platform_get_vbus_status(musb);
+       if (vbus)
+               v2 = "connected";
+       else
+               v2 = "disconnected";
+#else
+       /* NOTE: board-specific issues, like too-big capacitors keeping
+        * VBUS high for a long time after power has been removed, can
+        * cause temporary false indications of a connection.
+        */
+       vbus = musb_readb(musb->pRegs, MGC_O_HDRC_DEVCTL);
+       if (vbus & 0x10) {
+               /* REVISIT retest on real OTG hardware */
+               switch (musb->board_mode) {
+               case MUSB_HOST:
+                       v2 = "A";
+                       break;
+               case MUSB_PERIPHERAL:
+                       v2 = "B";
+                       break;
+               case MUSB_OTG:
+                       v1 = "Mini-";
+                       v2 = (vbus & MGC_M_DEVCTL_BDEVICE) ? "B" : "A";
+                       break;
+               }
+       } else  /* VBUS level below A-Valid */
+               v2 = "disconnected";
+#endif
+       musb_platform_try_idle(musb);
+       spin_unlock_irqrestore(&musb->Lock, flags);
+
+       return sprintf(buf, "%s%s\n", v1, v2);
+}
+static DEVICE_ATTR(cable, S_IRUGO, musb_cable_show, NULL);
+
+#endif
+
+/* Only used to provide cable state change events */
+static void musb_irq_work(struct work_struct *data)
+{
+       struct musb *musb = container_of(data, struct musb, irq_work);
+
+       sysfs_notify(&musb->controller->kobj, NULL, "cable");
+}
+
+/* --------------------------------------------------------------------------
+ * Init support
+ */
+
+static struct musb *__init
+allocate_instance(struct device *dev, void __iomem *mbase)
+{
+       struct musb             *musb;
+       struct musb_hw_ep       *ep;
+       int                     epnum;
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       struct usb_hcd  *hcd;
+
+       hcd = usb_create_hcd(&musb_hc_driver, dev, dev->bus_id);
+       if (!hcd)
+               return NULL;
+       /* usbcore sets dev->driver_data to hcd, and sometimes uses that... */
+
+       musb = hcd_to_musb(hcd);
+       INIT_LIST_HEAD(&musb->control);
+       INIT_LIST_HEAD(&musb->in_bulk);
+       INIT_LIST_HEAD(&musb->out_bulk);
+
+       hcd->uses_new_polling = 1;
+
+       musb->vbuserr_retry = VBUSERR_RETRY_COUNT;
+#else
+       musb = kzalloc(sizeof *musb, GFP_KERNEL);
+       if (!musb)
+               return NULL;
+       dev_set_drvdata(dev, musb);
+
+#endif
+
+       musb->pRegs = mbase;
+       musb->ctrl_base = mbase;
+       musb->nIrq = -ENODEV;
+       for (epnum = 0, ep = musb->aLocalEnd;
+                       epnum < MUSB_C_NUM_EPS;
+                       epnum++, ep++) {
+
+               ep->musb = musb;
+               ep->bLocalEnd = epnum;
+       }
+
+       musb->controller = dev;
+       return musb;
+}
+
+static void musb_free(struct musb *musb)
+{
+       /* this has multiple entry modes. it handles fault cleanup after
+        * probe(), where things may be partially set up, as well as rmmod
+        * cleanup after everything's been de-activated.
+        */
+
+#ifdef CONFIG_SYSFS
+       device_remove_file(musb->controller, &dev_attr_mode);
+       device_remove_file(musb->controller, &dev_attr_cable);
+#endif
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+       musb_gadget_cleanup(musb);
+#endif
+
+       if (musb->nIrq >= 0) {
+               disable_irq_wake(musb->nIrq);
+               free_irq(musb->nIrq, musb);
+       }
+       if (is_dma_capable() && musb->pDmaController) {
+               struct dma_controller   *c = musb->pDmaController;
+
+               (void) c->stop(c->pPrivateData);
+               dma_controller_destroy(c);
+       }
+
+       musb_writeb(musb->pRegs, MGC_O_HDRC_DEVCTL, 0);
+       musb_platform_exit(musb);
+       musb_writeb(musb->pRegs, MGC_O_HDRC_DEVCTL, 0);
+
+       if (musb->clock) {
+               clk_disable(musb->clock);
+               clk_put(musb->clock);
+       }
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       usb_put_hcd(musb_to_hcd(musb));
+#else
+       kfree(musb);
+#endif
+}
+
+/*
+ * Perform generic per-controller initialization.
+ *
+ * @pDevice: the controller (already clocked, etc)
+ * @nIrq: irq
+ * @pRegs: virtual address of controller registers,
+ *     not yet corrected for platform-specific offsets
+ */
+static int __init
+musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
+{
+       int                     status;
+       struct musb             *pThis;
+       struct musb_hdrc_platform_data *plat = dev->platform_data;
+
+       /* The driver might handle more features than the board; OK.
+        * Fail when the board needs a feature that's not enabled.
+        */
+       if (!plat) {
+               dev_dbg(dev, "no platform_data?\n");
+               return -ENODEV;
+       }
+       switch (plat->mode) {
+       case MUSB_HOST:
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+               break;
+#else
+               goto bad_config;
+#endif
+       case MUSB_PERIPHERAL:
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+               break;
+#else
+               goto bad_config;
+#endif
+       case MUSB_OTG:
+#ifdef CONFIG_USB_MUSB_OTG
+               break;
+#else
+       bad_config:
+#endif
+       default:
+               dev_err(dev, "incompatible Kconfig role setting\n");
+               return -EINVAL;
+       }
+
+       /* allocate */
+       pThis = allocate_instance(dev, ctrl);
+       if (!pThis)
+               return -ENOMEM;
+
+       spin_lock_init(&pThis->Lock);
+       pThis->board_mode = plat->mode;
+       pThis->board_set_power = plat->set_power;
+       pThis->min_power = plat->min_power;
+
+       /* assume vbus is off */
+
+       /* platform adjusts pThis->pRegs and pThis->isr if needed,
+        * and activates clocks
+        */
+       pThis->isr = generic_interrupt;
+       status = musb_platform_init(pThis);
+
+       if (status < 0)
+               goto fail;
+       if (!pThis->isr) {
+               status = -ENODEV;
+               goto fail2;
+       }
+
+#ifndef CONFIG_USB_INVENTRA_FIFO
+       if (use_dma && dev->dma_mask) {
+               struct dma_controller   *c;
+
+               c = dma_controller_create(pThis, pThis->pRegs);
+               pThis->pDmaController = c;
+               if (c)
+                       (void) c->start(c->pPrivateData);
+       }
+#endif
+       /* ideally this would be abstracted in platform setup */
+       if (!is_dma_capable() || !pThis->pDmaController)
+               dev->dma_mask = NULL;
+
+       /* be sure interrupts are disabled before connecting ISR */
+       musb_platform_disable(pThis);
+
+       /* setup musb parts of the core (especially endpoints) */
+       status = musb_core_init(plat->multipoint
+                       ? MUSB_CONTROLLER_MHDRC
+                       : MUSB_CONTROLLER_HDRC, pThis);
+       if (status < 0)
+               goto fail2;
+
+       /* attach to the IRQ */
+       if (request_irq (nIrq, pThis->isr, 0, dev->bus_id, pThis)) {
+               dev_err(dev, "request_irq %d failed!\n", nIrq);
+               status = -ENODEV;
+               goto fail2;
+       }
+       pThis->nIrq = nIrq;
+// FIXME this handles wakeup irqs wrong
+       if (enable_irq_wake(nIrq) == 0)
+               device_init_wakeup(dev, 1);
+
+       pr_info("%s: USB %s mode controller at %p using %s, IRQ %d\n",
+                       musb_driver_name,
+                       ({char *s;
+                       switch (pThis->board_mode) {
+                       case MUSB_HOST:         s = "Host"; break;
+                       case MUSB_PERIPHERAL:   s = "Peripheral"; break;
+                       default:                s = "OTG"; break;
+                       }; s; }),
+                       ctrl,
+                       (is_dma_capable() && pThis->pDmaController)
+                               ? "DMA" : "PIO",
+                       pThis->nIrq);
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       /* host side needs more setup, except for no-host modes */
+       if (pThis->board_mode != MUSB_PERIPHERAL) {
+               struct usb_hcd  *hcd = musb_to_hcd(pThis);
+
+               if (pThis->board_mode == MUSB_OTG)
+                       hcd->self.otg_port = 1;
+               pThis->xceiv.host = &hcd->self;
+               hcd->power_budget = 2 * (plat->power ? : 250);
+       }
+#endif                         /* CONFIG_USB_MUSB_HDRC_HCD */
+
+       /* For the host-only role, we can activate right away.
+        * (We expect the ID pin to be forcibly grounded!!)
+        * Otherwise, wait till the gadget driver hooks up.
+        */
+       if (!is_otg_enabled(pThis) && is_host_enabled(pThis)) {
+               MUSB_HST_MODE(pThis);
+               pThis->xceiv.default_a = 1;
+               pThis->xceiv.state = OTG_STATE_A_IDLE;
+
+               status = usb_add_hcd(musb_to_hcd(pThis), -1, 0);
+
+               DBG(1, "%s mode, status %d, devctl %02x %c\n",
+                       "HOST", status,
+                       musb_readb(pThis->pRegs, MGC_O_HDRC_DEVCTL),
+                       (musb_readb(pThis->pRegs, MGC_O_HDRC_DEVCTL)
+                                       & MGC_M_DEVCTL_BDEVICE
+                               ? 'B' : 'A'));
+
+       } else /* peripheral is enabled */ {
+               MUSB_DEV_MODE(pThis);
+               pThis->xceiv.default_a = 0;
+               pThis->xceiv.state = OTG_STATE_B_IDLE;
+
+               status = musb_gadget_setup(pThis);
+
+               DBG(1, "%s mode, status %d, dev%02x\n",
+                       is_otg_enabled(pThis) ? "OTG" : "PERIPHERAL",
+                       status,
+                       musb_readb(pThis->pRegs, MGC_O_HDRC_DEVCTL));
+
+       }
+
+       if (status == 0)
+               musb_debug_create("driver/musb_hdrc", pThis);
+       else {
+fail:
+               device_init_wakeup(dev, 0);
+               musb_free(pThis);
+               return status;
+       }
+
+       INIT_WORK(&pThis->irq_work, musb_irq_work);
+
+#ifdef CONFIG_SYSFS
+       status = device_create_file(dev, &dev_attr_mode);
+       status = device_create_file(dev, &dev_attr_cable);
+       status = 0;
+#endif
+
+       return status;
+
+fail2:
+       musb_platform_exit(pThis);
+       goto fail;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* all implementations (PCI bridge to FPGA, VLYNQ, etc) should just
+ * bridge to a platform device; this driver then suffices.
+ */
+
+#ifndef CONFIG_USB_INVENTRA_FIFO
+static u64     *orig_dma_mask;
+#endif
+
+static int __init musb_probe(struct platform_device *pdev)
+{
+       struct device   *dev = &pdev->dev;
+       int             irq = platform_get_irq(pdev, 0);
+       struct resource *iomem;
+       void __iomem    *base;
+
+       iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!iomem || irq == 0)
+               return -ENODEV;
+
+       base = ioremap(iomem->start, iomem->end - iomem->start + 1);
+       if (!base) {
+               dev_err(dev, "ioremap failed\n");
+               return -ENOMEM;
+       }
+
+#ifndef CONFIG_USB_INVENTRA_FIFO
+       /* clobbered by use_dma=n */
+       orig_dma_mask = dev->dma_mask;
+#endif
+       return musb_init_controller(dev, irq, base);
+}
+
+static int __devexit musb_remove(struct platform_device *pdev)
+{
+       struct musb     *musb = dev_to_musb(&pdev->dev);
+       void __iomem    *ctrl_base = musb->ctrl_base;
+
+       /* this gets called on rmmod.
+        *  - Host mode: host may still be active
+        *  - Peripheral mode: peripheral is deactivated (or never-activated)
+        *  - OTG mode: both roles are deactivated (or never-activated)
+        */
+       musb_shutdown(pdev);
+       musb_debug_delete("driver/musb_hdrc", musb);
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       if (musb->board_mode == MUSB_HOST)
+               usb_remove_hcd(musb_to_hcd(musb));
+#endif
+       musb_free(musb);
+       iounmap(ctrl_base);
+       device_init_wakeup(&pdev->dev, 0);
+#ifndef CONFIG_USB_INVENTRA_FIFO
+       pdev->dev.dma_mask = orig_dma_mask;
+#endif
+       return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int musb_suspend(struct platform_device *pdev, pm_message_t message)
+{
+       unsigned long   flags;
+       struct musb     *musb = dev_to_musb(&pdev->dev);
+
+       if (!musb->clock)
+               return 0;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+
+       if (is_peripheral_active(musb)) {
+               /* FIXME force disconnect unless we know USB will wake
+                * the system up quickly enough to respond ...
+                */
+       } else if (is_host_active(musb)) {
+               /* we know all the children are suspended; sometimes
+                * they will even be wakeup-enabled.
+                */
+       }
+
+       clk_disable(musb->clock);
+       spin_unlock_irqrestore(&musb->Lock, flags);
+       return 0;
+}
+
+static int musb_resume(struct platform_device *pdev)
+{
+       unsigned long   flags;
+       struct musb     *musb = dev_to_musb(&pdev->dev);
+
+       if (!musb->clock)
+               return 0;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+       clk_enable(musb->clock);
+       /* for static cmos like DaVinci, register values were preserved
+        * unless for some reason the whole soc powered down and we're
+        * not treating that as a whole-system restart (e.g. swsusp)
+        */
+       spin_unlock_irqrestore(&musb->Lock, flags);
+       return 0;
+}
+
+#else
+#define        musb_suspend    NULL
+#define        musb_resume     NULL
+#endif
+
+static struct platform_driver musb_driver = {
+       .driver = {
+               .name           = (char *)musb_driver_name,
+               .bus            = &platform_bus_type,
+               .owner          = THIS_MODULE,
+       },
+       .remove         = __devexit_p(musb_remove),
+       .shutdown       = musb_shutdown,
+       .suspend        = musb_suspend,
+       .resume         = musb_resume,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init musb_init(void)
+{
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       if (usb_disabled())
+               return 0;
+#endif
+
+       pr_info("%s: version " MUSB_VERSION ", "
+#ifdef CONFIG_USB_INVENTRA_FIFO
+               "pio"
+#elif defined(CONFIG_USB_TI_CPPI_DMA)
+               "cppi-dma"
+#elif defined(CONFIG_USB_INVENTRA_DMA)
+               "musb-dma"
+#elif defined(CONFIG_USB_TUSB_OMAP_DMA)
+               "tusb-omap-dma"
+#else
+               "?dma?"
+#endif
+               ", "
+#ifdef CONFIG_USB_MUSB_OTG
+               "otg (peripheral+host)"
+#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
+               "peripheral"
+#elif defined(CONFIG_USB_MUSB_HDRC_HCD)
+               "host"
+#endif
+               ", debug=%d\n",
+               musb_driver_name, debug);
+       return platform_driver_probe(&musb_driver, musb_probe);
+}
+
+/* make us init after usbcore and before usb
+ * gadget and host-side drivers start to register
+ */
+subsys_initcall(musb_init);
+
+static void __exit musb_cleanup(void)
+{
+       platform_driver_unregister(&musb_driver);
+}
+module_exit(musb_cleanup);
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
new file mode 100644 (file)
index 0000000..1f1e554
--- /dev/null
@@ -0,0 +1,852 @@
+/*
+ * TUSB6010 USB 2.0 OTG Dual Role controller
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Jarkko Nikula <jarkko.nikula@nokia.com>
+ * Tony Lindgren <tony@atomide.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.
+ *
+ * Notes:
+ * - Driver assumes that interface to external host (main CPU) is
+ *   configured for NOR FLASH interface instead of VLYNQ serial
+ *   interface.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+
+#include "musbdefs.h"
+
+
+/*
+ * TUSB 6010 may use a parallel bus that doesn't support byte ops;
+ * so both loading and unloading FIFOs need explicit byte counts.
+ */
+
+void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *buf)
+{
+       void __iomem    *ep_conf = hw_ep->conf;
+       void __iomem    *fifo = hw_ep->fifo;
+       u8              epnum = hw_ep->bLocalEnd;
+       u8              *bufp = (u8 *)buf;
+       int             i, remain;
+       u32             val;
+
+       prefetch(bufp);
+
+       DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
+                       'T', epnum, fifo, len, bufp);
+
+       if (epnum)
+               musb_writel(ep_conf, TUSB_EP_TX_OFFSET,
+                       TUSB_EP_CONFIG_XFR_SIZE(len));
+       else
+               musb_writel(ep_conf, 0, TUSB_EP0_CONFIG_DIR_TX |
+                       TUSB_EP0_CONFIG_XFR_SIZE(len));
+
+       /* Write 32-bit blocks from buffer to FIFO
+        * REVISIT: Optimize for burst ... writesl/writesw
+        */
+       if (len >= 4) {
+               if (((unsigned long)bufp & 0x3) == 0) {
+                       for (i = 0; i < (len / 4); i++ ) {
+                               val = *(u32 *)bufp;
+                               bufp += 4;
+                               musb_writel(fifo, 0, val);
+                       }
+               } else if (((unsigned long)bufp & 0x2) == 0x2) {
+                       for (i = 0; i < (len / 4); i++ ) {
+                               val = (u32)(*(u16 *)bufp);
+                               bufp += 2;
+                               val |= (*(u16 *)bufp) << 16;
+                               bufp += 2;
+                               musb_writel(fifo, 0, val);
+                       }
+               } else {
+                       for (i = 0; i < (len / 4); i++ ) {
+                               memcpy(&val, bufp, 4);
+                               bufp += 4;
+                               musb_writel(fifo, 0, val);
+                       }
+               }
+               remain = len - (i * 4);
+       } else
+               remain = len;
+
+       if (remain) {
+               /* Write rest of 1-3 bytes from buffer into FIFO */
+               memcpy(&val, bufp, remain);
+               musb_writel(fifo, 0, val);
+       }
+}
+
+void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf)
+{
+       void __iomem    *ep_conf = hw_ep->conf;
+       void __iomem    *fifo = hw_ep->fifo;
+       u8              epnum = hw_ep->bLocalEnd;
+       u8              *bufp = (u8 *)buf;
+       int             i, remain;
+       u32             val;
+
+       DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
+                       'R', epnum, fifo, len, bufp);
+
+       if (epnum)
+               musb_writel(ep_conf, TUSB_EP_RX_OFFSET,
+                       TUSB_EP_CONFIG_XFR_SIZE(len));
+       else
+               musb_writel(ep_conf, 0, TUSB_EP0_CONFIG_XFR_SIZE(len));
+
+       /* Read 32-bit blocks from FIFO to buffer
+        * REVISIT: Optimize for burst ... writesl/writesw
+        */
+       if (len >= 4) {
+               if (((unsigned long)bufp & 0x3) == 0) {
+                       for (i = 0; i < (len / 4); i++) {
+                               val = musb_readl(fifo, 0);
+                               *(u32 *)bufp = val;
+                               bufp += 4;
+                       }
+               } else if (((unsigned long)bufp & 0x2) == 0x2) {
+                       for (i = 0; i < (len / 4); i++) {
+                               val = musb_readl(fifo, 0);
+                               *(u16 *)bufp = (u16)(val & 0xffff);
+                               bufp += 2;
+                               *(u16 *)bufp = (u16)(val >> 16);
+                               bufp += 2;
+                       }
+               } else {
+                       for (i = 0; i < (len / 4); i++) {
+                               val = musb_readl(fifo, 0);
+                               memcpy(bufp, &val, 4);
+                               bufp += 4;
+                       }
+               }
+               remain = len - (i * 4);
+       } else
+               remain = len;
+
+       if (remain) {
+               /* Read rest of 1-3 bytes from FIFO */
+               val = musb_readl(fifo, 0);
+               memcpy(bufp, &val, remain);
+       }
+}
+
+/* This is used by gadget drivers, and OTG transceiver logic, allowing
+ * at most mA current to be drawn from VBUS during a Default-B session
+ * (that is, while VBUS exceeds 4.4V).  In Default-A (including pure host
+ * mode), or low power Default-B sessions, something else supplies power.
+ * Caller must take care of locking.
+ */
+static int tusb_set_power(struct otg_transceiver *x, unsigned mA)
+{
+       struct musb     *musb = container_of(x, struct musb, xceiv);
+       void __iomem    *base = musb->ctrl_base;
+       u32             reg;
+
+       /* tps65030 seems to consume max 100mA, with maybe 60mA available
+        * (measured on one board) for things other than tps and tusb.
+        *
+        * REVISIT we could use VBUS to supply only _one_ of { 1.5V, 3.3V }.
+        * The actual current usage would be very board-specific.  For now,
+        * it's simpler to just use an aggregate (also board-specific).
+        */
+       if (x->default_a || mA < (musb->min_power << 1))
+               mA = 0;
+
+       reg = musb_readl(base, TUSB_PRCM_MNGMT);
+       if (mA)
+               reg |= TUSB_PRCM_MNGMT_15_SW_EN | TUSB_PRCM_MNGMT_33_SW_EN;
+       else
+               reg &= ~(TUSB_PRCM_MNGMT_15_SW_EN | TUSB_PRCM_MNGMT_33_SW_EN);
+       musb_writel(base, TUSB_PRCM_MNGMT, reg);
+
+       DBG(2, "draw max %d mA VBUS\n", mA);
+       return 0;
+}
+
+/* workaround for issue 13:  change clock during chip idle
+ * (to be fixed in rev3 silicon) ... symptoms include disconnect
+ * or looping suspend/resume cycles
+ */
+static void tusb_set_clock_source(struct musb *musb, unsigned mode)
+{
+       void __iomem    *base = musb->ctrl_base;
+       u32             reg;
+
+       reg = musb_readl(base, TUSB_PRCM_CONF);
+       reg &= ~TUSB_PRCM_CONF_SYS_CLKSEL(0x3);
+
+       /* 0 = refclk (clkin, XI)
+        * 1 = PHY 60 MHz (internal PLL)
+        * 2 = not supported
+        * 3 = NOR clock (huh?)
+        */
+       if (mode > 0)
+               reg |= TUSB_PRCM_CONF_SYS_CLKSEL(mode & 0x3);
+
+       musb_writel(base, TUSB_PRCM_CONF, reg);
+
+       // FIXME tusb6010_platform_retime(mode == 0);
+}
+
+/*
+ * Idle TUSB6010 until next wake-up event; NOR access always wakes.
+ * Other code ensures that we idle unless we're connected _and_ the
+ * USB link is not suspended ... and tells us the relevant wakeup
+ * events.  SW_EN for voltage is handled separately.
+ */
+static void tusb_allow_idle(struct musb *musb, u32 wakeup_enables)
+{
+       void __iomem    *base = musb->ctrl_base;
+       u32             reg;
+
+       tusb_set_clock_source(musb, 0);
+
+       wakeup_enables |= TUSB_PRCM_WNORCS;
+       musb_writel(base, TUSB_PRCM_WAKEUP_MASK, ~wakeup_enables);
+
+       /* REVISIT writeup of WID implies that if WID set and ID is grounded,
+        * TUSB_PHY_OTG_CTRL.TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP must be cleared.
+        * Presumably that's mostly to save power, hence WID is immaterial ...
+        */
+
+       reg = musb_readl(base, TUSB_PRCM_MNGMT);
+       /* issue 4: when driving vbus, use hipower (vbus_det) comparator */
+       if (is_host_active(musb)) {
+               reg |= TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN;
+               reg &= ~TUSB_PRCM_MNGMT_OTG_SESS_END_EN;
+       } else {
+               reg |= TUSB_PRCM_MNGMT_OTG_SESS_END_EN;
+               reg &= ~TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN;
+       }
+       reg |= TUSB_PRCM_MNGMT_PM_IDLE | TUSB_PRCM_MNGMT_DEV_IDLE;
+       musb_writel(base, TUSB_PRCM_MNGMT, reg);
+
+       DBG(2, "idle, wake on %02x\n", wakeup_enables);
+}
+
+/*
+ * Updates cable VBUS status. Caller must take care of locking.
+ */
+int musb_platform_get_vbus_status(struct musb *musb)
+{
+       void __iomem    *base = musb->ctrl_base;
+       u32             otg_stat, prcm_mngmt;
+       int             ret = 0;
+
+       otg_stat = musb_readl(base, TUSB_DEV_OTG_STAT);
+       prcm_mngmt = musb_readl(base, TUSB_PRCM_MNGMT);
+
+       /* Temporarily enable VBUS detection if it was disabled for
+        * suspend mode. Unless it's enabled otg_stat and devctl will
+        * not show correct VBUS state.
+        */
+       if (!(prcm_mngmt & TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN)) {
+               u32 tmp = prcm_mngmt;
+               tmp |= TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN;
+               musb_writel(base, TUSB_PRCM_MNGMT, tmp);
+               otg_stat = musb_readl(base, TUSB_DEV_OTG_STAT);
+               musb_writel(base, TUSB_PRCM_MNGMT, prcm_mngmt);
+       }
+
+       if (otg_stat & TUSB_DEV_OTG_STAT_VBUS_SENSE)
+               ret = 1;
+
+       return ret;
+}
+
+static struct timer_list musb_idle_timer;
+
+static void musb_do_idle(unsigned long _musb)
+{
+       struct musb     *musb = (void *)_musb;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+       if (!musb->is_active) {
+               u32     wakeups;
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+               /* wait until khubd handles port change status */
+               if (is_host_active(musb) && (musb->port1_status >> 16))
+                       goto done;
+#endif
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+               if (is_peripheral_enabled(musb) && !musb->pGadgetDriver)
+                       wakeups = 0;
+               else {
+                       wakeups = TUSB_PRCM_WHOSTDISCON
+                                       | TUSB_PRCM_WBUS
+                                       | TUSB_PRCM_WVBUS;
+                       if (is_otg_enabled(musb))
+                               wakeups |= TUSB_PRCM_WID;
+               }
+#else
+               wakeups = TUSB_PRCM_WHOSTDISCON | TUSB_PRCM_WBUS;
+#endif
+               tusb_allow_idle(musb, wakeups);
+       }
+done:
+       spin_unlock_irqrestore(&musb->Lock, flags);
+}
+
+/*
+ * Maybe put TUSB6010 into idle mode mode depending on USB link status,
+ * like "disconnected" or "suspended".  We'll be woken out of it by
+ * connect, resume, or disconnect.
+ *
+ * Needs to be called as the last function everywhere where there is
+ * register access to TUSB6010 because of NOR flash wake-up.
+ * Caller should own controller spinlock.
+ *
+ * Delay because peripheral enables D+ pullup 3msec after SE0, and
+ * we don't want to treat that full speed J as a wakeup event.
+ * ... peripherals must draw only suspend current after 10 msec.
+ */
+void musb_platform_try_idle(struct musb *musb)
+{
+       if (musb->is_active)
+               del_timer(&musb_idle_timer);
+       else
+               mod_timer(&musb_idle_timer, jiffies + msecs_to_jiffies(3));
+}
+
+/* ticks of 60 MHz clock */
+#define DEVCLOCK               60000000
+#define OTG_TIMER_MS(msecs)    ((msecs) \
+               ? (TUSB_DEV_OTG_TIMER_VAL((DEVCLOCK/1000)*(msecs)) \
+                               | TUSB_DEV_OTG_TIMER_ENABLE) \
+               : 0)
+
+static void tusb_set_vbus(struct musb *musb, int is_on)
+{
+       void __iomem    *base = musb->ctrl_base;
+       u32             conf, prcm, timer;
+       u8              devctl;
+
+       /* HDRC controls CPEN, but beware current surges during device
+        * connect.  They can trigger transient overcurrent conditions
+        * that must be ignored.
+        */
+
+       prcm = musb_readl(base, TUSB_PRCM_MNGMT);
+       conf = musb_readl(base, TUSB_DEV_CONF);
+       devctl = musb_readb(musb->pRegs, MGC_O_HDRC_DEVCTL);
+
+       if (is_on) {
+               musb->is_active = 1;
+               timer = OTG_TIMER_MS(OTG_TIME_A_WAIT_VRISE);
+
+               musb->xceiv.default_a = 1;
+               musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
+               devctl |= MGC_M_DEVCTL_SESSION;
+
+               conf |= TUSB_DEV_CONF_USB_HOST_MODE;
+               MUSB_HST_MODE(musb);
+       } else {
+               musb->is_active = 0;
+               timer = 0;
+
+               /* NOTE:  we're skipping A_WAIT_VFALL -> A_IDLE and
+                * jumping right to B_IDLE...
+                */
+
+               musb->xceiv.default_a = 0;
+               musb->xceiv.state = OTG_STATE_B_IDLE;
+               devctl &= ~MGC_M_DEVCTL_SESSION;
+
+               conf &= ~TUSB_DEV_CONF_USB_HOST_MODE;
+               MUSB_DEV_MODE(musb);
+       }
+       prcm &= ~(TUSB_PRCM_MNGMT_15_SW_EN | TUSB_PRCM_MNGMT_33_SW_EN);
+
+       musb_writel(base, TUSB_PRCM_MNGMT, prcm);
+       musb_writel(base, TUSB_DEV_OTG_TIMER, timer);
+       musb_writel(base, TUSB_DEV_CONF, conf);
+       musb_writeb(musb->pRegs, MGC_O_HDRC_DEVCTL, devctl);
+
+       DBG(1, "VBUS %s, devctl %02x otg %3x conf %08x prcm %08x\n",
+               otg_state_string(musb),
+               musb_readb(musb->pRegs, MGC_O_HDRC_DEVCTL),
+               musb_readl(base, TUSB_DEV_OTG_STAT),
+               conf, prcm);
+}
+
+static inline void
+tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *base)
+{
+       u32     otg_stat = musb_readl(base, TUSB_DEV_OTG_STAT);
+
+       /* ID pin */
+       if ((int_src & TUSB_INT_SRC_ID_STATUS_CHNG)) {
+               int     default_a;
+
+               if (is_otg_enabled(musb))
+                       default_a = !(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS);
+               else
+                       default_a = is_host_enabled(musb);
+               DBG(2, "Default-%c\n", default_a ? 'A' : 'B');
+               musb->xceiv.default_a = default_a;
+               tusb_set_vbus(musb, default_a);
+       }
+
+       /* VBUS state change */
+       if (int_src & TUSB_INT_SRC_VBUS_SENSE_CHNG) {
+
+               /* B-dev state machine:  no vbus ~= disconnect */
+               if ((is_otg_enabled(musb) && !musb->xceiv.default_a)
+                               || !is_host_enabled(musb)) {
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+                       // ? musb_root_disconnect(musb);
+                       musb->port1_status &=
+                               ~(USB_PORT_STAT_CONNECTION
+                               | USB_PORT_STAT_ENABLE
+                               | USB_PORT_STAT_LOW_SPEED
+                               | USB_PORT_STAT_HIGH_SPEED
+                               | USB_PORT_STAT_TEST
+                               );
+#endif
+
+                       if (otg_stat & TUSB_DEV_OTG_STAT_SESS_END) {
+                               if (musb->xceiv.state != OTG_STATE_B_IDLE) {
+                                       /* INTR_DISCONNECT can hide... */
+                                       musb->xceiv.state = OTG_STATE_B_IDLE;
+                                       musb->int_usb |= MGC_M_INTR_DISCONNECT;
+                               }
+                               musb->is_active = 0;
+                       }
+                       DBG(2, "vbus change, %s, otg %03x\n",
+                               otg_state_string(musb), otg_stat);
+                       schedule_work(&musb->irq_work);
+
+               } else /* A-dev state machine */ {
+                       DBG(4, "vbus change, %s, otg %03x\n",
+                               otg_state_string(musb), otg_stat);
+
+                       switch (musb->xceiv.state) {
+                       case OTG_STATE_A_WAIT_VRISE:
+                               /* ignore; A-session-valid < VBUS_VALID/2,
+                                * we monitor this with the timer
+                                */
+                               break;
+                       case OTG_STATE_A_WAIT_VFALL:
+                               /* REVISIT this irq triggers during short
+                                * spikes causet by enumeration ...
+                                */
+                               if (musb->vbuserr_retry) {
+                                       musb->vbuserr_retry--;
+                                       tusb_set_vbus(musb, 1);
+                               }
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       }
+
+       /* OTG timer expiration */
+       if (int_src & TUSB_INT_SRC_OTG_TIMEOUT) {
+               u8      devctl;
+
+               DBG(4, "%s timer, %03x\n", otg_state_string(musb), otg_stat);
+
+               switch (musb->xceiv.state) {
+               case OTG_STATE_A_WAIT_VRISE:
+                       /* VBUS has probably been valid for a while now,
+                        * but may well have bounced out of range a bit
+                        */
+                       devctl = musb_readb(musb->pRegs, MGC_O_HDRC_DEVCTL);
+                       if (otg_stat & TUSB_DEV_OTG_STAT_VBUS_VALID) {
+                               u32     timer;
+
+                               if ((devctl & MGC_M_DEVCTL_VBUS)
+                                               != MGC_M_DEVCTL_VBUS) {
+                                       DBG(2, "devctl %02x\n", devctl);
+                                       break;
+                               }
+                               musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
+
+                               /* REVISIT: if nothing is connected yet,
+                                * mark controller as inactive so that
+                                * we can suspend the TUSB chip.
+                                */
+
+                               /* timeout 0 == infinite (like non-OTG hosts) */
+                               timer = OTG_TIMER_MS(OTG_TIME_A_WAIT_BCON);
+                               if (timer)
+                                       musb_writel(base, TUSB_DEV_OTG_TIMER,
+                                                       timer);
+                       } else {
+                               /* REVISIT report overcurrent to hub? */
+                               ERR("vbus too slow, devctl %02x\n", devctl);
+                               tusb_set_vbus(musb, 0);
+                       }
+                       break;
+               case OTG_STATE_A_WAIT_BCON:
+                       if (OTG_TIME_A_WAIT_BCON)
+                               tusb_set_vbus(musb, 0);
+                       break;
+               case OTG_STATE_A_SUSPEND:
+                       break;
+               case OTG_STATE_B_WAIT_ACON:
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static irqreturn_t tusb_interrupt(int irq, void *__hci)
+{
+       struct musb     *musb = __hci;
+       void __iomem    *base = musb->ctrl_base;
+       unsigned long   flags;
+       u32             int_src;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+
+       int_src = musb_readl(base, TUSB_INT_SRC) & ~TUSB_INT_SRC_RESERVED_BITS;
+       DBG(3, "TUSB IRQ %08x\n", int_src);
+
+       musb->int_usb = (u8) int_src;
+
+       /* Acknowledge wake-up source interrupts */
+       if (int_src & TUSB_INT_SRC_DEV_WAKEUP) {
+               u32     reg;
+               u32     i;
+
+               /* there are issues re-locking the PLL on wakeup ... */
+
+               /* work around issue 8 */
+               for (i = 0xf7f7f7; i > 0xf7f7f7 - 1000; i--) {
+                       musb_writel(base, TUSB_SCRATCH_PAD, 0);
+                       musb_writel(base, TUSB_SCRATCH_PAD, i);
+                       reg = musb_readl(base, TUSB_SCRATCH_PAD);
+                       if (reg == i)
+                               break;
+                       DBG(1, "TUSB NOR not ready\n");
+               }
+
+               /* work around issue 13 (2nd half) */
+               tusb_set_clock_source(musb, 1);
+
+               reg = musb_readl(base, TUSB_PRCM_WAKEUP_SOURCE);
+               musb_writel(base, TUSB_PRCM_WAKEUP_CLEAR, reg);
+               if (reg & ~TUSB_PRCM_WNORCS) {
+                       musb->is_active = 1;
+                       schedule_work(&musb->irq_work);
+               }
+               DBG(3, "wake %sactive %02x\n",
+                               musb->is_active ? "" : "in", reg);
+
+               // REVISIT host side TUSB_PRCM_WHOSTDISCON, TUSB_PRCM_WBUS
+       }
+
+       /* OTG state change reports (annoyingly) not issued by Mentor core */
+       if (int_src & (TUSB_INT_SRC_VBUS_SENSE_CHNG
+                               | TUSB_INT_SRC_OTG_TIMEOUT
+                               | TUSB_INT_SRC_ID_STATUS_CHNG))
+               tusb_otg_ints(musb, int_src, base);
+
+       /* TX dma callback must be handled here, RX dma callback is
+        * handled in tusb_omap_dma_cb.
+        */
+       if ((int_src & TUSB_INT_SRC_TXRX_DMA_DONE)) {
+               u32     dma_src = musb_readl(base, TUSB_DMA_INT_SRC);
+               u32     real_dma_src = musb_readl(base, TUSB_DMA_INT_MASK);
+
+               DBG(3, "DMA IRQ %08x\n", dma_src);
+               real_dma_src = ~real_dma_src & dma_src;
+               if (tusb_dma_omap() && real_dma_src) {
+                       int     tx_source = (real_dma_src & 0xffff);
+                       int     i;
+
+                       for (i = 1; i <= 15; i++) {
+                               if (tx_source & (1 << i)) {
+                                       DBG(3, "completing ep%i %s\n", i, "tx");
+                                       musb_dma_completion(musb, i, 1);
+                               }
+                       }
+               }
+               musb_writel(base, TUSB_DMA_INT_CLEAR, dma_src);
+       }
+
+       /* EP interrupts. In OCP mode tusb6010 mirrors the MUSB * interrupts */
+       if (int_src & (TUSB_INT_SRC_USB_IP_TX | TUSB_INT_SRC_USB_IP_RX)) {
+               u32     musb_src = musb_readl(base, TUSB_USBIP_INT_SRC);
+
+               musb_writel(base, TUSB_USBIP_INT_CLEAR, musb_src);
+               musb->int_rx = (((musb_src >> 16) & 0xffff) << 1);
+               musb->int_tx = (musb_src & 0xffff);
+       } else
+               musb->int_rx = musb->int_tx = 0;
+
+       if (int_src & (TUSB_INT_SRC_USB_IP_TX | TUSB_INT_SRC_USB_IP_RX | 0xff))
+               musb_interrupt(musb);
+
+       /* Acknowledge TUSB interrupts. Clear only non-reserved bits */
+       musb_writel(base, TUSB_INT_SRC_CLEAR,
+               int_src & ~TUSB_INT_MASK_RESERVED_BITS);
+
+       musb_platform_try_idle(musb);
+       spin_unlock_irqrestore(&musb->Lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+static int dma_off;
+
+/*
+ * Enables TUSB6010. Caller must take care of locking.
+ * REVISIT:
+ * - Check what is unnecessary in MGC_HdrcStart()
+ */
+void musb_platform_enable(struct musb * musb)
+{
+       void __iomem    *base = musb->ctrl_base;
+
+       /* Setup TUSB6010 main interrupt mask. Enable all interrupts except SOF.
+        * REVISIT: Enable and deal with TUSB_INT_SRC_USB_IP_SOF */
+       musb_writel(base, TUSB_INT_MASK, TUSB_INT_SRC_USB_IP_SOF);
+
+       /* Setup TUSB interrupt, disable DMA and GPIO interrupts */
+       musb_writel(base, TUSB_USBIP_INT_MASK, 0);
+       musb_writel(base, TUSB_DMA_INT_MASK, 0x7fffffff);
+       musb_writel(base, TUSB_GPIO_INT_MASK, 0x1ff);
+
+       /* Clear all subsystem interrups */
+       musb_writel(base, TUSB_USBIP_INT_CLEAR, 0x7fffffff);
+       musb_writel(base, TUSB_DMA_INT_CLEAR, 0x7fffffff);
+       musb_writel(base, TUSB_GPIO_INT_CLEAR, 0x1ff);
+
+       /* Acknowledge pending interrupt(s) */
+       musb_writel(base, TUSB_INT_SRC_CLEAR, ~TUSB_INT_MASK_RESERVED_BITS);
+
+       /* Only 0 clock cycles for minimum interrupt de-assertion time and
+        * interrupt polarity active low seems to work reliably here */
+       musb_writel(base, TUSB_INT_CTRL_CONF,
+                       TUSB_INT_CTRL_CONF_INT_RELCYC(0));
+
+       set_irq_type(musb->nIrq, IRQ_TYPE_LEVEL_LOW);
+
+       /* maybe force into the Default-A OTG state machine */
+       if (!(musb_readl(base, TUSB_DEV_OTG_STAT)
+                       & TUSB_DEV_OTG_STAT_ID_STATUS))
+               musb_writel(base, TUSB_INT_SRC_SET,
+                               TUSB_INT_SRC_ID_STATUS_CHNG);
+
+       if (is_dma_capable() && dma_off)
+               printk(KERN_WARNING "%s %s: dma not reactivated\n",
+                               __FILE__, __FUNCTION__);
+       else
+               dma_off = 1;
+}
+
+/*
+ * Disables TUSB6010. Caller must take care of locking.
+ */
+void musb_platform_disable(struct musb *musb)
+{
+       void __iomem    *base = musb->ctrl_base;
+
+       /* FIXME stop DMA, IRQs, timers, ... */
+
+       /* disable all IRQs */
+       musb_writel(base, TUSB_INT_MASK, ~TUSB_INT_MASK_RESERVED_BITS);
+       musb_writel(base, TUSB_USBIP_INT_MASK, 0);
+       musb_writel(base, TUSB_DMA_INT_MASK, 0x7fffffff);
+       musb_writel(base, TUSB_GPIO_INT_MASK, 0x1ff);
+
+       del_timer(&musb_idle_timer);
+
+       if (is_dma_capable() && !dma_off) {
+               printk(KERN_WARNING "%s %s: dma still active\n",
+                               __FILE__, __FUNCTION__);
+               dma_off = 1;
+       }
+}
+
+/*
+ * Sets up TUSB6010 CPU interface specific signals and registers
+ * Note: Settings optimized for OMAP24xx
+ */
+static void __init tusb_setup_cpu_interface(struct musb *musb)
+{
+       void __iomem    *base = musb->ctrl_base;
+
+       /* Disable GPIO[7:0] pullups (used as output DMA requests) */
+       musb_writel(base, TUSB_PULLUP_1_CTRL, 0x000000FF);
+       /* Disable all pullups on NOR IF, DMAREQ0 and DMAREQ1 */
+       musb_writel(base, TUSB_PULLUP_2_CTRL, 0x01FFFFFF);
+
+       /* Turn GPIO[5:0] to DMAREQ[5:0] signals */
+       musb_writel(base, TUSB_GPIO_CONF, TUSB_GPIO_CONF_DMAREQ(0x3f));
+
+       /* Burst size 16x16 bits, all six DMA requests enabled, DMA request
+        * de-assertion time 2 system clocks p 62 */
+       musb_writel(base, TUSB_DMA_REQ_CONF,
+               TUSB_DMA_REQ_CONF_BURST_SIZE(2) |
+               TUSB_DMA_REQ_CONF_DMA_REQ_EN(0x3f) |
+               TUSB_DMA_REQ_CONF_DMA_REQ_ASSER(2));
+
+       /* Set 0 wait count for synchronous burst access */
+       musb_writel(base, TUSB_WAIT_COUNT, 1);
+}
+
+#define TUSB_REV_MAJOR(reg_val)                ((reg_val >> 4) & 0xf)
+#define TUSB_REV_MINOR(reg_val)                (reg_val & 0xf)
+
+static int __init tusb_print_revision(struct musb *musb)
+{
+       void __iomem    *base = musb->ctrl_base;
+
+       pr_info("tusb: Revisions: %s%i.%i %s%i.%i %s%i.%i %s%i.%i\n",
+               "prcm",
+               TUSB_REV_MAJOR(musb_readl(base, TUSB_PRCM_REV)),
+               TUSB_REV_MINOR(musb_readl(base, TUSB_PRCM_REV)),
+               "int",
+               TUSB_REV_MAJOR(musb_readl(base, TUSB_INT_CTRL_REV)),
+               TUSB_REV_MINOR(musb_readl(base, TUSB_INT_CTRL_REV)),
+               "gpio",
+               TUSB_REV_MAJOR(musb_readl(base, TUSB_GPIO_REV)),
+               TUSB_REV_MINOR(musb_readl(base, TUSB_GPIO_REV)),
+               "dma",
+               TUSB_REV_MAJOR(musb_readl(base, TUSB_DMA_CTRL_REV)),
+               TUSB_REV_MINOR(musb_readl(base, TUSB_DMA_CTRL_REV)));
+
+       return TUSB_REV_MAJOR(musb_readl(base, TUSB_INT_CTRL_REV));
+}
+
+static int __init tusb_start(struct musb *musb)
+{
+       void __iomem    *base = musb->ctrl_base;
+       int             ret = 0;
+       unsigned long   flags;
+       u32             reg;
+
+       if (musb->board_set_power)
+               ret = musb->board_set_power(1);
+       if (ret != 0) {
+               printk(KERN_ERR "tusb: Cannot enable TUSB6010\n");
+               return ret;
+       }
+
+       spin_lock_irqsave(&musb->Lock, flags);
+
+       if (musb_readl(base, TUSB_PROD_TEST_RESET) !=
+               TUSB_PROD_TEST_RESET_VAL) {
+               printk(KERN_ERR "tusb: Unable to detect TUSB6010\n");
+               goto err;
+       }
+
+       ret = tusb_print_revision(musb);
+       if (ret < 2) {
+               printk(KERN_ERR "tusb: Unsupported TUSB6010 revision %i\n",
+                               ret);
+               goto err;
+       }
+
+       /* The uint bit for "USB non-PDR interrupt enable" has to be 1 when
+        * NOR FLASH interface is used */
+       musb_writel(base, TUSB_VLYNQ_CTRL, 8);
+
+       /* Select PHY free running 60MHz as a system clock */
+       tusb_set_clock_source(musb, 1);
+
+       /* VBus valid timer 1us, disable DFT/Debug and VLYNQ clocks for
+        * power saving, enable VBus detect and session end comparators,
+        * enable IDpullup, enable VBus charging */
+       musb_writel(base, TUSB_PRCM_MNGMT,
+               TUSB_PRCM_MNGMT_VBUS_VALID_TIMER(0xa) |
+               TUSB_PRCM_MNGMT_VBUS_VALID_FLT_EN |
+               TUSB_PRCM_MNGMT_OTG_SESS_END_EN |
+               TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN |
+               TUSB_PRCM_MNGMT_OTG_ID_PULLUP);
+       tusb_setup_cpu_interface(musb);
+
+       /* simplify:  always sense/pullup ID pins, as if in OTG mode */
+       reg = musb_readl(base, TUSB_PHY_OTG_CTRL);
+       reg |= TUSB_PHY_OTG_CTRL_WRPROTECT | TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP;
+       musb_writel(base, TUSB_PHY_OTG_CTRL, reg);
+
+       reg = musb_readl(base, TUSB_PHY_OTG_CTRL_ENABLE);
+       reg |= TUSB_PHY_OTG_CTRL_WRPROTECT | TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP;
+       musb_writel(base, TUSB_PHY_OTG_CTRL_ENABLE, reg);
+
+       spin_unlock_irqrestore(&musb->Lock, flags);
+
+       return 0;
+
+err:
+       spin_unlock_irqrestore(&musb->Lock, flags);
+
+       if (musb->board_set_power)
+               musb->board_set_power(0);
+
+       return -ENODEV;
+}
+
+int __init musb_platform_init(struct musb *musb)
+{
+       struct platform_device  *pdev;
+       struct resource         *mem;
+       int                     ret;
+
+       pdev = to_platform_device(musb->controller);
+
+       /* dma address for async dma */
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       musb->async = mem->start;
+
+       /* dma address for sync dma */
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!mem) {
+               pr_debug("no sync dma resource?\n");
+               return -ENODEV;
+       }
+       musb->sync = mem->start;
+
+       /* Offsets from base: VLYNQ at 0x000, MUSB regs at 0x400,
+        * FIFOs at 0x600, TUSB at 0x800
+        */
+       musb->pRegs += TUSB_BASE_OFFSET;
+
+       ret = tusb_start(musb);
+       if (ret) {
+               printk(KERN_ERR "Could not start tusb6010 (%d)\n",
+                               ret);
+               return -ENODEV;
+       }
+       musb->isr = tusb_interrupt;
+
+       if (is_host_enabled(musb))
+               musb->board_set_vbus = tusb_set_vbus;
+       if (is_peripheral_enabled(musb))
+               musb->xceiv.set_power = tusb_set_power;
+
+       setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
+
+       return ret;
+}
+
+int musb_platform_exit(struct musb *musb)
+{
+       del_timer_sync(&musb_idle_timer);
+
+       if (musb->board_set_power)
+               musb->board_set_power(0);
+
+       return 0;
+}
diff --git a/drivers/usb/musb/tusb6010.h b/drivers/usb/musb/tusb6010.h
new file mode 100644 (file)
index 0000000..df73a29
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+ * Definitions for TUSB6010 USB 2.0 OTG Dual Role controller
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Jarkko Nikula <jarkko.nikula@nokia.com>
+ * Tony Lindgren <tony@atomide.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 __TUSB6010_H__
+#define __TUSB6010_H__
+
+#ifdef CONFIG_USB_TUSB6010
+#define musb_in_tusb()                 1
+#else
+#define musb_in_tusb()                 0
+#endif
+
+#ifdef CONFIG_USB_TUSB_OMAP_DMA
+#define tusb_dma_omap()                        1
+#else
+#define tusb_dma_omap()                        0
+#endif
+
+/* VLYNQ control register. 32-bit at offset 0x000 */
+#define TUSB_VLYNQ_CTRL                        0x004
+
+/* Mentor Graphics OTG core registers. 8,- 16- and 32-bit at offset 0x400 */
+#define TUSB_BASE_OFFSET               0x400
+
+/* FIFO registers 32-bit at offset 0x600 */
+#define TUSB_FIFO_BASE                 0x600
+
+/* Device System & Control registers. 32-bit at offset 0x800 */
+#define TUSB_SYS_REG_BASE              0x800
+
+#define TUSB_DEV_CONF                  (TUSB_SYS_REG_BASE + 0x000)
+#define                TUSB_DEV_CONF_USB_HOST_MODE             (1 << 16)
+#define                TUSB_DEV_CONF_PROD_TEST_MODE            (1 << 15)
+#define                TUSB_DEV_CONF_SOFT_ID                   (1 << 1)
+#define                TUSB_DEV_CONF_ID_SEL                    (1 << 0)
+
+#define TUSB_PHY_OTG_CTRL_ENABLE       (TUSB_SYS_REG_BASE + 0x004)
+#define TUSB_PHY_OTG_CTRL              (TUSB_SYS_REG_BASE + 0x008)
+#define                TUSB_PHY_OTG_CTRL_WRPROTECT             (0xa5 << 24)
+#define                TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP         (1 << 23)
+#define                TUSB_PHY_OTG_CTRL_OTG_VBUS_DET_EN       (1 << 19)
+#define                TUSB_PHY_OTG_CTRL_OTG_SESS_END_EN       (1 << 18)
+#define                TUSB_PHY_OTG_CTRL_TESTM2                (1 << 17)
+#define                TUSB_PHY_OTG_CTRL_TESTM1                (1 << 16)
+#define                TUSB_PHY_OTG_CTRL_TESTM0                (1 << 15)
+#define                TUSB_PHY_OTG_CTRL_TX_DATA2              (1 << 14)
+#define                TUSB_PHY_OTG_CTRL_TX_GZ2                (1 << 13)
+#define                TUSB_PHY_OTG_CTRL_TX_ENABLE2            (1 << 12)
+#define                TUSB_PHY_OTG_CTRL_DM_PULLDOWN           (1 << 11)
+#define                TUSB_PHY_OTG_CTRL_DP_PULLDOWN           (1 << 10)
+#define                TUSB_PHY_OTG_CTRL_OSC_EN                (1 << 9)
+#define                TUSB_PHY_OTG_CTRL_PHYREF_CLKSEL(v)      (((v) & 3) << 7)
+#define                TUSB_PHY_OTG_CTRL_PD                    (1 << 6)
+#define                TUSB_PHY_OTG_CTRL_PLL_ON                (1 << 5)
+#define                TUSB_PHY_OTG_CTRL_EXT_RPU               (1 << 4)
+#define                TUSB_PHY_OTG_CTRL_PWR_GOOD              (1 << 3)
+#define                TUSB_PHY_OTG_CTRL_RESET                 (1 << 2)
+#define                TUSB_PHY_OTG_CTRL_SUSPENDM              (1 << 1)
+#define                TUSB_PHY_OTG_CTRL_CLK_MODE              (1 << 0)
+
+/*OTG status register */
+#define TUSB_DEV_OTG_STAT              (TUSB_SYS_REG_BASE + 0x00c)
+#define                TUSB_DEV_OTG_STAT_PWR_CLK_GOOD          (1 << 8)
+#define                TUSB_DEV_OTG_STAT_SESS_END              (1 << 7)
+#define                TUSB_DEV_OTG_STAT_SESS_VALID            (1 << 6)
+#define                TUSB_DEV_OTG_STAT_VBUS_VALID            (1 << 5)
+#define                TUSB_DEV_OTG_STAT_VBUS_SENSE            (1 << 4)
+#define                TUSB_DEV_OTG_STAT_ID_STATUS             (1 << 3)
+#define                TUSB_DEV_OTG_STAT_HOST_DISCON           (1 << 2)
+#define                TUSB_DEV_OTG_STAT_LINE_STATE            (3 << 0)
+#define                TUSB_DEV_OTG_STAT_DP_ENABLE             (1 << 1)
+#define                TUSB_DEV_OTG_STAT_DM_ENABLE             (1 << 0)
+
+#define TUSB_DEV_OTG_TIMER             (TUSB_SYS_REG_BASE + 0x010)
+#      define TUSB_DEV_OTG_TIMER_ENABLE                (1 << 31)
+#      define TUSB_DEV_OTG_TIMER_VAL(v)                ((v) & 0x07ffffff)
+#define TUSB_PRCM_REV                  (TUSB_SYS_REG_BASE + 0x014)
+
+/* PRCM configuration register */
+#define TUSB_PRCM_CONF                 (TUSB_SYS_REG_BASE + 0x018)
+#define                TUSB_PRCM_CONF_SFW_CPEN         (1 << 24)
+#define                TUSB_PRCM_CONF_SYS_CLKSEL(v)    (((v) & 3) << 16)
+
+/* PRCM management register */
+#define TUSB_PRCM_MNGMT                        (TUSB_SYS_REG_BASE + 0x01c)
+#define                TUSB_PRCM_MNGMT_SRP_FIX_TIMER(v)        (((v) & 0xf) << 25)
+#define                TUSB_PRCM_MNGMT_SRP_FIX_EN              (1 << 24)
+#define                TUSB_PRCM_MNGMT_VBUS_VALID_TIMER(v)     (((v) & 0xf) << 20)
+#define                TUSB_PRCM_MNGMT_VBUS_VALID_FLT_EN       (1 << 19)
+#define                TUSB_PRCM_MNGMT_DFT_CLK_DIS             (1 << 18)
+#define                TUSB_PRCM_MNGMT_VLYNQ_CLK_DIS           (1 << 17)
+#define                TUSB_PRCM_MNGMT_OTG_SESS_END_EN         (1 << 10)
+#define                TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN         (1 << 9)
+#define                TUSB_PRCM_MNGMT_OTG_ID_PULLUP           (1 << 8)
+#define                TUSB_PRCM_MNGMT_15_SW_EN                (1 << 4)
+#define                TUSB_PRCM_MNGMT_33_SW_EN                (1 << 3)
+#define                TUSB_PRCM_MNGMT_5V_CPEN                 (1 << 2)
+#define                TUSB_PRCM_MNGMT_PM_IDLE                 (1 << 1)
+#define                TUSB_PRCM_MNGMT_DEV_IDLE                (1 << 0)
+
+/* Wake-up source clear and mask registers */
+#define TUSB_PRCM_WAKEUP_SOURCE                (TUSB_SYS_REG_BASE + 0x020)
+#define TUSB_PRCM_WAKEUP_CLEAR         (TUSB_SYS_REG_BASE + 0x028)
+#define TUSB_PRCM_WAKEUP_MASK          (TUSB_SYS_REG_BASE + 0x02c)
+#define                TUSB_PRCM_WAKEUP_RESERVED_BITS  (0xffffe << 13)
+#define                TUSB_PRCM_WGPIO_7       (1 << 12)
+#define                TUSB_PRCM_WGPIO_6       (1 << 11)
+#define                TUSB_PRCM_WGPIO_5       (1 << 10)
+#define                TUSB_PRCM_WGPIO_4       (1 << 9)
+#define                TUSB_PRCM_WGPIO_3       (1 << 8)
+#define                TUSB_PRCM_WGPIO_2       (1 << 7)
+#define                TUSB_PRCM_WGPIO_1       (1 << 6)
+#define                TUSB_PRCM_WGPIO_0       (1 << 5)
+#define                TUSB_PRCM_WHOSTDISCON   (1 << 4)        /* Host disconnect */
+#define                TUSB_PRCM_WBUS          (1 << 3)        /* USB bus resume */
+#define                TUSB_PRCM_WNORCS        (1 << 2)        /* NOR chip select */
+#define                TUSB_PRCM_WVBUS         (1 << 1)        /* OTG PHY VBUS */
+#define                TUSB_PRCM_WID           (1 << 0)        /* OTG PHY ID detect */
+
+#define TUSB_PULLUP_1_CTRL             (TUSB_SYS_REG_BASE + 0x030)
+#define TUSB_PULLUP_2_CTRL             (TUSB_SYS_REG_BASE + 0x034)
+#define TUSB_INT_CTRL_REV              (TUSB_SYS_REG_BASE + 0x038)
+#define TUSB_INT_CTRL_CONF             (TUSB_SYS_REG_BASE + 0x03c)
+#define TUSB_USBIP_INT_SRC             (TUSB_SYS_REG_BASE + 0x040)
+#define TUSB_USBIP_INT_SET             (TUSB_SYS_REG_BASE + 0x044)
+#define TUSB_USBIP_INT_CLEAR           (TUSB_SYS_REG_BASE + 0x048)
+#define TUSB_USBIP_INT_MASK            (TUSB_SYS_REG_BASE + 0x04c)
+#define TUSB_DMA_INT_SRC               (TUSB_SYS_REG_BASE + 0x050)
+#define TUSB_DMA_INT_SET               (TUSB_SYS_REG_BASE + 0x054)
+#define TUSB_DMA_INT_CLEAR             (TUSB_SYS_REG_BASE + 0x058)
+#define TUSB_DMA_INT_MASK              (TUSB_SYS_REG_BASE + 0x05c)
+#define TUSB_GPIO_INT_SRC              (TUSB_SYS_REG_BASE + 0x060)
+#define TUSB_GPIO_INT_SET              (TUSB_SYS_REG_BASE + 0x064)
+#define TUSB_GPIO_INT_CLEAR            (TUSB_SYS_REG_BASE + 0x068)
+#define TUSB_GPIO_INT_MASK             (TUSB_SYS_REG_BASE + 0x06c)
+
+/* NOR flash interrupt source registers */
+#define TUSB_INT_SRC                   (TUSB_SYS_REG_BASE + 0x070)
+#define TUSB_INT_SRC_SET               (TUSB_SYS_REG_BASE + 0x074)
+#define TUSB_INT_SRC_CLEAR             (TUSB_SYS_REG_BASE + 0x078)
+#define TUSB_INT_MASK                  (TUSB_SYS_REG_BASE + 0x07c)
+#define                TUSB_INT_SRC_TXRX_DMA_DONE              (1 << 24)
+#define                TUSB_INT_SRC_USB_IP_CORE                (1 << 17)
+#define                TUSB_INT_SRC_OTG_TIMEOUT                (1 << 16)
+#define                TUSB_INT_SRC_VBUS_SENSE_CHNG            (1 << 15)
+#define                TUSB_INT_SRC_ID_STATUS_CHNG             (1 << 14)
+#define                TUSB_INT_SRC_DEV_WAKEUP                 (1 << 13)
+#define                TUSB_INT_SRC_DEV_READY                  (1 << 12)
+#define                TUSB_INT_SRC_USB_IP_TX                  (1 << 9)
+#define                TUSB_INT_SRC_USB_IP_RX                  (1 << 8)
+#define                TUSB_INT_SRC_USB_IP_VBUS_ERR            (1 << 7)
+#define                TUSB_INT_SRC_USB_IP_VBUS_REQ            (1 << 6)
+#define                TUSB_INT_SRC_USB_IP_DISCON              (1 << 5)
+#define                TUSB_INT_SRC_USB_IP_CONN                (1 << 4)
+#define                TUSB_INT_SRC_USB_IP_SOF                 (1 << 3)
+#define                TUSB_INT_SRC_USB_IP_RST_BABBLE          (1 << 2)
+#define                TUSB_INT_SRC_USB_IP_RESUME              (1 << 1)
+#define                TUSB_INT_SRC_USB_IP_SUSPEND             (1 << 0)
+
+/* NOR flash interrupt registers reserved bits. Must be written as 0 */
+#define                TUSB_INT_MASK_RESERVED_17               (0x3fff << 17)
+#define                TUSB_INT_MASK_RESERVED_13               (1 << 13)
+#define                TUSB_INT_MASK_RESERVED_8                (0xf << 8)
+#define                TUSB_INT_SRC_RESERVED_26                (0x1f << 26)
+#define                TUSB_INT_SRC_RESERVED_18                (0x3f << 18)
+#define                TUSB_INT_SRC_RESERVED_10                (0x03 << 10)
+
+/* Reserved bits for NOR flash interrupt mask and clear register */
+#define                TUSB_INT_MASK_RESERVED_BITS     (TUSB_INT_MASK_RESERVED_17 | \
+                                               TUSB_INT_MASK_RESERVED_13 | \
+                                               TUSB_INT_MASK_RESERVED_8)
+
+/* Reserved bits for NOR flash interrupt status register */
+#define                TUSB_INT_SRC_RESERVED_BITS      (TUSB_INT_SRC_RESERVED_26 | \
+                                               TUSB_INT_SRC_RESERVED_18 | \
+                                               TUSB_INT_SRC_RESERVED_10)
+
+#define TUSB_GPIO_REV                  (TUSB_SYS_REG_BASE + 0x080)
+#define TUSB_GPIO_CONF                 (TUSB_SYS_REG_BASE + 0x084)
+#define TUSB_DMA_CTRL_REV              (TUSB_SYS_REG_BASE + 0x100)
+#define TUSB_DMA_REQ_CONF              (TUSB_SYS_REG_BASE + 0x104)
+#define TUSB_EP0_CONF                  (TUSB_SYS_REG_BASE + 0x108)
+#define TUSB_DMA_EP_MAP                        (TUSB_SYS_REG_BASE + 0x148)
+
+/* Offsets from each ep base register */
+#define TUSB_EP_TX_OFFSET              0x10c   /* EP_IN in docs */
+#define TUSB_EP_RX_OFFSET              0x14c   /* EP_OUT in docs */
+#define TUSB_EP_MAX_PACKET_SIZE_OFFSET 0x188
+
+#define TUSB_WAIT_COUNT                        (TUSB_SYS_REG_BASE + 0x1c8)
+#define TUSB_SCRATCH_PAD               (TUSB_SYS_REG_BASE + 0x1c4)
+#define TUSB_PROD_TEST_RESET           (TUSB_SYS_REG_BASE + 0x1d8)
+
+/* Device System & Control register bitfields */
+#define TUSB_INT_CTRL_CONF_INT_RELCYC(v)       (((v) & 0x7) << 18)
+#define TUSB_INT_CTRL_CONF_INT_POLARITY                (1 << 17)
+#define TUSB_INT_CTRL_CONF_INT_MODE            (1 << 16)
+#define TUSB_GPIO_CONF_DMAREQ(v)               (((v) & 0x3f) << 24)
+#define TUSB_DMA_REQ_CONF_BURST_SIZE(v)                (((v) & 3) << 26)
+#define TUSB_DMA_REQ_CONF_DMA_REQ_EN(v)                (((v) & 0x3f) << 20)
+#define TUSB_DMA_REQ_CONF_DMA_REQ_ASSER(v)     (((v) & 0xf) << 16)
+#define TUSB_EP0_CONFIG_SW_EN                  (1 << 8)
+#define TUSB_EP0_CONFIG_DIR_TX                 (1 << 7)
+#define TUSB_EP0_CONFIG_XFR_SIZE(v)            ((v) & 0x7f)
+#define TUSB_EP_CONFIG_SW_EN                   (1 << 31)
+#define TUSB_EP_CONFIG_XFR_SIZE(v)             ((v) & 0x7fffffff)
+#define TUSB_PROD_TEST_RESET_VAL               0xa596
+#define TUSB_EP_FIFO(ep)                       (TUSB_FIFO_BASE + (ep) * 0x20)
+
+/*----------------------------------------------------------------------------*/
+
+#ifdef CONFIG_USB_TUSB6010
+
+/* configuration parameters specific to this silicon */
+
+/* Number of Tx endpoints. Legal values are 1 - 16 (this value includes EP0) */
+#define MUSB_C_NUM_EPT 16
+
+/* Number of Rx endpoints. Legal values are 1 - 16 (this value includes EP0) */
+#define MUSB_C_NUM_EPR 16
+
+/* Endpoint 1 to 15 direction types. C_EP1_DEF is defined if either Tx endpoint
+ * 1 or Rx endpoint 1 are used.
+ */
+#define MUSB_C_EP1_DEF
+
+/* C_EP1_TX_DEF is defined if Tx endpoint 1 is used */
+#define MUSB_C_EP1_TX_DEF
+
+/* C_EP1_RX_DEF is defined if Rx endpoint 1 is used */
+#define MUSB_C_EP1_RX_DEF
+
+/* C_EP1_TOR_DEF is defined if Tx endpoint 1 and Rx endpoint 1 share a FIFO */
+/* #define C_EP1_TOR_DEF */
+
+/* C_EP1_TAR_DEF is defined if both Tx endpoint 1 and Rx endpoint 1 are used
+ * and do not share a FIFO.
+ */
+#define MUSB_C_EP1_TAR_DEF
+
+/* Similarly for all other used endpoints */
+#define MUSB_C_EP2_DEF
+#define MUSB_C_EP2_TX_DEF
+#define MUSB_C_EP2_RX_DEF
+#define MUSB_C_EP2_TAR_DEF
+#define MUSB_C_EP3_DEF
+#define MUSB_C_EP3_TX_DEF
+#define MUSB_C_EP3_RX_DEF
+#define MUSB_C_EP3_TAR_DEF
+#define MUSB_C_EP4_DEF
+#define MUSB_C_EP4_TX_DEF
+#define MUSB_C_EP4_RX_DEF
+#define MUSB_C_EP4_TAR_DEF
+
+/* Endpoint 1 to 15 FIFO address bits. Legal values are 3 to 13 - corresponding
+ * to FIFO sizes of 8 to 8192 bytes. If an Tx endpoint shares a FIFO with an Rx
+ * endpoint then the Rx FIFO size must be the same as the Tx FIFO size. All
+ * endpoints 1 to 15 must be defined, unused endpoints should be set to 2.
+ */
+#define MUSB_C_EP1T_BITS 5
+#define MUSB_C_EP1R_BITS 5
+#define MUSB_C_EP2T_BITS 5
+#define MUSB_C_EP2R_BITS 5
+#define MUSB_C_EP3T_BITS 3
+#define MUSB_C_EP3R_BITS 3
+#define MUSB_C_EP4T_BITS 3
+#define MUSB_C_EP4R_BITS 3
+
+#define MUSB_C_EP5T_BITS 2
+#define MUSB_C_EP5R_BITS 2
+#define MUSB_C_EP6T_BITS 2
+#define MUSB_C_EP6R_BITS 2
+#define MUSB_C_EP7T_BITS 2
+#define MUSB_C_EP7R_BITS 2
+#define MUSB_C_EP8T_BITS 2
+#define MUSB_C_EP8R_BITS 2
+#define MUSB_C_EP9T_BITS 2
+#define MUSB_C_EP9R_BITS 2
+#define MUSB_C_EP10T_BITS 2
+#define MUSB_C_EP10R_BITS 2
+#define MUSB_C_EP11T_BITS 2
+#define MUSB_C_EP11R_BITS 2
+#define MUSB_C_EP12T_BITS 2
+#define MUSB_C_EP12R_BITS 2
+#define MUSB_C_EP13T_BITS 2
+#define MUSB_C_EP13R_BITS 2
+#define MUSB_C_EP14T_BITS 2
+#define MUSB_C_EP14R_BITS 2
+#define MUSB_C_EP15T_BITS 2
+#define MUSB_C_EP15R_BITS 2
+
+/* Define the following constant if the USB2.0 Transceiver Macrocell data width
+ * is 16-bits.
+ */
+/* #define C_UTM_16 */
+
+/* Define this constant if the CPU uses big-endian byte ordering. */
+/* #define C_BIGEND */
+
+/* Define the following constant if any Tx endpoint is required to support
+ * multiple bulk packets.
+ */
+/* #define C_MP_TX */
+
+/* Define the following constant if any Rx endpoint is required to support
+ * multiple bulk packets.
+ */
+/* #define C_MP_RX */
+
+/* Define the following constant if any Tx endpoint is required to support high
+ * bandwidth ISO.
+ */
+/* #define C_HB_TX */
+
+/* Define the following constant if any Rx endpoint is required to support high
+ * bandwidth ISO.
+ */
+/* #define C_HB_RX */
+
+/* Define the following constant if software connect/disconnect control is
+ * required.
+ */
+#define MUSB_C_SOFT_CON
+
+/* Define the following constant if Vendor Control Registers are required. */
+/* #define C_VEND_REG */
+
+/* Vendor control register widths. */
+#define MUSB_C_VCTL_BITS 4
+#define MUSB_C_VSTAT_BITS 8
+
+/* Define the following constant to include a DMA controller. */
+/* #define C_DMA */
+
+/* Define the following constant if 2 or more DMA channels are required. */
+/* #define C_DMA2 */
+
+/* Define the following constant if 3 or more DMA channels are required. */
+/* #define C_DMA3 */
+
+/* Define the following constant if 4 or more DMA channels are required. */
+/* #define C_DMA4 */
+
+/* Define the following constant if 5 or more DMA channels are required. */
+/* #define C_DMA5 */
+
+/* Define the following constant if 6 or more DMA channels are required. */
+/* #define C_DMA6 */
+
+/* Define the following constant if 7 or more DMA channels are required. */
+/* #define C_DMA7 */
+
+/* Define the following constant if 8 or more DMA channels are required. */
+/* #define C_DMA8 */
+
+/* Enable Dynamic FIFO Sizing */
+#define MUSB_C_DYNFIFO_DEF
+
+/* Derived constants. The following constants are derived from the previous
+ * configuration constants
+ */
+
+/* Total number of endpoints. Legal values are 2 - 16. This must be equal to
+ * the larger of C_NUM_EPT, C_NUM_EPR
+ */
+/* #define MUSB_C_NUM_EPS 5 */
+
+/* C_EPMAX_BITS is equal to the largest endpoint FIFO word address bits */
+#define MUSB_C_EPMAX_BITS 11
+
+/* C_RAM_BITS is the number of address bits required to address the RAM (32-bit
+ * addresses).  It is defined as log2 of the sum of 2** of all the endpoint FIFO
+ * dword address bits (rounded up).
+ */
+#define MUSB_C_RAM_BITS 12
+
+#endif /* CONFIG_USB_TUSB6010 */
+
+#endif /* __TUSB6010_H__ */
diff --git a/drivers/usb/musb/tusb6010_omap.c b/drivers/usb/musb/tusb6010_omap.c
new file mode 100644 (file)
index 0000000..07f9efe
--- /dev/null
@@ -0,0 +1,684 @@
+/*
+ * TUSB6010 USB 2.0 OTG Dual Role controller OMAP DMA interface
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Tony Lindgren <tony@atomide.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/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/mux.h>
+
+#include "musbdefs.h"
+
+/*
+ * REVISIT: With TUSB2.0 only one dmareq line can be used at a time.
+ * This should get fixed in hardware at some point.
+ */
+#define BROKEN_DMAREQ
+
+#ifdef BROKEN_DMAREQ
+#define dmareq_works()         0
+#else
+#define dmareq_works()         1
+#endif
+
+#define to_chdat(c)            (struct tusb_omap_dma_ch *)(c)->pPrivateData
+
+#define MAX_DMAREQ             5       /* REVISIT: Really 6, but req5 not OK */
+
+struct tusb_omap_dma_ch {
+       struct musb             *musb;
+       void __iomem            *tusb_base;
+       unsigned long           phys_offset;
+       int                     epnum;
+       u8                      tx;
+       struct musb_hw_ep       *hw_ep;
+
+       int                     ch;
+       s8                      dmareq;
+       s8                      sync_dev;
+
+       struct tusb_omap_dma    *tusb_dma;
+
+       void __iomem            *dma_addr;
+
+       u32                     len;
+       u16                     packet_sz;
+       u16                     transfer_packet_sz;
+       u32                     transfer_len;
+       u32                     completed_len;
+};
+
+struct tusb_omap_dma {
+       struct dma_controller           controller;
+       struct musb                     *musb;
+       void __iomem                    *tusb_base;
+
+       int                             ch;
+       s8                              dmareq;
+       s8                              sync_dev;
+};
+
+static int tusb_omap_dma_start(struct dma_controller *c)
+{
+       struct tusb_omap_dma    *tusb_dma;
+
+       tusb_dma = container_of(c, struct tusb_omap_dma, controller);
+
+       // DBG(3, "ep%i ch: %i\n", chdat->epnum, chdat->ch);
+
+       return 0;
+}
+
+static int tusb_omap_dma_stop(struct dma_controller *c)
+{
+       struct tusb_omap_dma    *tusb_dma;
+
+       tusb_dma = container_of(c, struct tusb_omap_dma, controller);
+
+       // DBG(3, "ep%i ch: %i\n", chdat->epnum, chdat->ch);
+
+       return 0;
+}
+
+#ifdef BROKEN_DMAREQ
+
+/*
+ * Allocate dmareq0 to the current channel unless it's already taken
+ */
+static inline int tusb_omap_use_shared_dmareq(struct tusb_omap_dma_ch *chdat)
+{
+       u32             reg = musb_readl(chdat->tusb_base, TUSB_DMA_EP_MAP);
+
+       if (reg != 0) {
+               DBG(3, "ep%i dmareq0 is busy for ep%i\n",
+                       chdat->epnum, reg & 0xf);
+               return -EAGAIN;
+       }
+
+       if (chdat->tx)
+               reg = (1 << 4) | chdat->epnum;
+       else
+               reg = chdat->epnum;
+
+       musb_writel(chdat->tusb_base, TUSB_DMA_EP_MAP, reg);
+
+       return 0;
+}
+
+static inline void tusb_omap_free_shared_dmareq(struct tusb_omap_dma_ch *chdat)
+{
+       u32             reg = musb_readl(chdat->tusb_base, TUSB_DMA_EP_MAP);
+
+       if ((reg & 0xf) != chdat->epnum) {
+               printk(KERN_ERR "ep%i trying to release dmareq0 for ep%i\n",
+                       chdat->epnum, reg & 0xf);
+               return;
+       }
+       musb_writel(chdat->tusb_base, TUSB_DMA_EP_MAP, 0);
+}
+
+#else
+#define tusb_omap_use_shared_dmareq(x, y)      do {} while (0)
+#define tusb_omap_free_shared_dmareq(x, y)     do {} while (0)
+#endif
+
+/*
+ * See also musb_dma_completion in plat_uds.c and musb_g_[tx|rx]() in
+ * musb_gadget.c.
+ */
+static void tusb_omap_dma_cb(int lch, u16 ch_status, void *data)
+{
+       struct dma_channel      *channel = (struct dma_channel *)data;
+       struct tusb_omap_dma_ch *chdat = to_chdat(channel);
+       struct tusb_omap_dma    *tusb_dma = chdat->tusb_dma;
+       struct musb             *musb = chdat->musb;
+       struct musb_hw_ep       *hw_ep = chdat->hw_ep;
+       void __iomem            *ep_conf = hw_ep->conf;
+       void __iomem            *musb_base = musb->pRegs;
+       unsigned long           remaining, flags;
+       int                     ch;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+
+       if (dmareq_works())
+               ch = chdat->ch;
+       else
+               ch = tusb_dma->ch;
+
+       if (ch_status != OMAP_DMA_BLOCK_IRQ)
+               printk(KERN_ERR "TUSB DMA error status: %i\n", ch_status);
+
+       DBG(2, "ep%i %s dma callback ch: %i status: %x\n",
+               chdat->epnum, chdat->tx ? "tx" : "rx",
+               ch, ch_status);
+
+       if (chdat->tx)
+               remaining = musb_readl(ep_conf, TUSB_EP_TX_OFFSET);
+       else
+               remaining = musb_readl(ep_conf, TUSB_EP_RX_OFFSET);
+
+       remaining = TUSB_EP_CONFIG_XFR_SIZE(remaining);
+       channel->dwActualLength = chdat->transfer_len - remaining;
+
+       DBG(2, "remaining %lu/%u\n", remaining, chdat->transfer_len);
+
+       if (!dmareq_works())
+               tusb_omap_free_shared_dmareq(chdat);
+
+       channel->bStatus = MGC_DMA_STATUS_FREE;
+
+       /* Handle only RX callbacks here. TX callbacks musb be handled based
+        * on the TUSB DMA status interrupt.
+        * REVISIT: Use both TUSB DMA status interrupt and OMAP DMA callback
+        * interrupt for RX and TX.
+        */
+       if (!chdat->tx)
+               musb_dma_completion(musb, chdat->epnum, chdat->tx);
+
+       /* We musb terminate short tx transfers manually by setting TXPKTRDY.
+        * REVISIT: This same problem may occur with other MUSB dma as well.
+        * Easy to test with g_ether by pinging the MUSB board with ping -s54.
+        */
+       if ((chdat->transfer_len < chdat->packet_sz)
+                       || (chdat->transfer_len % chdat->packet_sz != 0)) {
+               u16     csr;
+
+               if (chdat->tx) {
+                       DBG(2, "terminating short tx packet\n");
+                       MGC_SelectEnd(musb_base, chdat->epnum);
+                       csr = musb_readw(hw_ep->regs, MGC_O_HDRC_TXCSR);
+                       csr |= MGC_M_TXCSR_MODE | MGC_M_TXCSR_TXPKTRDY
+                               | MGC_M_TXCSR_P_WZC_BITS;
+                       musb_writew(hw_ep->regs, MGC_O_HDRC_TXCSR, csr);
+               }
+       }
+
+       spin_unlock_irqrestore(&musb->Lock, flags);
+}
+
+static int tusb_omap_dma_program(struct dma_channel *channel, u16 packet_sz,
+                               u8 rndis_mode, dma_addr_t dma_addr, u32 len)
+{
+       struct tusb_omap_dma_ch         *chdat = to_chdat(channel);
+       struct tusb_omap_dma            *tusb_dma = chdat->tusb_dma;
+       struct musb                     *musb = chdat->musb;
+       struct musb_hw_ep               *hw_ep = chdat->hw_ep;
+       void __iomem                    *musb_base = musb->pRegs;
+       void __iomem                    *ep_conf = hw_ep->conf;
+       dma_addr_t                      fifo = hw_ep->fifo_sync;
+       struct omap_dma_channel_params  dma_params;
+       int                             src_burst, dst_burst;
+       u16                             csr;
+       int                             ch;
+       s8                              dmareq;
+       s8                              sync_dev;
+
+       if (unlikely(dma_addr & 0x1))
+               return FALSE;
+       if (len < 32)
+               return FALSE;
+       if ((len % 32 != 0))
+               return FALSE;
+       else
+               chdat->transfer_len = len;
+
+       if (len < packet_sz)
+               chdat->transfer_packet_sz = chdat->transfer_len;
+       else
+               chdat->transfer_packet_sz = packet_sz;
+
+       if (dmareq_works()) {
+               ch = chdat->ch;
+               dmareq = chdat->dmareq;
+               sync_dev = chdat->sync_dev;
+       } else {
+               if (tusb_omap_use_shared_dmareq(chdat) != 0) {
+                       DBG(3, "could not get dma for ep%i\n", chdat->epnum);
+                       return FALSE;
+               }
+               if (tusb_dma->ch < 0) {
+                       /* REVISIT: This should get blocked earlier, happens
+                        * with MSC ErrorRecoveryTest
+                        */
+                       WARN_ON(1);
+                       return FALSE;
+               }
+
+               ch = tusb_dma->ch;
+               dmareq = tusb_dma->dmareq;
+               sync_dev = tusb_dma->sync_dev;
+               omap_set_dma_callback(ch, tusb_omap_dma_cb, channel);
+       }
+
+       chdat->packet_sz = packet_sz;
+       chdat->len = len;
+       channel->dwActualLength = 0;
+       chdat->dma_addr = (void __iomem *)dma_addr;
+       channel->bStatus = MGC_DMA_STATUS_BUSY;
+
+       /* Since we're recycling dma areas, we need to clean or invalidate */
+       if (chdat->tx) {
+               consistent_sync(phys_to_virt(dma_addr), len, DMA_TO_DEVICE);
+       } else
+               consistent_sync(phys_to_virt(dma_addr), len, DMA_FROM_DEVICE);
+
+       /* Use 16-bit transfer if dma_addr is not 32-bit aligned */
+       if ((dma_addr & 0x3) == 0) {
+               dma_params.data_type = OMAP_DMA_DATA_TYPE_S32;
+               dma_params.elem_count = 8;              /* Elements in frame */
+       } else {
+               dma_params.data_type = OMAP_DMA_DATA_TYPE_S16;
+               dma_params.elem_count = 16;             /* Elements in frame */
+               fifo = hw_ep->fifo_async;
+       }
+
+       dma_params.frame_count  = chdat->transfer_len / 32; /* Burst sz frame */
+
+       DBG(2, "ep%i %s dma ch%i dma: %08x len: %u(%u) packet_sz: %i(%i)\n",
+               chdat->epnum, chdat->tx ? "tx" : "rx",
+               ch, dma_addr, chdat->transfer_len, len,
+               chdat->transfer_packet_sz, packet_sz);
+
+       /*
+        * Prepare omap DMA for transfer
+        */
+       if (chdat->tx) {
+               dma_params.src_amode    = OMAP_DMA_AMODE_POST_INC;
+               dma_params.src_start    = (unsigned long)dma_addr;
+               dma_params.src_ei       = 0;
+               dma_params.src_fi       = 0;
+
+               dma_params.dst_amode    = OMAP_DMA_AMODE_DOUBLE_IDX;
+               dma_params.dst_start    = (unsigned long)fifo;
+               dma_params.dst_ei       = 1;
+               dma_params.dst_fi       = -31;          /* Loop 32 byte window */
+
+               dma_params.trigger      = sync_dev;
+               dma_params.sync_mode    = OMAP_DMA_SYNC_FRAME;
+               dma_params.src_or_dst_synch     = 0;    /* Dest sync */
+
+               src_burst = OMAP_DMA_DATA_BURST_16;     /* 16x32 read */
+               dst_burst = OMAP_DMA_DATA_BURST_8;      /* 8x32 write */
+       } else {
+               dma_params.src_amode    = OMAP_DMA_AMODE_DOUBLE_IDX;
+               dma_params.src_start    = (unsigned long)fifo;
+               dma_params.src_ei       = 1;
+               dma_params.src_fi       = -31;          /* Loop 32 byte window */
+
+               dma_params.dst_amode    = OMAP_DMA_AMODE_POST_INC;
+               dma_params.dst_start    = (unsigned long)dma_addr;
+               dma_params.dst_ei       = 0;
+               dma_params.dst_fi       = 0;
+
+               dma_params.trigger      = sync_dev;
+               dma_params.sync_mode    = OMAP_DMA_SYNC_FRAME;
+               dma_params.src_or_dst_synch     = 1;    /* Source sync */
+
+               src_burst = OMAP_DMA_DATA_BURST_8;      /* 8x32 read */
+               dst_burst = OMAP_DMA_DATA_BURST_16;     /* 16x32 write */
+       }
+
+       DBG(2, "ep%i %s using %i-bit %s dma from 0x%08lx to 0x%08lx\n",
+               chdat->epnum, chdat->tx ? "tx" : "rx",
+               (dma_params.data_type == OMAP_DMA_DATA_TYPE_S32) ? 32 : 16,
+               ((dma_addr & 0x3) == 0) ? "sync" : "async",
+               dma_params.src_start, dma_params.dst_start);
+
+       omap_set_dma_params(ch, &dma_params);
+       omap_set_dma_src_burst_mode(ch, src_burst);
+       omap_set_dma_dest_burst_mode(ch, dst_burst);
+       omap_set_dma_write_mode(ch, OMAP_DMA_WRITE_LAST_NON_POSTED);
+
+       /*
+        * Prepare MUSB for DMA transfer
+        */
+       if (chdat->tx) {
+               MGC_SelectEnd(musb_base, chdat->epnum);
+               csr = musb_readw(hw_ep->regs, MGC_O_HDRC_TXCSR);
+               csr |= (MGC_M_TXCSR_AUTOSET | MGC_M_TXCSR_DMAENAB
+                       | MGC_M_TXCSR_DMAMODE | MGC_M_TXCSR_MODE);
+               csr &= ~MGC_M_TXCSR_P_UNDERRUN;
+               musb_writew(hw_ep->regs, MGC_O_HDRC_TXCSR, csr);
+       } else {
+               MGC_SelectEnd(musb_base, chdat->epnum);
+               csr = musb_readw(hw_ep->regs, MGC_O_HDRC_RXCSR);
+               csr |= MGC_M_RXCSR_DMAENAB;
+               csr &= ~(MGC_M_RXCSR_AUTOCLEAR | MGC_M_RXCSR_DMAMODE);
+               musb_writew(hw_ep->regs, MGC_O_HDRC_RXCSR,
+                       csr | MGC_M_RXCSR_P_WZC_BITS);
+       }
+
+       /*
+        * Start DMA transfer
+        */
+       omap_start_dma(ch);
+
+       if (chdat->tx) {
+               /* Send transfer_packet_sz packets at a time */
+               musb_writel(ep_conf, TUSB_EP_MAX_PACKET_SIZE_OFFSET,
+                       chdat->transfer_packet_sz);
+
+               musb_writel(ep_conf, TUSB_EP_TX_OFFSET,
+                       TUSB_EP_CONFIG_XFR_SIZE(chdat->transfer_len));
+       } else {
+               /* Receive transfer_packet_sz packets at a time */
+               musb_writel(ep_conf, TUSB_EP_MAX_PACKET_SIZE_OFFSET,
+                       chdat->transfer_packet_sz << 16);
+
+               musb_writel(ep_conf, TUSB_EP_RX_OFFSET,
+                       TUSB_EP_CONFIG_XFR_SIZE(chdat->transfer_len));
+       }
+
+       return TRUE;
+}
+
+static int tusb_omap_dma_abort(struct dma_channel *channel)
+{
+       struct tusb_omap_dma_ch *chdat = to_chdat(channel);
+       struct tusb_omap_dma    *tusb_dma = chdat->tusb_dma;
+
+       if (!dmareq_works()) {
+               if (tusb_dma->ch >= 0) {
+                       omap_stop_dma(tusb_dma->ch);
+                       omap_free_dma(tusb_dma->ch);
+                       tusb_dma->ch = -1;
+               }
+
+               tusb_dma->dmareq = -1;
+               tusb_dma->sync_dev = -1;
+       }
+
+       channel->bStatus = MGC_DMA_STATUS_FREE;
+
+       return 0;
+}
+
+static inline int tusb_omap_dma_allocate_dmareq(struct tusb_omap_dma_ch *chdat)
+{
+       u32             reg = musb_readl(chdat->tusb_base, TUSB_DMA_EP_MAP);
+       int             i, dmareq_nr = -1;
+
+       const int sync_dev[6] = {
+               OMAP24XX_DMA_EXT_DMAREQ0,
+               OMAP24XX_DMA_EXT_DMAREQ1,
+               OMAP24XX_DMA_EXT_DMAREQ2,
+               OMAP24XX_DMA_EXT_DMAREQ3,
+               OMAP24XX_DMA_EXT_DMAREQ4,
+               OMAP24XX_DMA_EXT_DMAREQ5,
+       };
+
+       for (i = 0; i < MAX_DMAREQ; i++) {
+               int cur = (reg & (0xf << (i * 5))) >> (i * 5);
+               if (cur == 0) {
+                       dmareq_nr = i;
+                       break;
+               }
+       }
+
+       if (dmareq_nr == -1)
+               return -EAGAIN;
+
+       reg |= (chdat->epnum << (dmareq_nr * 5));
+       if (chdat->tx)
+               reg |= ((1 << 4) << (dmareq_nr * 5));
+       musb_writel(chdat->tusb_base, TUSB_DMA_EP_MAP, reg);
+
+       chdat->dmareq = dmareq_nr;
+       chdat->sync_dev = sync_dev[chdat->dmareq];
+
+       return 0;
+}
+
+static inline void tusb_omap_dma_free_dmareq(struct tusb_omap_dma_ch *chdat)
+{
+       u32 reg;
+
+       if (!chdat || chdat->dmareq < 0)
+               return;
+
+       reg = musb_readl(chdat->tusb_base, TUSB_DMA_EP_MAP);
+       reg &= ~(0x1f << (chdat->dmareq * 5));
+       musb_writel(chdat->tusb_base, TUSB_DMA_EP_MAP, reg);
+
+       chdat->dmareq = -1;
+       chdat->sync_dev = -1;
+}
+
+static struct dma_channel *dma_channel_pool[MAX_DMAREQ];
+
+static struct dma_channel *
+tusb_omap_dma_allocate(struct dma_controller *c,
+               struct musb_hw_ep *hw_ep,
+               u8 tx)
+{
+       int ret, i;
+       const char              *dev_name;
+       struct tusb_omap_dma    *tusb_dma;
+       struct musb             *musb;
+       void __iomem            *tusb_base;
+       struct dma_channel      *channel = NULL;
+       struct tusb_omap_dma_ch *chdat = NULL;
+       u32                     reg;
+
+       tusb_dma = container_of(c, struct tusb_omap_dma, controller);
+       musb = tusb_dma->musb;
+       tusb_base = musb->ctrl_base;
+
+       reg = musb_readl(tusb_base, TUSB_DMA_INT_MASK);
+       if (tx)
+               reg &= ~(1 << hw_ep->bLocalEnd);
+       else
+               reg &= ~(1 << (hw_ep->bLocalEnd + 15));
+       musb_writel(tusb_base, TUSB_DMA_INT_MASK, reg);
+
+       /* REVISIT: Why does dmareq5 not work? */
+       if (hw_ep->bLocalEnd == 0) {
+               DBG(3, "Not allowing DMA for ep0 %s\n", tx ? "tx" : "rx");
+               return NULL;
+       }
+
+       for (i = 0; i < MAX_DMAREQ; i++) {
+               struct dma_channel *ch = dma_channel_pool[i];
+               if (ch->bStatus == MGC_DMA_STATUS_UNKNOWN) {
+                       ch->bStatus = MGC_DMA_STATUS_FREE;
+                       channel = ch;
+                       chdat = ch->pPrivateData;
+                       break;
+               }
+       }
+
+       if (!channel)
+               return NULL;
+
+       if (tx) {
+               chdat->tx = 1;
+               dev_name = "TUSB transmit";
+       } else {
+               chdat->tx = 0;
+               dev_name = "TUSB receive";
+       }
+
+       chdat->musb = tusb_dma->musb;
+       chdat->tusb_base = tusb_dma->tusb_base;
+       chdat->hw_ep = hw_ep;
+       chdat->epnum = hw_ep->bLocalEnd;
+       chdat->dmareq = -1;
+       chdat->completed_len = 0;
+       chdat->tusb_dma = tusb_dma;
+
+       channel->dwMaxLength = 0x7fffffff;
+       channel->bDesiredMode = 0;
+       channel->dwActualLength = 0;
+
+       if (dmareq_works()) {
+               ret = tusb_omap_dma_allocate_dmareq(chdat);
+               if (ret != 0)
+                       goto free_dmareq;
+
+               ret = omap_request_dma(chdat->sync_dev, dev_name,
+                               tusb_omap_dma_cb, channel, &chdat->ch);
+               if (ret != 0)
+                       goto free_dmareq;
+       } else if (tusb_dma->ch == -1) {
+               tusb_dma->dmareq = 0;
+               tusb_dma->sync_dev = OMAP24XX_DMA_EXT_DMAREQ0;
+
+               /* Callback data gets set later in the shared dmareq case */
+               ret = omap_request_dma(tusb_dma->sync_dev, "TUSB shared",
+                               tusb_omap_dma_cb, NULL, &tusb_dma->ch);
+               if (ret != 0)
+                       goto free_dmareq;
+
+               chdat->dmareq = -1;
+               chdat->ch = -1;
+       }
+
+       DBG(3, "ep%i %s dma: %s dma%i dmareq%i sync%i\n",
+               chdat->epnum,
+               chdat->tx ? "tx" : "rx",
+               chdat->ch >=0 ? "dedicated" : "shared",
+               chdat->ch >= 0 ? chdat->ch : tusb_dma->ch,
+               chdat->dmareq >= 0 ? chdat->dmareq : tusb_dma->dmareq,
+               chdat->sync_dev >= 0 ? chdat->sync_dev : tusb_dma->sync_dev);
+
+       return channel;
+
+free_dmareq:
+       tusb_omap_dma_free_dmareq(chdat);
+
+       DBG(3, "ep%i: Could not get a DMA channel\n", chdat->epnum);
+       channel->bStatus = MGC_DMA_STATUS_UNKNOWN;
+
+       return NULL;
+}
+
+static void tusb_omap_dma_release(struct dma_channel *channel)
+{
+       struct tusb_omap_dma_ch *chdat = to_chdat(channel);
+       struct musb             *musb = chdat->musb;
+       void __iomem            *tusb_base = musb->ctrl_base;
+       u32                     reg;
+
+       DBG(3, "ep%i ch%i\n", chdat->epnum, chdat->ch);
+
+       reg = musb_readl(tusb_base, TUSB_DMA_INT_MASK);
+       if (chdat->tx)
+               reg |= (1 << chdat->epnum);
+       else
+               reg |= (1 << (chdat->epnum + 15));
+       musb_writel(tusb_base, TUSB_DMA_INT_MASK, reg);
+
+       reg = musb_readl(tusb_base, TUSB_DMA_INT_CLEAR);
+       if (chdat->tx)
+               reg |= (1 << chdat->epnum);
+       else
+               reg |= (1 << (chdat->epnum + 15));
+       musb_writel(tusb_base, TUSB_DMA_INT_CLEAR, reg);
+
+       channel->bStatus = MGC_DMA_STATUS_UNKNOWN;
+
+       if (chdat->ch >= 0) {
+               omap_stop_dma(chdat->ch);
+               omap_free_dma(chdat->ch);
+               chdat->ch = -1;
+       }
+
+       if (chdat->dmareq >= 0)
+               tusb_omap_dma_free_dmareq(chdat);
+
+       channel = NULL;
+}
+
+void dma_controller_destroy(struct dma_controller *c)
+{
+       struct tusb_omap_dma    *tusb_dma;
+       int                     i;
+
+       tusb_dma = container_of(c, struct tusb_omap_dma, controller);
+       for (i = 0; i < MAX_DMAREQ; i++) {
+               struct dma_channel *ch = dma_channel_pool[i];
+               if (ch) {
+                       if (ch->pPrivateData)
+                               kfree(ch->pPrivateData);
+                       kfree(ch);
+               }
+       }
+
+       if (!dmareq_works() && tusb_dma && tusb_dma->ch >= 0)
+               omap_free_dma(tusb_dma->ch);
+
+       kfree(tusb_dma);
+}
+
+struct dma_controller *__init
+dma_controller_create(struct musb *musb, void __iomem *base)
+{
+       void __iomem            *tusb_base = musb->ctrl_base;
+       struct tusb_omap_dma    *tusb_dma;
+       int                     i;
+
+       /* REVISIT: Get dmareq lines used from board-*.c */
+
+       musb_writel(musb->ctrl_base, TUSB_DMA_INT_MASK, 0x7fffffff);
+       musb_writel(musb->ctrl_base, TUSB_DMA_EP_MAP, 0);
+
+       musb_writel(tusb_base, TUSB_DMA_REQ_CONF,
+               TUSB_DMA_REQ_CONF_BURST_SIZE(2)
+               | TUSB_DMA_REQ_CONF_DMA_REQ_EN(0x3f)
+               | TUSB_DMA_REQ_CONF_DMA_REQ_ASSER(2));
+
+       tusb_dma = kzalloc(sizeof(struct tusb_omap_dma), GFP_KERNEL);
+       if (!tusb_dma)
+               goto cleanup;
+
+       tusb_dma->musb = musb;
+       tusb_dma->tusb_base = musb->ctrl_base;
+
+       tusb_dma->ch = -1;
+       tusb_dma->dmareq = -1;
+       tusb_dma->sync_dev = -1;
+
+       tusb_dma->controller.start = tusb_omap_dma_start;
+       tusb_dma->controller.stop = tusb_omap_dma_stop;
+       tusb_dma->controller.channel_alloc = tusb_omap_dma_allocate;
+       tusb_dma->controller.channel_release = tusb_omap_dma_release;
+       tusb_dma->controller.channel_program = tusb_omap_dma_program;
+       tusb_dma->controller.channel_abort = tusb_omap_dma_abort;
+       tusb_dma->controller.pPrivateData = tusb_dma;
+
+       for (i = 0; i < MAX_DMAREQ; i++) {
+               struct dma_channel      *ch;
+               struct tusb_omap_dma_ch *chdat;
+
+               ch = kzalloc(sizeof(struct dma_channel), GFP_KERNEL);
+               if (!ch)
+                       goto cleanup;
+
+               dma_channel_pool[i] = ch;
+
+               chdat = kzalloc(sizeof(struct tusb_omap_dma_ch), GFP_KERNEL);
+               if (!chdat)
+                       goto cleanup;
+
+               ch->bStatus = MGC_DMA_STATUS_UNKNOWN;
+               ch->pPrivateData = chdat;
+       }
+
+       return &tusb_dma->controller;
+
+cleanup:
+       dma_controller_destroy(&tusb_dma->controller);
+
+       return NULL;
+}
diff --git a/drivers/usb/musb/virthub.c b/drivers/usb/musb/virthub.c
new file mode 100644 (file)
index 0000000..41ae741
--- /dev/null
@@ -0,0 +1,384 @@
+/*****************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006 by Nokia Corporation
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux 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.
+ *
+ * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/timer.h>
+
+#include "musbdefs.h"
+
+
+static void musb_port_suspend(struct musb *musb, u8 bSuspend)
+{
+       u8              power;
+       void __iomem    *pBase = musb->pRegs;
+
+       if (!is_host_active(musb))
+               return;
+
+       /* NOTE:  this doesn't necessarily put PHY into low power mode,
+        * turning off its clock; that's a function of PHY integration and
+        * MGC_M_POWER_ENSUSPEND.  PHY may need a clock (sigh) to detect
+        * SE0 changing to connect (J) or wakeup (K) states.
+        */
+       power = musb_readb(pBase, MGC_O_HDRC_POWER);
+       if (bSuspend) {
+               power &= ~MGC_M_POWER_RESUME;
+               power |= MGC_M_POWER_SUSPENDM;
+               musb_writeb(pBase, MGC_O_HDRC_POWER, power);
+
+               DBG(3, "Root port suspended, power %02x\n", power);
+
+               musb->port1_status |= USB_PORT_STAT_SUSPEND;
+               switch (musb->xceiv.state) {
+               case OTG_STATE_A_HOST:
+                       musb->xceiv.state = OTG_STATE_A_SUSPEND;
+                       musb->is_active = is_otg_enabled(musb)
+                                       && musb->xceiv.host->b_hnp_enable;
+                       musb_platform_try_idle(musb);
+                       break;
+               case OTG_STATE_B_HOST:
+                       musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
+                       MUSB_DEV_MODE(musb);
+                       /* REVISIT restore setting of MGC_M_DEVCTL_HR */
+                       break;
+               default:
+                       DBG(1, "bogus rh suspend? %s\n",
+                               otg_state_string(musb));
+               }
+       } else if (power & MGC_M_POWER_SUSPENDM) {
+               power &= ~MGC_M_POWER_SUSPENDM;
+               power |= MGC_M_POWER_RESUME;
+               musb_writeb(pBase, MGC_O_HDRC_POWER, power);
+
+               DBG(3, "Root port resuming, power %02x\n", power);
+
+               /* later, GetPortStatus will stop RESUME signaling */
+               musb->port1_status |= MUSB_PORT_STAT_RESUME;
+               musb->rh_timer = jiffies + msecs_to_jiffies(20);
+       }
+}
+
+static void musb_port_reset(struct musb *musb, u8 bReset)
+{
+       u8              power;
+       void __iomem    *pBase = musb->pRegs;
+
+#ifdef CONFIG_USB_MUSB_OTG
+       /* REVISIT this looks wrong for HNP */
+       u8 devctl = musb_readb(pBase, MGC_O_HDRC_DEVCTL);
+
+       if (musb->bDelayPortPowerOff || !(devctl & MGC_M_DEVCTL_HM)) {
+               return;
+       }
+#endif
+
+       if (!is_host_active(musb))
+               return;
+
+       /* NOTE:  caller guarantees it will turn off the reset when
+        * the appropriate amount of time has passed
+        */
+       power = musb_readb(pBase, MGC_O_HDRC_POWER);
+       if (bReset) {
+               musb->bIgnoreDisconnect = TRUE;
+               power &= 0xf0;
+               musb_writeb(pBase, MGC_O_HDRC_POWER,
+                               power | MGC_M_POWER_RESET);
+
+               musb->port1_status |= USB_PORT_STAT_RESET;
+               musb->port1_status &= ~USB_PORT_STAT_ENABLE;
+               musb->rh_timer = jiffies + msecs_to_jiffies(50);
+       } else {
+               DBG(4, "root port reset stopped\n");
+               musb_writeb(pBase, MGC_O_HDRC_POWER,
+                               power & ~MGC_M_POWER_RESET);
+
+               musb->bIgnoreDisconnect = FALSE;
+
+               power = musb_readb(pBase, MGC_O_HDRC_POWER);
+               if (power & MGC_M_POWER_HSMODE) {
+                       DBG(4, "high-speed device connected\n");
+                       musb->port1_status |= USB_PORT_STAT_HIGH_SPEED;
+               }
+
+               musb->port1_status &= ~USB_PORT_STAT_RESET;
+               musb->port1_status |= USB_PORT_STAT_ENABLE
+                                       | (USB_PORT_STAT_C_RESET << 16)
+                                       | (USB_PORT_STAT_C_ENABLE << 16);
+               usb_hcd_poll_rh_status(musb_to_hcd(musb));
+
+               musb->vbuserr_retry = VBUSERR_RETRY_COUNT;
+       }
+}
+
+void musb_root_disconnect(struct musb *musb)
+{
+       musb->port1_status = (1 << USB_PORT_FEAT_POWER)
+                       | (1 << USB_PORT_FEAT_C_CONNECTION);
+
+       usb_hcd_poll_rh_status(musb_to_hcd(musb));
+       musb->is_active = 0;
+
+       switch (musb->xceiv.state) {
+       case OTG_STATE_A_HOST:
+       case OTG_STATE_A_SUSPEND:
+               musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
+               break;
+       case OTG_STATE_A_WAIT_VFALL:
+               musb->xceiv.state = OTG_STATE_B_IDLE;
+               break;
+       default:
+               DBG(1, "host disconnect (%s)\n", otg_state_string(musb));
+       }
+}
+
+
+/*---------------------------------------------------------------------*/
+
+int musb_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+       struct musb     *musb = hcd_to_musb(hcd);
+       int             retval = 0;
+
+       /* called in_irq() via usb_hcd_poll_rh_status() */
+       if (musb->port1_status & 0xffff0000) {
+               *buf = 0x02;
+               retval = 1;
+       }
+       return retval;
+}
+
+int musb_hub_control(
+       struct usb_hcd  *hcd,
+       u16             typeReq,
+       u16             wValue,
+       u16             wIndex,
+       char            *buf,
+       u16             wLength)
+{
+       struct musb     *musb = hcd_to_musb(hcd);
+       u32             temp;
+       int             retval = 0;
+       unsigned long   flags;
+
+       if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
+               return -ESHUTDOWN;
+
+       /* hub features:  always zero, setting is a NOP
+        * port features: reported, sometimes updated when host is active
+        * no indicators
+        */
+       spin_lock_irqsave(&musb->Lock, flags);
+       switch (typeReq) {
+       case ClearHubFeature:
+       case SetHubFeature:
+               switch (wValue) {
+               case C_HUB_OVER_CURRENT:
+               case C_HUB_LOCAL_POWER:
+                       break;
+               default:
+                       goto error;
+               }
+               break;
+       case ClearPortFeature:
+               if (wIndex != 1)
+                       goto error;
+
+               switch (wValue) {
+               case USB_PORT_FEAT_ENABLE:
+                       break;
+               case USB_PORT_FEAT_SUSPEND:
+                       musb_port_suspend(musb, FALSE);
+                       break;
+               case USB_PORT_FEAT_POWER:
+                       if (!(is_otg_enabled(musb) && hcd->self.is_b_host))
+                               musb_set_vbus(musb, 0);
+                       break;
+               case USB_PORT_FEAT_C_CONNECTION:
+               case USB_PORT_FEAT_C_ENABLE:
+               case USB_PORT_FEAT_C_OVER_CURRENT:
+               case USB_PORT_FEAT_C_RESET:
+               case USB_PORT_FEAT_C_SUSPEND:
+                       break;
+               default:
+                       goto error;
+               }
+               DBG(5, "clear feature %d\n", wValue);
+               musb->port1_status &= ~(1 << wValue);
+               break;
+       case GetHubDescriptor:
+               {
+               struct usb_hub_descriptor *desc = (void *)buf;
+
+               desc->bDescLength = 9;
+               desc->bDescriptorType = 0x29;
+               desc->bNbrPorts = 1;
+               desc->wHubCharacteristics = __constant_cpu_to_le16(
+                                 0x0001        /* per-port power switching */
+                               | 0x0010        /* no overcurrent reporting */
+                               );
+               desc->bPwrOn2PwrGood = 5;       /* msec/2 */
+               desc->bHubContrCurrent = 0;
+
+               /* workaround bogus struct definition */
+               desc->DeviceRemovable[0] = 0x02;        /* port 1 */
+               desc->DeviceRemovable[1] = 0xff;
+               }
+               break;
+       case GetHubStatus:
+               temp = 0;
+               *(__le32 *) buf = cpu_to_le32 (temp);
+               break;
+       case GetPortStatus:
+               if (wIndex != 1)
+                       goto error;
+
+               /* finish RESET signaling? */
+               if ((musb->port1_status & USB_PORT_STAT_RESET)
+                               && time_after(jiffies, musb->rh_timer))
+                       musb_port_reset(musb, FALSE);
+
+               /* finish RESUME signaling? */
+               if ((musb->port1_status & MUSB_PORT_STAT_RESUME)
+                               && time_after(jiffies, musb->rh_timer)) {
+                       u8              power;
+
+                       power = musb_readb(musb->pRegs, MGC_O_HDRC_POWER);
+                       power &= ~MGC_M_POWER_RESUME;
+                       DBG(4, "root port resume stopped, power %02x\n",
+                                       power);
+                       musb_writeb(musb->pRegs, MGC_O_HDRC_POWER, power);
+
+                       /* ISSUE:  DaVinci (RTL 1.300) disconnects after
+                        * resume of high speed peripherals (but not full
+                        * speed ones).
+                        */
+
+                       musb->is_active = 1;
+                       musb->port1_status &= ~(USB_PORT_STAT_SUSPEND
+                                       | MUSB_PORT_STAT_RESUME);
+                       musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
+                       usb_hcd_poll_rh_status(musb_to_hcd(musb));
+                       /* NOTE: it might really be A_WAIT_BCON ... */
+                       musb->xceiv.state = OTG_STATE_A_HOST;
+               }
+
+               *(__le32 *) buf = cpu_to_le32(musb->port1_status
+                               & ~MUSB_PORT_STAT_RESUME);
+
+               /* port change status is more interesting */
+               DBG((*(u16*)(buf+2)) ? 2 : 5, "port status %08x\n",
+                               musb->port1_status);
+               break;
+       case SetPortFeature:
+               if ((wIndex & 0xff) != 1)
+                       goto error;
+
+               switch (wValue) {
+               case USB_PORT_FEAT_POWER:
+                       /* NOTE: this controller has a strange state machine
+                        * that involves "requesting sessions" according to
+                        * magic side effects from incompletely-described
+                        * rules about startup...
+                        *
+                        * This call is what really starts the host mode; be
+                        * very careful about side effects if you reorder any
+                        * initialization logic, e.g. for OTG, or change any
+                        * logic relating to VBUS power-up.
+                        */
+                       if (!(is_otg_enabled(musb) && hcd->self.is_b_host))
+                               musb_start(musb);
+                       break;
+               case USB_PORT_FEAT_RESET:
+                       musb_port_reset(musb, TRUE);
+                       break;
+               case USB_PORT_FEAT_SUSPEND:
+                       musb_port_suspend(musb, TRUE);
+                       break;
+               case USB_PORT_FEAT_TEST:
+                       if (unlikely(is_host_active(musb)))
+                               goto error;
+
+                       wIndex >>= 8;
+                       switch (wIndex) {
+                       case 1:
+                               pr_debug("TEST_J\n");
+                               temp = MGC_M_TEST_J;
+                               break;
+                       case 2:
+                               pr_debug("TEST_K\n");
+                               temp = MGC_M_TEST_K;
+                               break;
+                       case 3:
+                               pr_debug("TEST_SE0_NAK\n");
+                               temp = MGC_M_TEST_SE0_NAK;
+                               break;
+                       case 4:
+                               pr_debug("TEST_PACKET\n");
+                               temp = MGC_M_TEST_PACKET;
+                               musb_load_testpacket(musb);
+                               break;
+                       case 5:
+                               pr_debug("TEST_FORCE_ENABLE\n");
+                               temp = MGC_M_TEST_FORCE_HOST
+                                       | MGC_M_TEST_FORCE_HS;
+
+                               /* FIXME and enable a session too */
+                               break;
+                       default:
+                               goto error;
+                       }
+                       musb_writeb(musb->pRegs, MGC_O_HDRC_TESTMODE, temp);
+                       break;
+               default:
+                       goto error;
+               }
+               DBG(5, "set feature %d\n", wValue);
+               musb->port1_status |= 1 << wValue;
+               break;
+
+       default:
+error:
+               /* "protocol stall" on error */
+               retval = -EPIPE;
+       }
+       spin_unlock_irqrestore(&musb->Lock, flags);
+       return retval;
+}
index 3e4873c4109f6f6e0450df7fc471e816584e5829..64ad6472db5d201b37725875a6c165c090ddc490 100644 (file)
@@ -1646,6 +1646,9 @@ config FB_VIRTUAL
          the vfb_enable=1 option.
 
          If unsure, say N.
+
+source "drivers/video/omap/Kconfig"
+
 if VT
        source "drivers/video/console/Kconfig"
 endif
@@ -1654,10 +1657,6 @@ if FB || SGI_NEWPORT_CONSOLE
        source "drivers/video/logo/Kconfig"
 endif
 
-if ARCH_OMAP
-       source "drivers/video/omap/Kconfig"
-endif
-
 if SYSFS
        source "drivers/video/backlight/Kconfig"
 endif
index a5bd901256e5862d61425e640cf8378b41e9b327..f144697b3c21d31f829d7f945e0b86f15773c233 100644 (file)
@@ -106,7 +106,7 @@ obj-$(CONFIG_FB_VESA)             += vesafb.o
 obj-$(CONFIG_FB_IMAC)             += imacfb.o
 obj-$(CONFIG_FB_VGA16)            += vga16fb.o vgastate.o
 obj-$(CONFIG_FB_OF)               += offb.o
-obj-$(CONFIG_FB_OMAP)             += omap/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o
+obj-$(CONFIG_FB_OMAP)            += omap/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o
 
 # the test framebuffer is last
 obj-$(CONFIG_FB_VIRTUAL)          += vfb.o
index 02f15297a021b1c7902137ee09bed8355e62f412..915844904104b67f9aa25deea95b1ec14bc0fd5f 100644 (file)
@@ -66,3 +66,11 @@ config BACKLIGHT_HP680
          If you have a HP Jornada 680, say y to enable the
          backlight driver.
 
+config BACKLIGHT_OMAP
+       tristate "OMAP LCD Backlight"
+       depends on BACKLIGHT_DEVICE && (ARCH_OMAP1 || ARCH_OMAP2)
+       default y
+       help
+         This driver controls the LCD backlight level and power
+         for the PWL module of OMAP processors.  Say Y if you plan
+         to use power saving.
index 65e5553fc849fed5bcbadb287640313bdfa09b97..c2e0b879fa5c367d6cd745130c1bf71dba80ca83 100644 (file)
@@ -5,3 +5,4 @@ obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
 obj-$(CONFIG_BACKLIGHT_CORGI)  += corgi_bl.o
 obj-$(CONFIG_BACKLIGHT_HP680)  += hp680_bl.o
 obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o
+obj-$(CONFIG_BACKLIGHT_OMAP)   += omap_bl.o
diff --git a/drivers/video/backlight/omap_bl.c b/drivers/video/backlight/omap_bl.c
new file mode 100644 (file)
index 0000000..3b57b27
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * drivers/video/backlight/omap_bl.c
+ *
+ * Backlight driver for OMAP based boards.
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This package 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 package 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 package; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/board.h>
+#include <asm/arch/mux.h>
+
+#define OMAPBL_MAX_INTENSITY           0xff
+
+struct omap_backlight {
+       int powermode;
+       int current_intensity;
+
+       struct device *dev;
+       struct omap_backlight_config *pdata;
+};
+
+static void inline omapbl_send_intensity(int intensity)
+{
+       omap_writeb(intensity, OMAP_PWL_ENABLE);
+}
+
+static void inline omapbl_send_enable(int enable)
+{
+       omap_writeb(enable, OMAP_PWL_CLK_ENABLE);
+}
+
+static void omapbl_blank(struct omap_backlight *bl, int mode)
+{
+       if (bl->pdata->set_power)
+               bl->pdata->set_power(bl->dev, mode);
+
+       switch (mode) {
+       case FB_BLANK_NORMAL:
+       case FB_BLANK_VSYNC_SUSPEND:
+       case FB_BLANK_HSYNC_SUSPEND:
+       case FB_BLANK_POWERDOWN:
+               omapbl_send_intensity(0);
+               omapbl_send_enable(0);
+               break;
+
+       case FB_BLANK_UNBLANK:
+               omapbl_send_intensity(bl->current_intensity);
+               omapbl_send_enable(1);
+               break;
+       }
+}
+
+#ifdef CONFIG_PM
+static int omapbl_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct backlight_device *dev = platform_get_drvdata(pdev);
+       struct omap_backlight *bl = class_get_devdata(&dev->class_dev);
+
+       omapbl_blank(bl, FB_BLANK_POWERDOWN);
+       return 0;
+}
+
+static int omapbl_resume(struct platform_device *pdev)
+{
+       struct backlight_device *dev = platform_get_drvdata(pdev);
+       struct omap_backlight *bl = class_get_devdata(&dev->class_dev);
+
+       omapbl_blank(bl, bl->powermode);
+       return 0;
+}
+#else
+#define omapbl_suspend NULL
+#define omapbl_resume  NULL
+#endif
+
+static int omapbl_set_power(struct backlight_device *dev, int state)
+{
+       struct omap_backlight *bl = class_get_devdata(&dev->class_dev);
+
+       omapbl_blank(bl, state);
+       bl->powermode = state;
+
+       return 0;
+}
+
+static int omapbl_update_status(struct backlight_device *dev)
+{
+       struct omap_backlight *bl = class_get_devdata(&dev->class_dev);
+
+       if (bl->current_intensity != dev->props->brightness) {
+               if (dev->props->brightness < 0)
+                       return -EPERM;  /* Leave current_intensity untouched */
+
+               if (bl->powermode == FB_BLANK_UNBLANK)
+                       omapbl_send_intensity(dev->props->brightness);
+               bl->current_intensity = dev->props->brightness;
+       }
+
+       if (dev->props->fb_blank != bl->powermode)
+               omapbl_set_power(dev, dev->props->fb_blank);
+
+       return 0;
+}
+
+static int omapbl_get_intensity(struct backlight_device *dev)
+{
+       struct omap_backlight *bl = class_get_devdata(&dev->class_dev);
+       return bl->current_intensity;
+}
+
+static struct backlight_properties omapbl_data = {
+       .owner          = THIS_MODULE,
+       .get_brightness = omapbl_get_intensity,
+       .update_status  = omapbl_update_status,
+       .max_brightness = OMAPBL_MAX_INTENSITY,
+};
+
+static int omapbl_probe(struct platform_device *pdev)
+{
+       struct backlight_device *dev;
+       struct omap_backlight *bl;
+       struct omap_backlight_config *pdata = pdev->dev.platform_data;
+
+       if (!pdata)
+               return -ENXIO;
+
+       omapbl_data.check_fb = pdata->check_fb;
+
+       bl = kzalloc(sizeof(struct omap_backlight), GFP_KERNEL);
+       if (unlikely(!bl))
+               return -ENOMEM;
+
+       dev = backlight_device_register("omap-bl", &pdev->dev,
+                       bl, &omapbl_data);
+       if (IS_ERR(dev)) {
+               kfree(bl);
+               return PTR_ERR(dev);
+       }
+
+       bl->powermode = FB_BLANK_POWERDOWN;
+       bl->current_intensity = 0;
+
+       bl->pdata = pdata;
+       bl->dev = &pdev->dev;
+
+       platform_set_drvdata(pdev, dev);
+
+       omap_cfg_reg(PWL);      /* Conflicts with UART3 */
+
+       omapbl_data.fb_blank = FB_BLANK_UNBLANK;
+       omapbl_data.brightness = pdata->default_intensity;
+       omapbl_update_status(dev);
+
+       printk(KERN_INFO "OMAP LCD backlight initialised\n");
+
+       return 0;
+}
+
+static int omapbl_remove(struct platform_device *pdev)
+{
+       struct backlight_device *dev = platform_get_drvdata(pdev);
+       struct omap_backlight *bl = class_get_devdata(&dev->class_dev);
+
+       backlight_device_unregister(dev);
+       kfree(bl);
+
+       return 0;
+}
+
+static struct platform_driver omapbl_driver = {
+       .probe          = omapbl_probe,
+       .remove         = omapbl_remove,
+       .suspend        = omapbl_suspend,
+       .resume         = omapbl_resume,
+       .driver         = {
+               .name   = "omap-bl",
+       },
+};
+
+static int __init omapbl_init(void)
+{
+       return platform_driver_register(&omapbl_driver);
+}
+
+static void __exit omapbl_exit(void)
+{
+       platform_driver_unregister(&omapbl_driver);
+}
+
+module_init(omapbl_init);
+module_exit(omapbl_exit);
+
+MODULE_AUTHOR("Andrzej Zaborowski <balrog@zabor.org>");
+MODULE_DESCRIPTION("OMAP LCD Backlight driver");
+MODULE_LICENSE("GPL");
index 78123a25a333e76691627cc04b3a5885fafaa9cd..d84187faab3ec585beb34dc3d2031aab5e91c2da 100644 (file)
@@ -9,7 +9,7 @@ config FB_OMAP_LCDC_EXTERNAL
        depends on FB_OMAP
        help
          Say Y here, if you want to have support for boards with an
-         external LCD controller connected to the SoSSI/RFBI interface.
+         external LCD controller connected to the SoSSI/RFBI interface. 
 
 config FB_OMAP_LCDC_HWA742
        bool "Epson HWA742 LCD controller support"
diff --git a/include/asm-arm/.gitignore b/include/asm-arm/.gitignore
new file mode 100644 (file)
index 0000000..e1bf470
--- /dev/null
@@ -0,0 +1,3 @@
+arch
+asm-offsets.h
+mach-types.h
index fcaf44c14714c8f36f2c9d75eec216bb01027f41..e655d35720068c2e87fec4987e2e4a8b5b9a69eb 100644 (file)
 #include <sound/pcm.h>
 #include <asm/arch/mcbsp.h>
 #include <linux/platform_device.h>
+/*
+ * Debug functions
+ */
+#undef DEBUG
+//#define DEBUG
+
+#define ERR(ARGS...) printk(KERN_ERR "{%s}-ERROR: ", __FUNCTION__);printk(ARGS);
+
+#ifdef DEBUG
+#define DPRINTK(ARGS...)  printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS)
+#define ADEBUG() printk("XXX Alsa debug f:%s, l:%d\n", __FUNCTION__, __LINE__)
+#define FN_IN printk(KERN_INFO "[%s]: start\n", __FUNCTION__)
+#define FN_OUT(n) printk(KERN_INFO "[%s]: end(%u)\n",__FUNCTION__, n)
+#else
+#define DPRINTK(ARGS...)       /* nop */
+#define ADEBUG()               /* nop */
+#define FN_IN                  /* nop */
+#define FN_OUT(n)              /* nop */
+#endif
 
 #define DMA_BUF_SIZE   (1024 * 8)
 
@@ -65,7 +84,7 @@ struct audio_stream {
        int period;             /* current transfer period */
        int periods;            /* current count of periods registerd in the DMA engine */
        spinlock_t dma_lock;    /* for locking in DMA operations */
-       struct snd_pcm_substream *stream;       /* the pcm stream */
+       snd_pcm_substream_t *stream;    /* the pcm stream */
        unsigned linked:1;      /* dma channels linked */
        int offset;             /* store start position of the last period in the alsa buffer */
        int (*hw_start)(void);  /* interface to start HW interface, e.g. McBSP */
@@ -76,8 +95,8 @@ struct audio_stream {
  * Alsa card structure for aic23
  */
 struct snd_card_omap_codec {
-       struct snd_card *card;
-       struct snd_pcm *pcm;
+       snd_card_t *card;
+       snd_pcm_t *pcm;
        long samplerate;
        struct audio_stream s[2];       /* playback & capture */
 };
@@ -89,9 +108,9 @@ struct snd_card_omap_codec {
 struct omap_alsa_codec_config {
        char    *name;
        struct  omap_mcbsp_reg_cfg *mcbsp_regs_alsa;
-       struct  snd_pcm_hw_constraint_list *hw_constraints_rates;
-       struct  snd_pcm_hardware *snd_omap_alsa_playback;
-       struct  snd_pcm_hardware *snd_omap_alsa_capture;
+       snd_pcm_hw_constraint_list_t *hw_constraints_rates;
+       snd_pcm_hardware_t *snd_omap_alsa_playback;
+       snd_pcm_hardware_t *snd_omap_alsa_capture;
        void    (*codec_configure_dev)(void);
        void    (*codec_set_samplerate)(long);
        void    (*codec_clock_setup)(void);
diff --git a/include/asm-arm/arch-omap/sti.h b/include/asm-arm/arch-omap/sti.h
new file mode 100644 (file)
index 0000000..e5a383d
--- /dev/null
@@ -0,0 +1,161 @@
+#ifndef __ASM_ARCH_OMAP_STI_H
+#define __ASM_ARCH_OMAP_STI_H
+
+#include <asm/io.h>
+
+/*
+ * STI/XTI
+ */
+#define STI_REVISION           0x00
+#define STI_SYSCONFIG          0x10
+#define STI_SYSSTATUS          0x14
+#define STI_IRQSTATUS          0x18
+#define STI_IRQSETEN           0x1c
+
+#if defined(CONFIG_ARCH_OMAP1)
+#define STI_IRQCLREN           0x20
+#define STI_ER                 0x24
+#define STI_DR                 0x28
+#define STI_RX_DR              0x2c
+#define STI_RX_STATUS          0x30
+#define STI_CLK_CTRL           0x34
+#define STI_IOBOTT0            0x4c
+#define STI_IOTOP0             0x50
+#define STI_IOBOTT1            0x54
+#define STI_IOTOP1             0x58
+#define STI_SERIAL_CFG         0x60
+
+#define STI_OCPT2_MATCH_INT    0
+#define STI_OCPT1_MATCH_INT    1
+#define STI_EMIFS_MATCH_INT    2
+#define STI_EMIFF_MATCH_INT    3
+#define STI_IO_MATCH_INT       4
+#define STI_RX_INT             5
+#define STI_DUMP_REQUEST_INT   6
+#define STI_DUMP_UNDERRUN_INT  7
+#define STI_WAKEUP_INT         9
+
+#define STI_NR_IRQS    10
+
+#define STI_IRQSTATUS_MASK     0x2ff
+#define STI_PERCHANNEL_SIZE    4
+
+#define STI_RXFIFO_EMPTY       (1 << 0)
+
+/*
+ * We use the following enums to retain consistency with the STI "functional"
+ * specification.
+ */
+
+/* STI_ER */
+enum {
+       UnlockStatMatch = (1 <<  2), /* Unlock status match event regs */
+       IOMPUStr1En1    = (1 <<  3), /* MPU IO match, strobe 1, window 1 */
+       IOMPUStr0En1    = (1 <<  4), /* MPU IO match, strobe 0, window 1 */
+       IOMPUStr1En0    = (1 <<  5), /* MPU IO match, strobe 1, window 0 */
+       IOMPUStr0En0    = (1 <<  6), /* MPU IO match, strobe 0, window 0 */
+       IODSPStr1En1    = (1 <<  7), /* DSP IO match, strobe 1, window 1 */
+       IODSPStr0En1    = (1 <<  8), /* DSP IO match, strobe 0, window 1 */
+       IODSPStr1En0    = (1 <<  9), /* DSP IO match, strobe 1, window 0 */
+       IODSPStr0En0    = (1 << 10), /* DSP IO match, strobe 0, window 0 */
+       MemMatchEn      = (1 << 11), /* Memory matched event */
+       DSPCmdEn        = (1 << 12), /* DSP command write */
+       MPUCmdEn        = (1 << 13), /* MPU command write */
+       MemDumpEn       = (1 << 14), /* System memory dump */
+       STIEn           = (1 << 15), /* Global trace enable */
+};
+#elif defined(CONFIG_ARCH_OMAP2)
+
+/* XTI interrupt bits */
+enum {
+       STI_WAKEUP_INT  = 0,
+       STI_ETB_THRESHOLD_INT,
+       STI_RX_INT,
+       STI_DUMP_REQUEST_INT,
+       STI_NR_IRQS,
+};
+
+/* XTI_TRACESELECT */
+enum {
+       CmdTimeStampEn  = (1 << 0),     /* Command write timestamps */
+       WinTimeStampEn  = (1 << 1),     /* Window match timestamps */
+       WinMatchEn      = (1 << 2),     /* Window match trace */
+       DSPCmdEn        = (1 << 3),     /* DSP command write */
+       MPUCmdEn        = (1 << 4),     /* MPU command write */
+       MemDumpEn0      = (1 << 5),     /* System memory dump */
+       MemDumpEn1      = (1 << 6),
+       MemDumpEn2      = (1 << 7),
+       ExtTriggerEn    = (1 << 8),     /* External trace trigger */
+       STIEn           = (1 << 9),     /* System trace enable */
+};
+
+#define STI_IRQSTATUS_MASK     0x0f
+#define STI_PERCHANNEL_SIZE    64
+
+/* XTI registers */
+#define XTI_SYSSTATUS          0x14
+#define XTI_TRACESELECT                0x24
+#define XTI_RXDATA             0x28
+#define XTI_SCLKCRTL           0x2c
+#define XTI_SCONFIG            0x30
+
+/* STI Compatability */
+#define STI_RX_STATUS          XTI_SYSSTATUS
+#define STI_IRQCLREN           STI_IRQSETEN
+#define STI_ER                 XTI_TRACESELECT
+#define STI_DR                 XTI_TRACESELECT
+#define STI_RX_DR              XTI_RXDATA
+#define STI_CLK_CTRL           XTI_SCLKCRTL
+#define STI_SERIAL_CFG         XTI_SCONFIG
+
+#define STI_RXFIFO_EMPTY       (1 << 8)
+
+#endif
+
+/* arch/arm/plat-omap/sti/sti.c */
+extern unsigned long sti_base, sti_channel_base;
+
+int sti_request_irq(unsigned int irq, void *handler, unsigned long arg);
+void sti_free_irq(unsigned int irq);
+void sti_enable_irq(unsigned int irq);
+void sti_disable_irq(unsigned int irq);
+void sti_ack_irq(unsigned int irq);
+
+int sti_trace_enable(int event);
+void sti_trace_disable(int event);
+
+void sti_channel_write_trace(int len, int id, void *data, unsigned int channel);
+
+/* arch/arm/plat-omap/sti/sti-fifo.c */
+int sti_read_packet(unsigned char *buf, int maxsize);
+
+static inline unsigned long sti_readl(unsigned long reg)
+{
+       return __raw_readl(sti_base + reg);
+}
+
+static inline void sti_writel(unsigned long data, unsigned long reg)
+{
+       __raw_writel(data, sti_base + reg);
+}
+
+#define to_channel_address(channel) \
+       (sti_channel_base + STI_PERCHANNEL_SIZE * (channel))
+
+static inline void sti_channel_writeb(unsigned char data, unsigned int channel)
+{
+       __raw_writeb(data, to_channel_address(channel));
+}
+
+static inline void sti_channel_writel(unsigned long data, unsigned int channel)
+{
+       __raw_writel(data, to_channel_address(channel));
+}
+
+#define STI_TRACE_CONTROL_CHANNEL      253
+
+static inline void sti_channel_flush(unsigned int channel)
+{
+       sti_channel_writeb(channel, STI_TRACE_CONTROL_CHANNEL);
+}
+#endif /* __ASM_ARCH_OMAP_STI_H */
index 05b029ef6371c6203b1471897490bebce8920815..664b708d2576689a80a6bb5199cb247cebfb6ffd 100644 (file)
@@ -36,4 +36,18 @@ struct flash_platform_data {
        unsigned int    nr_parts;
 };
 
+/**
+ * struct nand_platform_data - platform data describing NAND flash banks
+ * @dev_ready: tests if the NAND flash is ready (READY signal is high)
+ * @options:   bitmask for nand_chip.options
+ * @parts:     optional array of mtd_partitions for static partitioning
+ * @nr_parts:  number of mtd_partitions for static partitoning
+ */
+struct nand_platform_data {
+       int             (*dev_ready)(struct nand_platform_data *data);
+       unsigned int    options;
+       struct mtd_partition *parts;
+       unsigned int    nr_parts;
+};
+
 #endif
index e5407392afcad0413c0df46030f51e2c93c4fd5b..42f00678b362f2b684b5ec610f41d7ed8ce7d999 100644 (file)
@@ -136,6 +136,13 @@ struct tag_acorn {
        __u8 adfsdrives;
 };
 
+/* TI OMAP specific information */
+#define ATAG_BOARD       0x414f4d50
+
+struct tag_omap {
+       u8 data[0];
+};
+
 /* footbridge memory clock, see arch/arm/mach-footbridge/arch.c */
 #define ATAG_MEMCLK    0x41000402
 
@@ -161,6 +168,11 @@ struct tag {
                 */
                struct tag_acorn        acorn;
 
+               /*
+                * OMAP specific
+                 */
+                struct tag_omap         omap;
+
                /*
                 * DC21285 specific
                 */
index 10eb56b2940ad8c8b7f6775de247d552a99cc6fe..6905ec573921e27a9fbf702e54f169bd862a609b 100644 (file)
 #define CN_VAL_CIFS                     0x1
 #define CN_W1_IDX                      0x3     /* w1 communication */
 #define CN_W1_VAL                      0x1
+#define CN_IDX_SX1SND                  0x4
+#define CN_VAL_SX1SND                  0x1
+#define CN_IDX_SX1PM                   0x5
+#define CN_VAL_SX1PM                   0x1
 
 
-#define CN_NETLINK_USERS               4
+#define CN_NETLINK_USERS               6
 
 /*
  * Maximum connector's message size.
index 1bf8c2eab22d3f3c6b48604760c01f57aae73aa0..b700c9cb9d7f554e253886bc766b0a3e665a4bf3 100644 (file)
 #define FB_ACCEL_NV_40          46      /* nVidia Arch 40               */
 #define FB_ACCEL_XGI_VOLARI_V  47      /* XGI Volari V3XT, V5, V8      */
 #define FB_ACCEL_XGI_VOLARI_Z  48      /* XGI Volari Z7                */
-#define FB_ACCEL_OMAP1610      49      /* TI OMAP16xx                  */
+#define FB_ACCEL_OMAP1610       49     /* TI OMAP16xx                  */
 #define FB_ACCEL_NEOMAGIC_NM2070 90    /* NeoMagic NM2070              */
 #define FB_ACCEL_NEOMAGIC_NM2090 91    /* NeoMagic NM2090              */
 #define FB_ACCEL_NEOMAGIC_NM2093 92    /* NeoMagic NM2093              */
index bde65c8a351939ce5aa19fc7e85c511be1037e99..8467e40de769c64304b667c20bdfe4a8e1f5c6d5 100644 (file)
@@ -336,10 +336,22 @@ struct input_absinfo {
 #define KEY_BRIGHTNESSUP       225
 #define KEY_MEDIA              226
 
-#define KEY_SWITCHVIDEOMODE    227
-#define KEY_KBDILLUMTOGGLE     228
-#define KEY_KBDILLUMDOWN       229
-#define KEY_KBDILLUMUP         230
+
+/*Zeus: these keys are defined for OMAP730 Perseus2*/
+#define KEY_STAR               227
+#define KEY_SHARP              228
+#define KEY_SOFT1              229
+#define KEY_SOFT2              230
+#define KEY_SEND               231
+#define KEY_CENTER             232
+#define KEY_HEADSETHOOK                233
+#define KEY_0_5                        234
+#define KEY_2_5                        235
+
+#define KEY_SWITCHVIDEOMODE    236
+#define KEY_KBDILLUMTOGGLE     237
+#define KEY_KBDILLUMDOWN       238
+#define KEY_KBDILLUMUP         239
 
 #define KEY_SEND               231
 #define KEY_REPLY              232
index adb3dafd33e96a6d12c122fc62101b6c7a5c0947..c371475829b3e673b07c8a319a14b7ebfa492698 100644 (file)
@@ -5,9 +5,17 @@
  *
  * It's OK if the min/max values are zero.
  */
+enum ads7846_filter {
+       ADS7846_FILTER_OK,
+       ADS7846_FILTER_REPEAT,
+       ADS7846_FILTER_IGNORE,
+};
+
 struct ads7846_platform_data {
        u16     model;                  /* 7843, 7845, 7846. */
        u16     vref_delay_usecs;       /* 0 for external vref; etc */
+       int     keep_vref_on : 1;       /* set to keep vref on for differential
+                                        * measurements as well */
        u16     x_plate_ohms;
        u16     y_plate_ohms;
 
@@ -21,5 +29,9 @@ struct ads7846_platform_data {
        u16     debounce_rep;           /* additional consecutive good readings
                                         * required after the first two */
        int     (*get_pendown_state)(void);
+       int     (*filter_init)  (struct ads7846_platform_data *pdata,
+                                void **filter_data);
+       int     (*filter)       (void *filter_data, int data_idx, int *val);
+       void    (*filter_cleanup)(void *filter_data);
 };
 
diff --git a/include/linux/spi/tsc2102.h b/include/linux/spi/tsc2102.h
new file mode 100644 (file)
index 0000000..b779fb1
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * include/linux/spi/tsc2102.h
+ *
+ * TI TSC2102 Touchscreen, Audio and Battery control register definitions 
+ *
+ * Copyright (c) 2005 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This package 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 package 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 package; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __LINUX_SPI_TSC2102_H
+#define __LINUX_SPI_TSC2102_H
+
+struct apm_power_info;
+struct tsc2102_config {
+       int use_internal;       /* Use internal reference voltage */
+       uint32_t monitor;       /* What inputs are relevant */
+       int temp_at25c[2];      /* Thermometer calibration data */
+       void (*apm_report)(struct apm_power_info *info, int *battery);
+                               /* Report status to APM based on battery[] */
+       void *alsa_config;      /* .platform_data for the ALSA device */
+};
+
+#define TSC_BAT1       (1 << 0)
+#define TSC_BAT2       (1 << 1)
+#define TSC_AUX                (1 << 2)
+#define TSC_TEMP       (1 << 4)
+
+extern u16 tsc2102_read_sync(int page, u8 address);
+extern void tsc2102_reads_sync(int page, u8 startaddress, u16 *data,
+               int numregs);
+extern void tsc2102_write_sync(int page, u8 address, u16 data);
+
+typedef void (*tsc2102_touch_t)(int touching);
+typedef void (*tsc2102_coords_t)(int x, int y, int z1, int z2);
+typedef void (*tsc2102_ports_t)(int bat1, int bat2, int aux);
+typedef void (*tsc2102_temp_t)(int temp);
+extern int tsc2102_touch_cb(tsc2102_touch_t handler);
+extern int tsc2102_coords_cb(tsc2102_coords_t handler);
+extern int tsc2102_ports_cb(tsc2102_ports_t handler);
+extern int tsc2102_temp1_cb(tsc2102_temp_t handler);
+extern int tsc2102_temp2_cb(tsc2102_temp_t handler);
+
+#ifdef CONFIG_SOUND
+extern void tsc2102_set_volume(uint8_t left_ch, uint8_t right_ch);
+extern void tsc2102_set_mute(int left_ch, int right_ch);
+extern void tsc2102_get_mute(int *left_ch, int *right_ch);
+extern void tsc2102_dac_power(int state);
+extern int tsc2102_set_rate(int rate);
+extern void tsc2102_set_i2s_master(int state);
+extern void tsc2102_set_deemphasis(int enable);
+extern void tsc2102_set_bassboost(int enable);
+#endif
+
+extern void tsc2102_keyclick(int amplitude, int freq, int length);
+
+#define TSC2102_REG(pg, addr)          pg, addr
+
+/* Page 0, Touch Screen & Keypad Data registers */
+#define TSC2102_TS_X                   TSC2102_REG(0, 0x00)
+#define TSC2102_TS_Y                   TSC2102_REG(0, 0x01)
+#define TSC2102_TS_Z1                  TSC2102_REG(0, 0x02)
+#define TSC2102_TS_Z2                  TSC2102_REG(0, 0x03)
+#define TSC2102_TS_BAT1                        TSC2102_REG(0, 0x05)
+#define TSC2102_TS_BAT2                        TSC2102_REG(0, 0x06)
+#define TSC2102_TS_AUX                 TSC2102_REG(0, 0x07)
+#define TSC2102_TS_TEMP1               TSC2102_REG(0, 0x09)
+#define TSC2102_TS_TEMP2               TSC2102_REG(0, 0x0a)
+
+/* Page 1, Touch Screen & Keypad Control registers */
+#define TSC2102_TS_ADC_CTRL            TSC2102_REG(1, 0x00)
+#define TSC2102_TS_STATUS_CTRL         TSC2102_REG(1, 0x01)
+#define TSC2102_TS_REF_CTRL            TSC2102_REG(1, 0x03)
+#define TSC2102_TS_RESET_CTRL          TSC2102_REG(1, 0x04)
+#define TSC2102_TS_CONFIG_CTRL         TSC2102_REG(1, 0x05)
+
+/* Page 2, Audio Control registers */
+#define TSC2102_AUDIO1_CTRL            TSC2102_REG(2, 0x00)
+#define TSC2102_DAC_GAIN_CTRL          TSC2102_REG(2, 0x02)
+#define TSC2102_AUDIO2_CTRL            TSC2102_REG(2, 0x04)
+#define TSC2102_DAC_POWER_CTRL         TSC2102_REG(2, 0x05)
+#define TSC2102_AUDIO3_CTRL            TSC2102_REG(2, 0x06)
+#define TSC2102_LCH_BASS_BOOST_N0      TSC2102_REG(2, 0x07)
+#define TSC2102_LCH_BASS_BOOST_N1      TSC2102_REG(2, 0x08)
+#define TSC2102_LCH_BASS_BOOST_N2      TSC2102_REG(2, 0x09)
+#define TSC2102_LCH_BASS_BOOST_N3      TSC2102_REG(2, 0x0a)
+#define TSC2102_LCH_BASS_BOOST_N4      TSC2102_REG(2, 0x0b)
+#define TSC2102_LCH_BASS_BOOST_N5      TSC2102_REG(2, 0x0c)
+#define TSC2102_LCH_BASS_BOOST_D1      TSC2102_REG(2, 0x0d)
+#define TSC2102_LCH_BASS_BOOST_D2      TSC2102_REG(2, 0x0e)
+#define TSC2102_LCH_BASS_BOOST_D4      TSC2102_REG(2, 0x0f)
+#define TSC2102_LCH_BASS_BOOST_D5      TSC2102_REG(2, 0x10)
+#define TSC2102_RCH_BASS_BOOST_N0      TSC2102_REG(2, 0x11)
+#define TSC2102_RCH_BASS_BOOST_N1      TSC2102_REG(2, 0x12)
+#define TSC2102_RCH_BASS_BOOST_N2      TSC2102_REG(2, 0x13)
+#define TSC2102_RCH_BASS_BOOST_N3      TSC2102_REG(2, 0x14)
+#define TSC2102_RCH_BASS_BOOST_N4      TSC2102_REG(2, 0x15)
+#define TSC2102_RCH_BASS_BOOST_N5      TSC2102_REG(2, 0x16)
+#define TSC2102_RCH_BASS_BOOST_D1      TSC2102_REG(2, 0x17)
+#define TSC2102_RCH_BASS_BOOST_D2      TSC2102_REG(2, 0x18)
+#define TSC2102_RCH_BASS_BOOST_D4      TSC2102_REG(2, 0x19)
+#define TSC2102_RCH_BASS_BOOST_D5      TSC2102_REG(2, 0x1a)
+#define TSC2102_PLL1_CTRL              TSC2102_REG(2, 0x1b)
+#define TSC2102_PLL2_CTRL              TSC2102_REG(2, 0x1c)
+#define TSC2102_AUDIO4_CTRL            TSC2102_REG(2, 0x1d)
+
+/* Field masks for Audio Control 1 */
+#define AC1_WLEN(ARG)                  (((ARG) & 0x03) << 10)
+#define AC1_DATFM(ARG)                 (((ARG) & 0x03) << 8)
+#define AC1_DACFS(ARG)                 ((ARG) & 0x3f)
+
+/* Field masks for TSC2102_DAC_GAIN_CTRL */
+#define DGC_DALMU                      (1 << 15)
+#define DGC_DALVL(ARG)                 (((ARG) & 0x7f) << 8)
+#define DGC_DARMU                      (1 << 7)
+#define DGC_DARVL(ARG)                 (((ARG) & 0x7f))
+
+/* Field formats for TSC2102_AUDIO2_CTRL */
+#define AC2_KCLEN                      (1 << 15)
+#define AC2_KCLAC(ARG)                 (((ARG) & 0x07) << 12)
+#define AC2_KCLFRQ(ARG)                        (((ARG) & 0x07) << 8)
+#define AC2_KCLLN(ARG)                 (((ARG) & 0x0f) << 4)
+#define AC2_DLGAF                      (1 << 3)
+#define AC2_DRGAF                      (1 << 2)
+#define AC2_DASTC                      (1 << 1)
+
+/* Field masks for TSC2102_DAC_POWER_CTRL */
+#define CPC_PWDNC                      (1 << 15)
+#define CPC_DAODRC                     (1 << 12)
+#define CPC_DAPWDN                     (1 << 10)
+#define CPC_VGPWDN                     (1 << 8)
+#define CPC_DAPWDF                     (1 << 6)
+#define CPC_BASSBC                     (1 << 1)
+#define CPC_DEEMPF                     (0x01)
+
+/* Field masks for TSC2101_AUDIO_CTRL_3 */
+#define AC3_DMSVOL(ARG)                        (((ARG) & 0x03) << 14)
+#define AC3_REFFS                      (1 << 13)
+#define AC3_DAXFM                      (1 << 12)
+#define AC3_SLVMS                      (1 << 11)
+#define AC3_DALOVF                     (1 << 7)
+#define AC3_DAROVF                     (1 << 6)
+#define AC3_REVID(ARG)                 (((ARG) & 0x07))
+
+/* Field masks for TSC2102_PLL1_CTRL */
+#define PLL1_PLLEN                     (1 << 15)
+#define PLL1_Q_VAL(ARG)                        (((ARG) & 0x0f) << 11)
+#define PLL1_P_VAL(ARG)                        (((ARG) & 0x07) << 8)
+#define PLL1_I_VAL(ARG)                        (((ARG) & 0x3f) << 2)
+
+/* Field masks for TSC2102_PLL2_CTRL */
+#define PLL2_D_VAL(ARG)                        (((ARG) & 0x3fff) << 2)
+
+/* Field masks for TSC2101_AUDIO_CTRL_4 */
+#define AC4_DASTPD                     (1 << 14)
+
+struct tsc2102_rate_info_s {
+       u16 sample_rate;
+       u8 divisor;
+       u8 fs_44k;      /* 44.1 kHz Fsref if 1, 48 kHz if 0 */
+};
+
+#endif /* __LINUX_SPI_TSC2102_H */
diff --git a/include/linux/spi/tsc2301.h b/include/linux/spi/tsc2301.h
new file mode 100644 (file)
index 0000000..6621042
--- /dev/null
@@ -0,0 +1,207 @@
+#ifndef _LINUX_SPI_TSC2301_H
+#define _LINUX_SPI_TSC2301_H
+
+#include <linux/types.h>
+#include <linux/timer.h>
+
+struct tsc2301_platform_data {
+       /*
+        * Keypad
+        */
+       s16     reset_gpio;
+       s16     keyb_int;
+       s16     keymap[16];     /* Set a key to a negative value if not used */
+       unsigned kp_rep:1;      /* Enable keypad repeating */
+
+       /*
+        * Touchscreen
+        */
+       s16     dav_gpio;
+       s16     pen_int_gpio;
+       u16     ts_x_plate_ohm;
+       u32     ts_stab_time;   /* voltage settling time */
+       u8      ts_hw_avg;      /* HW assiseted averaging. Can be
+                                  0, 4, 8, 16 samples per reading */
+       u32     ts_max_pressure;/* Samples with bigger pressure value will
+                                  be ignored, since the corresponding X, Y
+                                  values are unreliable */
+       u32     ts_touch_pressure;      /* Pressure limit until we report a
+                                          touch event. After that we switch
+                                          to ts_max_pressure. */
+       unsigned ts_ignore_last : 1;
+
+       /*
+        * Audio
+        */
+       unsigned        pll_pdc:4;
+       unsigned        pll_a:4;
+       unsigned        pll_n:4;
+       unsigned        pll_output:1; /* Output PLL on GPIO_0 */
+
+       unsigned        mclk_ratio:2;
+       unsigned        i2s_sample_rate:4;
+       unsigned        i2s_format:2;
+       /* Mask for audio blocks to be powered down */
+       u16             power_down_blocks;
+
+       /* Called after codec has been initialized, can be NULL */
+       int (* codec_init)(struct device *tsc2301_dev);
+       /* Called when codec is being removed, can be NULL */
+       void (* codec_cleanup)(struct device *tsc2301_dev);
+       int     (*enable_clock)(struct device *dev);
+       void    (*disable_clock)(struct device *dev);
+       int     (*get_keyb_irq_state)(struct device *dev);
+
+       const struct tsc2301_mixer_gpio {
+               const char      *name;
+               unsigned        gpio:4;
+               unsigned        inverted:1;
+               unsigned        def_enable:1; /* enable by default */
+               unsigned        deactivate_on_pd:1; /* power-down flag */
+       } *mixer_gpios;
+       int     n_mixer_gpios;
+};
+
+struct tsc2301_kp;
+struct tsc2301_ts;
+struct tsc2301_mixer;
+
+struct tsc2301 {
+       struct spi_device       *spi;
+
+       s16                     reset_gpio;
+       u16                     config2_shadow;
+
+        struct tsc2301_kp      *kp;
+       struct tsc2301_ts       *ts;
+       struct tsc2301_mixer    *mixer;
+
+       int                     (*enable_clock)(struct device *dev);
+       void                    (*disable_clock)(struct device *dev);
+};
+
+
+#define TSC2301_HZ     33000000
+
+#define TSC2301_REG(page, addr)  (((page) << 11) | ((addr) << 5))
+#define TSC2301_REG_TO_PAGE(reg) (((reg) >> 11) & 0x03)
+#define TSC2301_REG_TO_ADDR(reg) (((reg) >> 5)  & 0x1f)
+
+#define TSC2301_REG_X          TSC2301_REG(0, 0)
+#define TSC2301_REG_Y          TSC2301_REG(0, 1)
+#define TSC2301_REG_Z1         TSC2301_REG(0, 2)
+#define TSC2301_REG_Z2         TSC2301_REG(0, 3)
+#define TSC2301_REG_KPDATA     TSC2301_REG(0, 4)
+#define TSC2301_REG_ADC                TSC2301_REG(1, 0)
+#define TSC2301_REG_KEY                TSC2301_REG(1, 1)
+#define TSC2301_REG_DAC                TSC2301_REG(1, 2)
+#define TSC2301_REG_REF                TSC2301_REG(1, 3)
+#define TSC2301_REG_CONFIG     TSC2301_REG(1, 5)
+#define TSC2301_REG_CONFIG2    TSC2301_REG(1, 6)
+#define TSC2301_REG_KPMASK     TSC2301_REG(1, 16)
+#define TSC2301_REG_AUDCNTL    TSC2301_REG(2, 0)
+#define TSC2301_REG_ADCVOL     TSC2301_REG(2, 1)
+#define TSC2301_REG_DACVOL     TSC2301_REG(2, 2)
+#define TSC2301_REG_BPVOL      TSC2301_REG(2, 3)
+#define TSC2301_REG_KEYCTL     TSC2301_REG(2, 4)
+#define TSC2301_REG_PD_MISC    TSC2301_REG(2, 5)
+#define TSC2301_REG_GPIO       TSC2301_REG(2, 6)
+#define TSC2301_REG_ADCLKCFG   TSC2301_REG(2, 27)
+
+#define TSC2301_REG_PD_MISC_APD                (1 << 15)
+#define TSC2301_REG_PD_MISC_AVPD       (1 << 14)
+#define TSC2301_REG_PD_MISC_ABPD       (1 << 13)
+#define TSC2301_REG_PD_MISC_HAPD       (1 << 12)
+#define TSC2301_REG_PD_MISC_MOPD       (1 << 11)
+#define TSC2301_REG_PD_MISC_DAPD       (1 << 10)
+#define TSC2301_REG_PD_MISC_ADPDL      (1 << 9)
+#define TSC2301_REG_PD_MISC_ADPDR      (1 << 8)
+#define TSC2301_REG_PD_MISC_PDSTS      (1 << 7)
+#define TSC2301_REG_PD_MISC_MIBPD      (1 << 6)
+
+/* I2S sample rate */
+#define TSC2301_I2S_SR_48000   0x00
+#define TSC2301_I2S_SR_44100   0x01
+#define TSC2301_I2S_SR_32000   0x02
+#define TSC2301_I2S_SR_24000   0x03
+#define TSC2301_I2S_SR_22050   0x04
+#define TSC2301_I2S_SR_16000   0x05
+#define TSC2301_I2S_SR_12000   0x06
+#define TSC2301_I2S_SR_11050   0x07
+#define TSC2301_I2S_SR_8000    0x08
+
+/* 16-bit, MSB-first. DAC Right-Justified, ADC Left-Justified */
+#define TSC2301_I2S_FORMAT0    0x00
+/* 20-bit, MSB-first. DAC Right-Justified, ADC Left-Justified */
+#define TSC2301_I2S_FORMAT1    0x01
+/* 20-bit, MSB-first. DAC Left-Justified, ADC Left-Justified */
+#define TSC2301_I2S_FORMAT2    0x02
+/* 20-bit, MSB-first */
+#define TSC2301_I2S_FORMAT3    0x03
+
+/* Master Clock Ratio */
+#define TSC2301_MCLK_256xFS    0x00 /* default */
+#define TSC2301_MCLK_384xFS    0x01
+#define TSC2301_MCLK_512xFS    0x02
+
+
+extern u16 tsc2301_read_reg(struct tsc2301 *tsc, int reg);
+extern void tsc2301_write_reg(struct tsc2301 *tsc, int reg, u16 val);
+extern void tsc2301_write_kbc(struct tsc2301 *tsc, int val);
+extern void tsc2301_write_pll(struct tsc2301 *tsc, int pll_n, int pll_a,
+                             int pll_pdc, int pct_e, int pll_o);
+extern void tsc2301_read_buf(struct tsc2301 *tsc, int reg, u16 *buf, int len);
+
+#define TSC2301_DECL_MOD(module)                                       \
+extern int  tsc2301_##module##_init(struct tsc2301 *tsc,               \
+                          struct tsc2301_platform_data *pdata);        \
+extern void tsc2301_##module##_exit(struct tsc2301 *tsc);              \
+extern void tsc2301_##module##_prep_for_clk_stop(struct tsc2301 *tsc); \
+extern void tsc2301_##module##_cont_after_clk_stop(struct tsc2301 *tsc);\
+extern int  tsc2301_##module##_suspend(struct tsc2301 *tsc);           \
+extern void tsc2301_##module##_resume(struct tsc2301 *tsc);
+
+#define TSC2301_DECL_EMPTY_MOD(module)                                 \
+static inline int tsc2301_##module##_init(struct tsc2301 *tsc,         \
+                          struct tsc2301_platform_data *pdata)         \
+{                                                                      \
+       return 0;                                                       \
+}                                                                      \
+static inline void tsc2301_##module##_exit(struct tsc2301 *tsc) {}     \
+static inline void tsc2301_##module##_prep_for_clk_stop                        \
+                                       (struct tsc2301 *tsc) {}        \
+static inline void tsc2301_##module##_cont_after_clk_stop              \
+                                       (struct tsc2301 *tsc) {}        \
+static inline int  tsc2301_##module##_suspend(struct tsc2301 *tsc)     \
+{                                                                      \
+       return 0;                                                       \
+}                                                                      \
+static inline void tsc2301_##module##_resume(struct tsc2301 *tsc) {}
+
+#ifdef CONFIG_SPI_TSC2301_KEYPAD
+TSC2301_DECL_MOD(kp)
+#else
+TSC2301_DECL_EMPTY_MOD(kp)
+#endif
+
+#ifdef CONFIG_SPI_TSC2301_TOUCHSCREEN
+TSC2301_DECL_MOD(ts)
+#else
+TSC2301_DECL_EMPTY_MOD(ts)
+#endif
+
+#ifdef CONFIG_SPI_TSC2301_AUDIO
+TSC2301_DECL_MOD(mixer)
+extern void tsc2301_mixer_set_power(struct device *tsc_dev, int dac, int adc);
+
+struct snd_card;
+extern int tsc2301_mixer_register_controls(struct device *tsc_dev,
+                                          struct snd_card *card);
+#else
+TSC2301_DECL_EMPTY_MOD(mixer)
+#endif
+
+extern void tsc2301_enable_mclk(struct device *tsc_dev);
+extern void tsc2301_disable_mclk(struct device *tsc_dev);
+
+#endif
diff --git a/include/linux/usb/musb.h b/include/linux/usb/musb.h
new file mode 100644 (file)
index 0000000..e1902df
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * This is used to for host and peripheral modes of the driver for
+ * Inventra (Multidrop) Highspeed Dual-Role Controllers:  (M)HDRC.
+ *
+ * Board initialization should put one of these into dev->platform_data,
+ * probably on some platform_device named "musb_hdrc".  It encapsulates
+ * key configuration differences between boards.
+ */
+
+/* The USB role is defined by the connector used on the board, so long as
+ * standards are being followed.  (Developer boards sometimes won't.)
+ */
+enum musb_mode {
+       MUSB_UNDEFINED = 0,
+       MUSB_HOST,              /* A or Mini-A connector */
+       MUSB_PERIPHERAL,        /* B or Mini-B connector */
+       MUSB_OTG                /* Mini-AB connector */
+};
+
+struct musb_hdrc_platform_data {
+       /* MUSB_HOST, MUSB_PERIPHERAL, or MUSB_OTG */
+       u8              mode;
+
+       /* (HOST or OTG) switch VBUS on/off */
+       int             (*set_vbus)(struct device *dev, int is_on);
+
+       /* (HOST or OTG) mA/2 power supplied on (default = 8mA) */
+       u8              power;
+
+       /* (PERIPHERAL) mA/2 max power consumed (default = 100mA) */
+       u8              min_power;
+
+       /* (HOST or OTG) msec/2 after VBUS on till power good */
+       u8              potpgt;
+
+       /* TBD:  chip defaults should probably go someplace else,
+        * e.g. number of tx/rx endpoints, etc
+        */
+       unsigned        multipoint:1;
+
+       /* Power the device on or off */
+       int             (*set_power)(int state);
+};
+
+
+/* TUSB 6010 support */
+
+#define        TUSB6010_OSCCLK_60      16667   /* psec/clk @ 60.0 MHz */
+#define        TUSB6010_REFCLK_24      41667   /* psec/clk @ 24.0 MHz XI */
+#define        TUSB6010_REFCLK_19      52633   /* psec/clk @ 19.2 MHz CLKIN */
+
+#ifdef CONFIG_ARCH_OMAP2
+
+extern int __init tusb6010_setup_interface(
+               struct musb_hdrc_platform_data *data,
+               unsigned ps_refclk, unsigned waitpin,
+               unsigned async_cs, unsigned sync_cs,
+               unsigned irq, unsigned dmachan);
+
+extern int tusb6010_platform_retime(unsigned is_refclk);
+
+#endif /* OMAP2 */
index c770e1a4e882289f66ae0e54451ba186f09c03d2..981d7aa5bb0424aafc1ed4e9e64fd0e3f285d681 100644 (file)
 
 #define __LOG_BUF_LEN  (1 << CONFIG_LOG_BUF_SHIFT)
 
+#ifdef        CONFIG_DEBUG_LL
+extern void printascii(char *);
+#endif
+
 /* printk's without a loglevel use this.. */
 #define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
 
@@ -445,12 +449,23 @@ static void zap_locks(void)
        init_MUTEX(&console_sem);
 }
 
-#if defined(CONFIG_PRINTK_TIME)
-static int printk_time = 1;
-#else
 static int printk_time = 0;
-#endif
-module_param(printk_time, int, S_IRUGO | S_IWUSR);
+
+#ifdef CONFIG_PRINTK_TIME
+
+/*
+ * Initialize printk time. Note that on some systems sched_clock()
+ * does not work until timer is initialized.
+ */
+static int __init printk_time_init(void)
+{
+       printk_time = 1;
+
+       return 0;
+}
+subsys_initcall(printk_time_init);
+
+#else
 
 static int __init printk_time_setup(char *str)
 {
@@ -462,6 +477,8 @@ static int __init printk_time_setup(char *str)
 
 __setup("time", printk_time_setup);
 
+#endif
+
 __attribute__((weak)) unsigned long long printk_clock(void)
 {
        return sched_clock();
@@ -537,6 +554,10 @@ asmlinkage int vprintk(const char *fmt, va_list args)
        /* Emit the output into the temporary buffer */
        printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);
 
+#ifdef CONFIG_DEBUG_LL
+       printascii(printk_buf);
+#endif
+
        /*
         * Copy the output into log_buf.  If the caller didn't provide
         * appropriate log level tags, we insert them here
index 2e4a5e0d16db3726755dea8c8930f35138927395..4dc323f908955bf72d61f9fc11eeb1f42280eb41 100644 (file)
@@ -33,4 +33,57 @@ config SND_PXA2XX_AC97
          Say Y or M if you want to support any AC97 codec attached to
          the PXA2xx AC97 interface.
 
+config SND_OMAP_AIC23
+       tristate "OMAP AIC23 alsa driver (osk5912)"
+       depends on ARCH_OMAP && SND
+       select SND_PCM
+       select I2C
+       select I2C_OMAP if ARCH_OMAP
+       select OMAP_MCBSP
+       select SENSORS_TLV320AIC23
+       help
+         Say Y here if you have a OSK platform board
+         and want to use its AIC23 audio chip.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-omap-aic23.
+         
+config SND_OMAP_TSC2101
+       tristate "OMAP TSC2101 alsa driver"
+       depends on ARCH_OMAP && SND
+       select SND_PCM
+         select OMAP_TSC2101
+         select OMAP_UWIRE if ARCH_OMAP
+        select OMAP_MCBSP
+       help
+         Say Y here if you have a OMAP platform board
+         and want to use its TSC2101 audio chip. Driver has
+         been tested with H2 and iPAQ h6300.
+         To compile this driver as a module, choose M here: the module
+         will be called snd-omap-tsc2101.
+
+config SND_SX1
+       tristate "Siemens SX1 Egold alsa driver"
+       depends on ARCH_OMAP && SND
+       select SND_PCM
+       select OMAP_MCBSP
+       help
+         Say Y here if you have a OMAP310 based Siemens SX1.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-omap-sx1.
+
+config SND_OMAP_TSC2102
+       tristate "OMAP TSC2102 alsa driver"
+       depends on ARCH_OMAP && SND
+       select SND_PCM
+       select TSC2102
+       help
+         Say Y here if you have an OMAP platform board
+         and want to use its TSC2102 audio chip.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-omap-tsc2102.
+
 endmenu
index 4ef6dd00c6eeafb9916378ad7098b642a309a0cc..bd12f53404a6c1c975db9754381bdc14096c532c 100644 (file)
@@ -13,3 +13,5 @@ snd-pxa2xx-pcm-objs           := pxa2xx-pcm.o
 
 obj-$(CONFIG_SND_PXA2XX_AC97)  += snd-pxa2xx-ac97.o
 snd-pxa2xx-ac97-objs           := pxa2xx-ac97.o
+
+obj-$(CONFIG_SND) += omap/
diff --git a/sound/arm/omap/Makefile b/sound/arm/omap/Makefile
new file mode 100644 (file)
index 0000000..c6bebac
--- /dev/null
@@ -0,0 +1,15 @@
+#
+## Makefile for ALSA OMAP
+#
+#
+obj-$(CONFIG_SND_OMAP_AIC23) += snd-omap-alsa-aic23.o
+snd-omap-alsa-aic23-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-aic23.o omap-alsa-aic23-mixer.o
+
+obj-$(CONFIG_SND_OMAP_TSC2101) += snd-omap-alsa-tsc2101.o
+snd-omap-alsa-tsc2101-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-tsc2101.o omap-alsa-tsc2101-mixer.o
+
+obj-$(CONFIG_SND_OMAP_TSC2102) += snd-omap-alsa-tsc2102.o
+snd-omap-alsa-tsc2102-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-tsc2102.o omap-alsa-tsc2102-mixer.o
+
+obj-$(CONFIG_SND_SX1) += snd-omap-alsa-sx1.o
+snd-omap-alsa-sx1-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-sx1.o omap-alsa-sx1-mixer.o
diff --git a/sound/arm/omap/omap-alsa-aic23-mixer.c b/sound/arm/omap/omap-alsa-aic23-mixer.c
new file mode 100644 (file)
index 0000000..b4332fe
--- /dev/null
@@ -0,0 +1,495 @@
+/*
+ * sound/arm/omap/omap-alsa-aic23-mixer.c
+ *
+ * Alsa Driver Mixer for generic codecs for omap boards
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Written by David Cohen, Daniel Petrini
+ *            {david.cohen, daniel.petrini}@indt.org.br
+ *
+ * Based on es1688_lib.c,
+ * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.
+ *
+ * History:
+ *
+ * 2005-08-02   INdT Kernel Team - Alsa mixer driver for omap osk.
+ *                             Creation of new file omap-alsa-mixer.c.
+ *                             Initial version with aic23 codec for osk5912
+ */
+
+#include <sound/driver.h>
+#include <asm/arch/aic23.h>
+
+#include <asm/arch/omap-alsa.h>
+#include "omap-alsa-aic23.h"
+#include <sound/initval.h>
+#include <sound/control.h>
+
+MODULE_AUTHOR("David Cohen, Daniel Petrini - INdT");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("OMAP Alsa mixer driver for ALSA");
+
+/*
+ * Codec dependent region
+ */
+
+/* Codec AIC23 */
+#if defined(CONFIG_SENSORS_TLV320AIC23) || defined (CONFIG_SENSORS_TLV320AIC23_MODULE)
+
+extern void audio_aic23_write(u8, u16);
+
+#define MIXER_NAME                  "Mixer AIC23"
+#define SND_OMAP_WRITE(reg, val)     audio_aic23_write(reg, val)
+
+#endif
+
+/* Callback Functions */
+#define OMAP_BOOL(xname, xindex, reg, reg_index, mask, invert) \
+{ \
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .index = xindex, \
+       .info = snd_omap_info_bool, \
+       .get = snd_omap_get_bool, \
+       .put = snd_omap_put_bool, \
+       .private_value = reg | (reg_index << 8) | (invert << 10) | (mask << 12) \
+}
+
+#define OMAP_MUX(xname, reg, reg_index, mask) \
+{ \
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .info = snd_omap_info_mux, \
+       .get = snd_omap_get_mux, \
+       .put = snd_omap_put_mux, \
+       .private_value = reg | (reg_index << 8) | (mask << 10) \
+}
+
+#define OMAP_SINGLE(xname, xindex, reg, reg_index, reg_val, mask) \
+{\
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .index = xindex, \
+       .info = snd_omap_info_single, \
+       .get = snd_omap_get_single, \
+       .put = snd_omap_put_single, \
+       .private_value = reg | (reg_val << 8) | (reg_index << 16) | (mask << 18) \
+}
+
+#define OMAP_DOUBLE(xname, xindex, left_reg, right_reg, reg_index, mask) \
+{\
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .index = xindex, \
+       .info = snd_omap_info_double, \
+       .get = snd_omap_get_double, \
+       .put = snd_omap_put_double, \
+       .private_value = left_reg | (right_reg << 8) | (reg_index << 16) | (mask << 18) \
+}
+
+/* Local Registers */
+enum snd_device_index {
+       PCM_INDEX = 0,
+       LINE_INDEX,
+       AAC_INDEX, /* Analog Audio Control: reg = l_reg */
+};
+
+struct {
+       u16 l_reg;
+       u16 r_reg;
+       u8 sw;
+} omap_regs[3];
+
+#ifdef CONFIG_PM
+struct {
+       u16 l_reg;
+       u16 r_reg;
+       u8 sw;
+} omap_pm_regs[3];
+#endif
+
+u16 snd_sidetone[6] = {
+       SIDETONE_18,
+       SIDETONE_12,
+       SIDETONE_9,
+       SIDETONE_6,
+       SIDETONE_0,
+       0
+};
+
+/* Begin Bool Functions */
+
+static int snd_omap_info_bool(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+
+       return 0;
+}
+
+static int snd_omap_get_bool(snd_kcontrol_t * kcontrol,
+                                snd_ctl_elem_value_t * ucontrol)
+{
+       int mic_index = (kcontrol->private_value >> 8) & 0x03;
+       u16 mask = (kcontrol->private_value >> 12) & 0xff;
+       int invert = (kcontrol->private_value >> 10) & 0x03;
+
+       if (invert)
+               ucontrol->value.integer.value[0] =
+                       (omap_regs[mic_index].l_reg & mask) ? 0 : 1;
+       else
+               ucontrol->value.integer.value[0] =
+                       (omap_regs[mic_index].l_reg & mask) ? 1 : 0;
+
+       return 0;
+}
+
+static int snd_omap_put_bool(snd_kcontrol_t * kcontrol,
+                                snd_ctl_elem_value_t * ucontrol)
+{
+       int mic_index = (kcontrol->private_value >> 8) & 0x03;
+       u16 mask = (kcontrol->private_value >> 12) & 0xff;
+       u16 reg = kcontrol->private_value & 0xff;
+       int invert = (kcontrol->private_value >> 10) & 0x03;
+
+       int changed = 1;
+
+       if (ucontrol->value.integer.value[0]) /* XOR */
+               if (invert)
+                       omap_regs[mic_index].l_reg &= ~mask;
+               else
+                       omap_regs[mic_index].l_reg |= mask;
+       else
+               if (invert)
+                       omap_regs[mic_index].l_reg |= mask;
+               else
+                       omap_regs[mic_index].l_reg &= ~mask;
+
+       SND_OMAP_WRITE(reg, omap_regs[mic_index].l_reg);
+
+       return changed;
+}
+
+/* End Bool Functions */
+
+/* Begin Mux Functions */
+
+static int snd_omap_info_mux(snd_kcontrol_t *kcontrol,
+                                snd_ctl_elem_info_t * uinfo)
+{
+       /* Mic = 0
+        * Line = 1 */
+       static char *texts[2] = { "Mic", "Line" };
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = 2;
+
+       if (uinfo->value.enumerated.item > 1)
+               uinfo->value.enumerated.item = 1;
+
+       strcpy(uinfo->value.enumerated.name,
+                       texts[uinfo->value.enumerated.item]);
+
+       return 0;
+}
+
+static int snd_omap_get_mux(snd_kcontrol_t * kcontrol,
+                               snd_ctl_elem_value_t * ucontrol)
+{
+       u16 mask = (kcontrol->private_value >> 10) & 0xff;
+       int mux_index = (kcontrol->private_value >> 8) & 0x03;
+
+       ucontrol->value.enumerated.item[0] =
+               (omap_regs[mux_index].l_reg & mask) ? 0 /* Mic */ : 1 /* Line */;
+
+       return 0;
+}
+
+static int snd_omap_put_mux(snd_kcontrol_t * kcontrol,
+                               snd_ctl_elem_value_t * ucontrol)
+{
+       u16 reg = kcontrol->private_value & 0xff;
+       u16 mask = (kcontrol->private_value >> 10) & 0xff;
+       int mux_index = (kcontrol->private_value >> 8) & 0x03;
+
+       int changed = 1;
+
+       if (!ucontrol->value.integer.value[0])
+               omap_regs[mux_index].l_reg |= mask; /* AIC23: Mic */
+       else
+               omap_regs[mux_index].l_reg &= ~mask; /* AIC23: Line */
+
+       SND_OMAP_WRITE(reg, omap_regs[mux_index].l_reg);
+
+       return changed;
+}
+
+/* End Mux Functions */
+
+/* Begin Single Functions */
+
+static int snd_omap_info_single(snd_kcontrol_t *kcontrol,
+                               snd_ctl_elem_info_t * uinfo)
+{
+       int mask = (kcontrol->private_value >> 18) & 0xff;
+       int reg_val = (kcontrol->private_value >> 8) & 0xff;
+
+       uinfo->type = mask ? SNDRV_CTL_ELEM_TYPE_INTEGER :
+                       SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = reg_val-1;
+
+       return 0;
+}
+
+static int snd_omap_get_single(snd_kcontrol_t * kcontrol,
+                                       snd_ctl_elem_value_t * ucontrol)
+{
+       u16 reg_val = (kcontrol->private_value >> 8) & 0xff;
+
+       ucontrol->value.integer.value[0] = snd_sidetone[reg_val];
+
+       return 0;
+}
+
+static int snd_omap_put_single(snd_kcontrol_t * kcontrol,
+                                       snd_ctl_elem_value_t * ucontrol)
+{
+       u16 reg_index = (kcontrol->private_value >> 16) & 0x03;
+       u16 mask = (kcontrol->private_value >> 18) & 0x1ff;
+       u16 reg = kcontrol->private_value & 0xff;
+       u16 reg_val = (kcontrol->private_value >> 8) & 0xff;
+
+       int changed = 0;
+
+       /* Volume */
+       if ((omap_regs[reg_index].l_reg !=
+                (ucontrol->value.integer.value[0] & mask))) {
+               changed = 1;
+
+               omap_regs[reg_index].l_reg &= ~mask;
+               omap_regs[reg_index].l_reg |=
+                       snd_sidetone[ucontrol->value.integer.value[0]];
+
+               snd_sidetone[reg_val] = ucontrol->value.integer.value[0];
+               SND_OMAP_WRITE(reg, omap_regs[reg_index].l_reg);
+       } else {
+               changed = 0;
+       }
+
+       return changed;
+}
+
+/* End Single Functions */
+
+/* Begin Double Functions */
+
+static int snd_omap_info_double(snd_kcontrol_t *kcontrol,
+                               snd_ctl_elem_info_t * uinfo)
+{
+       /* mask == 0 : Switch
+        * mask != 0 : Volume */
+       int mask = (kcontrol->private_value >> 18) & 0xff;
+
+       uinfo->type = mask ? SNDRV_CTL_ELEM_TYPE_INTEGER :
+                       SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = mask ? 2 : 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = mask ? mask : 1;
+
+       return 0;
+}
+
+static int snd_omap_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+       /* mask == 0 : Switch
+        * mask != 0 : Volume */
+       int mask = (kcontrol->private_value >> 18) & 0xff;
+       int vol_index = (kcontrol->private_value >> 16) & 0x03;
+
+       if (!mask) {
+               /* Switch */
+               ucontrol->value.integer.value[0] = omap_regs[vol_index].sw;
+       } else {
+               /* Volume */
+               ucontrol->value.integer.value[0] = omap_regs[vol_index].l_reg;
+               ucontrol->value.integer.value[1] = omap_regs[vol_index].r_reg;
+       }
+
+       return 0;
+}
+
+static int snd_omap_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+       /* mask == 0 : Switch
+        * mask != 0 : Volume */
+       int vol_index = (kcontrol->private_value >> 16) & 0x03;
+       int mask = (kcontrol->private_value >> 18) & 0xff;
+       int left_reg = kcontrol->private_value & 0xff;
+       int right_reg = (kcontrol->private_value >> 8) & 0xff;
+
+       int changed = 0;
+
+       if (!mask) {
+               /* Switch */
+               if (!ucontrol->value.integer.value[0]) {
+                       SND_OMAP_WRITE(left_reg, 0x00);
+                       SND_OMAP_WRITE(right_reg, 0x00);
+               } else {
+                       SND_OMAP_WRITE(left_reg, omap_regs[vol_index].l_reg);
+                       SND_OMAP_WRITE(right_reg, omap_regs[vol_index].r_reg);
+               }
+               changed = 1;
+               omap_regs[vol_index].sw = ucontrol->value.integer.value[0];
+       } else {
+               /* Volume */
+               if ((omap_regs[vol_index].l_reg != (ucontrol->value.integer.value[0] & mask)) ||
+                       (omap_regs[vol_index].r_reg != (ucontrol->value.integer.value[1] & mask))) {
+                       changed = 1;
+
+                       omap_regs[vol_index].l_reg &= ~mask;
+                       omap_regs[vol_index].r_reg &= ~mask;
+                       omap_regs[vol_index].l_reg |=
+                               (ucontrol->value.integer.value[0] & mask);
+                       omap_regs[vol_index].r_reg |=
+                               (ucontrol->value.integer.value[1] & mask);
+                       if (omap_regs[vol_index].sw) {
+                               /* write to registers only if sw is actived */
+                               SND_OMAP_WRITE(left_reg, omap_regs[vol_index].l_reg);
+                               SND_OMAP_WRITE(right_reg, omap_regs[vol_index].r_reg);
+                       }
+               }
+               else {
+                       changed = 0;
+               }
+       }
+
+       return changed;
+}
+
+/* End Double Functions */
+
+static snd_kcontrol_new_t snd_omap_controls[] = {
+       OMAP_DOUBLE("PCM Playback Switch", 0, LEFT_CHANNEL_VOLUME_ADDR, RIGHT_CHANNEL_VOLUME_ADDR,
+                    PCM_INDEX, 0x00),
+       OMAP_DOUBLE("PCM Playback Volume", 0, LEFT_CHANNEL_VOLUME_ADDR, RIGHT_CHANNEL_VOLUME_ADDR,
+                    PCM_INDEX, OUTPUT_VOLUME_MASK),
+       OMAP_BOOL("Line Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, BYPASS_ON, 0),
+       OMAP_DOUBLE("Line Capture Switch", 0, LEFT_LINE_VOLUME_ADDR, RIGHT_LINE_VOLUME_ADDR,
+                    LINE_INDEX, 0x00),
+       OMAP_DOUBLE("Line Capture Volume", 0, LEFT_LINE_VOLUME_ADDR, RIGHT_LINE_VOLUME_ADDR,
+                        LINE_INDEX, INPUT_VOLUME_MASK),
+       OMAP_BOOL("Mic Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, STE_ENABLED, 0),
+       OMAP_SINGLE("Mic Playback Volume", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, 5, SIDETONE_MASK),
+       OMAP_BOOL("Mic Capture Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, MICM_MUTED, 1),
+       OMAP_BOOL("Mic Booster Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, MICB_20DB, 0),
+       OMAP_MUX("Capture Source", ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, INSEL_MIC),
+};
+
+#ifdef CONFIG_PM
+
+void snd_omap_suspend_mixer(void)
+{
+       /* Saves current values to wake-up correctly */
+       omap_pm_regs[LINE_INDEX].l_reg = omap_regs[LINE_INDEX].l_reg;
+       omap_pm_regs[LINE_INDEX].r_reg = omap_regs[LINE_INDEX].l_reg;
+       omap_pm_regs[LINE_INDEX].sw = omap_regs[LINE_INDEX].sw;
+
+       omap_pm_regs[AAC_INDEX].l_reg = omap_regs[AAC_INDEX].l_reg;
+
+       omap_pm_regs[PCM_INDEX].l_reg = omap_regs[PCM_INDEX].l_reg;
+       omap_pm_regs[PCM_INDEX].r_reg = omap_regs[PCM_INDEX].r_reg;
+       omap_pm_regs[PCM_INDEX].sw = omap_regs[PCM_INDEX].sw;
+}
+
+void snd_omap_resume_mixer(void)
+{
+       /* Line's saved values */
+       omap_regs[LINE_INDEX].l_reg = omap_pm_regs[LINE_INDEX].l_reg;
+       omap_regs[LINE_INDEX].r_reg = omap_pm_regs[LINE_INDEX].l_reg;
+       omap_regs[LINE_INDEX].sw = omap_pm_regs[LINE_INDEX].sw;
+       SND_OMAP_WRITE(LEFT_LINE_VOLUME_ADDR, omap_pm_regs[LINE_INDEX].l_reg);
+       SND_OMAP_WRITE(RIGHT_LINE_VOLUME_ADDR, omap_pm_regs[LINE_INDEX].l_reg);
+
+       /* Analog Audio Control's saved values */
+       omap_regs[AAC_INDEX].l_reg = omap_pm_regs[AAC_INDEX].l_reg;
+       SND_OMAP_WRITE(ANALOG_AUDIO_CONTROL_ADDR, omap_regs[AAC_INDEX].l_reg);
+
+       /* Headphone's saved values */
+       omap_regs[PCM_INDEX].l_reg = omap_pm_regs[PCM_INDEX].l_reg;
+       omap_regs[PCM_INDEX].r_reg = omap_pm_regs[PCM_INDEX].r_reg;
+       omap_regs[PCM_INDEX].sw = omap_pm_regs[PCM_INDEX].sw;
+       SND_OMAP_WRITE(LEFT_CHANNEL_VOLUME_ADDR, omap_pm_regs[PCM_INDEX].l_reg);
+       SND_OMAP_WRITE(RIGHT_CHANNEL_VOLUME_ADDR, omap_pm_regs[PCM_INDEX].r_reg);
+}
+#endif
+
+void snd_omap_init_mixer(void)
+{
+       u16 vol_reg;
+
+       /* Line's default values */
+       omap_regs[LINE_INDEX].l_reg = DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK;
+       omap_regs[LINE_INDEX].r_reg = DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK;
+       omap_regs[LINE_INDEX].sw = 0;
+       SND_OMAP_WRITE(LEFT_LINE_VOLUME_ADDR, DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK);
+       SND_OMAP_WRITE(RIGHT_LINE_VOLUME_ADDR, DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK);
+
+       /* Analog Audio Control's default values */
+       omap_regs[AAC_INDEX].l_reg = DEFAULT_ANALOG_AUDIO_CONTROL;
+
+       /* Headphone's default values */
+       vol_reg = LZC_ON;
+       vol_reg &= ~OUTPUT_VOLUME_MASK;
+       vol_reg |= DEFAULT_OUTPUT_VOLUME;
+       omap_regs[PCM_INDEX].l_reg = DEFAULT_OUTPUT_VOLUME;
+       omap_regs[PCM_INDEX].r_reg = DEFAULT_OUTPUT_VOLUME;
+       omap_regs[PCM_INDEX].sw = 1;
+       SND_OMAP_WRITE(LEFT_CHANNEL_VOLUME_ADDR, vol_reg);
+       SND_OMAP_WRITE(RIGHT_CHANNEL_VOLUME_ADDR, vol_reg);
+}
+
+int snd_omap_mixer(struct snd_card_omap_codec *chip)
+{
+       snd_card_t *card;
+       unsigned int idx;
+       int err;
+
+       snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
+
+       card = chip->card;
+
+       strcpy(card->mixername, MIXER_NAME);
+
+       /* Registering alsa mixer controls */
+       for (idx = 0; idx < ARRAY_SIZE(snd_omap_controls); idx++)
+               if ((err = snd_ctl_add(card,
+                       snd_ctl_new1(&snd_omap_controls[idx], chip))) < 0)
+                       return err;
+
+       return 0;
+}
diff --git a/sound/arm/omap/omap-alsa-aic23.c b/sound/arm/omap/omap-alsa-aic23.c
new file mode 100644 (file)
index 0000000..b483961
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * arch/arm/mach-omap1/omap-alsa-aic23.c
+ * 
+ * Alsa codec Driver for AIC23 chip on OSK5912 platform board
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Written by Daniel Petrini, David Cohen, Anderson Briglia
+ *            {daniel.petrini, david.cohen, anderson.briglia}@indt.org.br
+ *
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ * 
+ * Based in former alsa driver for osk and oss driver
+ *
+ * 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.
+ */
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <linux/clk.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/aic23.h>
+
+#include <asm/arch/omap-alsa.h>
+#include "omap-alsa-aic23.h"
+
+static struct clk *aic23_mclk = 0;
+
+/* aic23 related */
+static const struct aic23_samplerate_reg_info
+ rate_reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
+       {4000, 0x06, 1},                /*  4000 */
+       {8000, 0x06, 0},                /*  8000 */
+       {16000, 0x0C, 1},               /* 16000 */
+       {22050, 0x11, 1},               /* 22050 */
+       {24000, 0x00, 1},               /* 24000 */
+       {32000, 0x0C, 0},               /* 32000 */
+       {44100, 0x11, 0},               /* 44100 */
+       {48000, 0x00, 0},               /* 48000 */
+       {88200, 0x1F, 0},               /* 88200 */
+       {96000, 0x0E, 0},               /* 96000 */
+};
+
+/*
+ * Hardware capabilities
+ */
+ /*
+ * DAC USB-mode sampling rates (MCLK = 12 MHz)
+ * The rates and rate_reg_into MUST be in the same order
+ */
+static unsigned int rates[] = {
+       4000, 8000, 16000, 22050,
+       24000, 32000, 44100,
+       48000, 88200, 96000,
+};
+
+static snd_pcm_hw_constraint_list_t aic23_hw_constraints_rates = {
+       .count = ARRAY_SIZE(rates),
+       .list = rates,
+       .mask = 0,
+};
+
+static snd_pcm_hardware_t aic23_snd_omap_alsa_playback = {
+       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),      
+       .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+       .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+                 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+                 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+                 SNDRV_PCM_RATE_KNOT),
+       .rate_min = 8000,
+       .rate_max = 96000,
+       .channels_min = 2,
+       .channels_max = 2,
+       .buffer_bytes_max = 128 * 1024,
+       .period_bytes_min = 32,
+       .period_bytes_max = 8 * 1024,
+       .periods_min = 16,
+       .periods_max = 255,
+       .fifo_size = 0,
+};
+
+static snd_pcm_hardware_t aic23_snd_omap_alsa_capture = {
+       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+       .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+       .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+                 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+                 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+                 SNDRV_PCM_RATE_KNOT),
+       .rate_min = 8000,
+       .rate_max = 96000,
+       .channels_min = 2,
+       .channels_max = 2,
+       .buffer_bytes_max = 128 * 1024,
+       .period_bytes_min = 32,
+       .period_bytes_max = 8 * 1024,
+       .periods_min = 16,
+       .periods_max = 255,
+       .fifo_size = 0,
+};
+
+/*
+ * Codec/mcbsp init and configuration section
+ * codec dependent code.
+ */
+
+extern int aic23_write_value(u8 reg, u16 value);
+
+/* TLV320AIC23 is a write only device */
+void audio_aic23_write(u8 address, u16 data)
+{
+       aic23_write_value(address, data);
+}
+EXPORT_SYMBOL_GPL(audio_aic23_write);
+
+/*
+ * Sample rate changing
+ */
+void aic23_set_samplerate(long rate)
+{
+       u8 count = 0;
+       u16 data = 0;
+
+       /* Fix the rate if it has a wrong value */
+       if (rate >= 96000)
+               rate = 96000;
+       else if (rate >= 88200)
+               rate = 88200;
+       else if (rate >= 48000)
+               rate = 48000;
+       else if (rate >= 44100)
+               rate = 44100;
+       else if (rate >= 32000)
+               rate = 32000;
+       else if (rate >= 24000)
+               rate = 24000;
+       else if (rate >= 22050)
+               rate = 22050;
+       else if (rate >= 16000)
+               rate = 16000;
+       else if (rate >= 8000)
+               rate = 8000;
+       else
+               rate = 4000;
+
+       /* Search for the right sample rate */
+       /* Verify what happens if the rate is not supported
+        * now it goes to 96Khz */
+       while ((rate_reg_info[count].sample_rate != rate) &&
+              (count < (NUMBER_SAMPLE_RATES_SUPPORTED - 1))) {
+               count++;
+       }
+
+       data = (rate_reg_info[count].divider << CLKIN_SHIFT) |
+           (rate_reg_info[count].control << BOSR_SHIFT) | USB_CLK_ON;
+
+       audio_aic23_write(SAMPLE_RATE_CONTROL_ADDR, data);
+}
+
+inline void aic23_configure(void)
+{
+       /* Reset codec */
+       audio_aic23_write(RESET_CONTROL_ADDR, 0);
+
+       /* Initialize the AIC23 internal state */
+
+       /* Analog audio path control, DAC selected, delete INSEL_MIC for line in */
+       audio_aic23_write(ANALOG_AUDIO_CONTROL_ADDR, DEFAULT_ANALOG_AUDIO_CONTROL);
+
+       /* Digital audio path control, de-emphasis control 44.1kHz */
+       audio_aic23_write(DIGITAL_AUDIO_CONTROL_ADDR, DEEMP_44K);
+
+       /* Digital audio interface, master/slave mode, I2S, 16 bit */
+#ifdef AIC23_MASTER
+       audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR,
+                         MS_MASTER | IWL_16 | FOR_DSP);
+#else
+       audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR, IWL_16 | FOR_DSP);
+#endif
+
+       /* Enable digital interface */
+       audio_aic23_write(DIGITAL_INTERFACE_ACT_ADDR, ACT_ON);
+}
+
+/*
+ *  Omap MCBSP clock configuration and Power Management
+ *  
+ *  Here we have some functions that allows clock to be enabled and
+ *   disabled only when needed. Besides doing clock configuration 
+ *   it allows turn on/turn off audio when necessary. 
+ */
+/*
+ * Do clock framework mclk search
+ */
+void aic23_clock_setup(void)
+{
+       aic23_mclk = clk_get(0, "mclk");
+}
+
+/*
+ * Do some sanity check, set clock rate, starts it and
+ *  turn codec audio on 
+ */
+int aic23_clock_on(void)
+{
+       uint    curRate;
+
+       if (clk_get_usecount(aic23_mclk) > 0) {
+               /* MCLK is already in use */
+               printk(KERN_WARNING
+                      "MCLK in use at %d Hz. We change it to %d Hz\n",
+                      (uint) clk_get_rate(aic23_mclk),
+                      CODEC_CLOCK);
+       }
+       curRate = (uint)clk_get_rate(aic23_mclk);
+       if (curRate != CODEC_CLOCK) {
+               if (clk_set_rate(aic23_mclk, CODEC_CLOCK)) {
+                       printk(KERN_ERR
+                              "Cannot set MCLK for AIC23 CODEC\n");
+                       return -ECANCELED;
+               }
+       }
+       clk_enable(aic23_mclk);
+
+       printk(KERN_DEBUG
+               "MCLK = %d [%d], usecount = %d\n",
+              (uint) clk_get_rate(aic23_mclk), CODEC_CLOCK,
+              clk_get_usecount(aic23_mclk));
+
+       /* Now turn the audio on */
+       audio_aic23_write(POWER_DOWN_CONTROL_ADDR, 
+                         ~DEVICE_POWER_OFF & ~OUT_OFF & ~DAC_OFF &
+                         ~ADC_OFF & ~MIC_OFF & ~LINE_OFF);     
+       return 0;
+}
+
+/*
+ * Do some sanity check, turn clock off and then turn
+ *  codec audio off
+ */
+int aic23_clock_off(void)
+{
+       if  (clk_get_usecount(aic23_mclk) > 0) { 
+               if (clk_get_rate(aic23_mclk) != CODEC_CLOCK) {
+                       printk(KERN_WARNING
+                              "MCLK for audio should be %d Hz. But is %d Hz\n",
+                              (uint) clk_get_rate(aic23_mclk),
+                              CODEC_CLOCK);
+               }
+
+               clk_disable(aic23_mclk);
+       }
+       
+       audio_aic23_write(POWER_DOWN_CONTROL_ADDR,
+                         DEVICE_POWER_OFF | OUT_OFF | DAC_OFF |
+                         ADC_OFF | MIC_OFF | LINE_OFF);        
+       return 0;
+}
+
+int aic23_get_default_samplerate(void)
+{
+       return DEFAULT_SAMPLE_RATE;
+}
+
+static int __devinit snd_omap_alsa_aic23_probe(struct platform_device *pdev)
+{
+       int     ret;
+       struct  omap_alsa_codec_config *codec_cfg;
+       
+       codec_cfg = pdev->dev.platform_data;
+       if (codec_cfg != NULL) {
+               codec_cfg->hw_constraints_rates = &aic23_hw_constraints_rates;
+               codec_cfg->snd_omap_alsa_playback  = &aic23_snd_omap_alsa_playback;
+               codec_cfg->snd_omap_alsa_capture  = &aic23_snd_omap_alsa_capture;               
+               codec_cfg->codec_configure_dev  = aic23_configure;
+               codec_cfg->codec_set_samplerate = aic23_set_samplerate;
+               codec_cfg->codec_clock_setup    = aic23_clock_setup;
+               codec_cfg->codec_clock_on       = aic23_clock_on;
+               codec_cfg->codec_clock_off      = aic23_clock_off;
+               codec_cfg->get_default_samplerate = aic23_get_default_samplerate;
+               ret     = snd_omap_alsa_post_probe(pdev, codec_cfg);
+       }
+       else
+               ret = -ENODEV;
+       return ret;
+}
+
+static struct platform_driver omap_alsa_driver = {
+       .probe          = snd_omap_alsa_aic23_probe,
+       .remove         = snd_omap_alsa_remove,
+       .suspend        = snd_omap_alsa_suspend,
+       .resume         = snd_omap_alsa_resume,
+       .driver = {
+               .name = "omap_alsa_mcbsp",
+       },
+};
+
+static int __init omap_alsa_aic23_init(void)
+{
+       int err;
+       
+       ADEBUG();
+       err = platform_driver_register(&omap_alsa_driver);
+
+       return err;
+}
+
+static void __exit omap_alsa_aic23_exit(void)
+{
+       ADEBUG();
+       
+       platform_driver_unregister(&omap_alsa_driver);
+}
+
+module_init(omap_alsa_aic23_init);
+module_exit(omap_alsa_aic23_exit);
diff --git a/sound/arm/omap/omap-alsa-aic23.h b/sound/arm/omap/omap-alsa-aic23.h
new file mode 100644 (file)
index 0000000..63907c4
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * sound/arm/omap-alsa-aic23.h
+ * 
+ * Alsa Driver for AIC23 codec on OSK5912 platform board
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Written by Daniel Petrini, David Cohen, Anderson Briglia
+ *            {daniel.petrini, david.cohen, anderson.briglia}@indt.org.br
+ *
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ *
+ * 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.
+ */
+
+#ifndef __OMAP_ALSA_AIC23_H
+#define __OMAP_ALSA_AIC23_H
+
+#include <sound/driver.h>
+#include <asm/arch/dma.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <asm/arch/mcbsp.h>
+
+/* Define to set the AIC23 as the master w.r.t McBSP */
+#define AIC23_MASTER
+
+#define NUMBER_SAMPLE_RATES_SUPPORTED  10
+
+/*
+ * AUDIO related MACROS
+ */
+#ifndef DEFAULT_BITPERSAMPLE
+#define DEFAULT_BITPERSAMPLE           16
+#endif
+
+#define DEFAULT_SAMPLE_RATE            44100
+#define CODEC_CLOCK                    12000000
+#define AUDIO_MCBSP                    OMAP_MCBSP1
+
+#define DEFAULT_OUTPUT_VOLUME          0x60
+#define DEFAULT_INPUT_VOLUME           0x00    /* 0 ==> mute line in */
+
+#define OUTPUT_VOLUME_MIN              LHV_MIN
+#define OUTPUT_VOLUME_MAX              LHV_MAX
+#define OUTPUT_VOLUME_RANGE            (OUTPUT_VOLUME_MAX - OUTPUT_VOLUME_MIN)
+#define OUTPUT_VOLUME_MASK             OUTPUT_VOLUME_MAX
+
+#define INPUT_VOLUME_MIN               LIV_MIN
+#define INPUT_VOLUME_MAX               LIV_MAX
+#define INPUT_VOLUME_RANGE             (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
+#define INPUT_VOLUME_MASK              INPUT_VOLUME_MAX
+
+#define SIDETONE_MASK                  0x1c0
+#define SIDETONE_0                     0x100
+#define SIDETONE_6                     0x000
+#define SIDETONE_9                     0x040
+#define SIDETONE_12                    0x080
+#define SIDETONE_18                    0x0c0
+
+#define DEFAULT_ANALOG_AUDIO_CONTROL  DAC_SELECTED | STE_ENABLED | BYPASS_ON | INSEL_MIC | MICB_20DB
+
+struct aic23_samplerate_reg_info {
+       u32 sample_rate;
+       u8 control;             /* SR3, SR2, SR1, SR0 and BOSR */
+       u8 divider;             /* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */
+};
+
+/*
+ * Defines codec specific functions pointers that can be used from the 
+ * common omap-alse base driver for all omap codecs. (tsc2101 and aic23)
+ */
+void define_codec_functions(struct omap_alsa_codec_config *codec_config);
+inline void aic23_configure(void);
+void aic23_set_samplerate(long rate);
+void aic23_clock_setup(void);
+int aic23_clock_on(void);
+int aic23_clock_off(void);
+int aic23_get_default_samplerate(void);
+
+#endif
diff --git a/sound/arm/omap/omap-alsa-dma.c b/sound/arm/omap/omap-alsa-dma.c
new file mode 100644 (file)
index 0000000..00359cb
--- /dev/null
@@ -0,0 +1,443 @@
+/*
+ * sound/arm/omap/omap-alsa-dma.c
+ *
+ * Common audio DMA handling for the OMAP processors
+ *
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * 
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
+ *
+ * This package 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.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ * 2004-06-07  Sriram Kannan   - Created new file from omap_audio_dma_intfc.c. This file
+ *                               will contain only the DMA interface and buffer handling of OMAP
+ *                               audio driver.
+ *
+ * 2004-06-22  Sriram Kannan   - removed legacy code (auto-init). Self-linking of DMA logical channel.
+ *
+ * 2004-08-12   Nishanth Menon  - Modified to integrate Audio requirements on 1610,1710 platforms
+ *
+ * 2004-11-01   Nishanth Menon  - 16xx platform code base modified to support multi channel chaining.
+ *
+ * 2004-12-15   Nishanth Menon  - Improved 16xx platform channel logic introduced - tasklets, queue handling updated
+ * 
+ * 2005-07-19  INdT Kernel Team - Alsa port. Creation of new file omap-alsa-dma.c based in
+ *                                omap-audio-dma-intfc.c oss file. Support for aic23 codec.
+ *                                Removal of buffer handling (Alsa does that), modifications
+ *     in dma handling and port to alsa structures.
+ *
+ * 2005-12-18   Dirk Behme      - Added L/R Channel Interchange fix as proposed by Ajaya Babu
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/pm.h>
+#include <linux/errno.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <linux/sysrq.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/semaphore.h>
+
+#include <asm/arch/dma.h>
+#include "omap-alsa-dma.h"
+
+#include <asm/arch/mcbsp.h>
+
+#include <asm/arch/omap-alsa.h>
+
+#undef DEBUG
+
+#define ERR(ARGS...) printk(KERN_ERR "{%s}-ERROR: ", __FUNCTION__);printk(ARGS);
+
+/* Channel Queue Handling macros
+ * tail always points to the current free entry
+ * Head always points to the current entry being used
+ * end is either head or tail
+ */
+
+#define AUDIO_QUEUE_INIT(s) s->dma_q_head = s->dma_q_tail = s->dma_q_count = 0;
+#define AUDIO_QUEUE_FULL(s) (nr_linked_channels == s->dma_q_count)
+#define AUDIO_QUEUE_LAST(s) (1 == s->dma_q_count)
+#define AUDIO_QUEUE_EMPTY(s) (0 == s->dma_q_count)
+#define __AUDIO_INCREMENT_QUEUE(end) ((end)=((end)+1) % nr_linked_channels)
+#define AUDIO_INCREMENT_HEAD(s) __AUDIO_INCREMENT_QUEUE(s->dma_q_head); s->dma_q_count--;
+#define AUDIO_INCREMENT_TAIL(s) __AUDIO_INCREMENT_QUEUE(s->dma_q_tail); s->dma_q_count++;
+
+/* DMA buffer fragmentation sizes */
+#define MAX_DMA_SIZE            0x1000000 /* todo: sync with alsa */
+//#define CUT_DMA_SIZE          0x1000
+/* TODO: To be moved to more appropriate location */
+#define DCSR_ERROR           0x3
+#define DCSR_END_BLOCK       (1 << 5)
+#define DCSR_SYNC_SET        (1 << 6)
+
+#define DCCR_FS              (1 << 5)
+#define DCCR_PRIO            (1 << 6)
+#define DCCR_EN              (1 << 7)
+#define DCCR_AI              (1 << 8)
+#define DCCR_REPEAT          (1 << 9)
+/* if 0 the channel works in 3.1 compatible mode*/
+#define DCCR_N31COMP         (1 << 10)
+#define DCCR_EP              (1 << 11)
+#define DCCR_SRC_AMODE_BIT   12
+#define DCCR_SRC_AMODE_MASK  (0x3<<12)
+#define DCCR_DST_AMODE_BIT   14
+#define DCCR_DST_AMODE_MASK  (0x3<<14)
+#define AMODE_CONST          0x0
+#define AMODE_POST_INC       0x1
+#define AMODE_SINGLE_INDEX   0x2
+#define AMODE_DOUBLE_INDEX   0x3
+
+/**************************** DATA STRUCTURES *****************************************/
+
+static spinlock_t dma_list_lock = SPIN_LOCK_UNLOCKED;
+
+static char nr_linked_channels = 1;
+
+/*********************************** MODULE SPECIFIC FUNCTIONS ***********************/
+
+static void sound_dma_irq_handler(int lch, u16 ch_status, void *data);
+static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
+                                    u_int dma_size);
+static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
+                                       u_int dma_size);
+static int audio_start_dma_chain(struct audio_stream * s);
+
+/***************************************************************************************
+ *
+ * DMA channel requests
+ *
+ **************************************************************************************/
+static void omap_sound_dma_link_lch(void *data)
+{
+
+       struct audio_stream *s = (struct audio_stream *) data;
+       int *chan = s->lch;
+       int i;
+
+       FN_IN;
+       if (s->linked) {
+               FN_OUT(1);
+               return;
+       }
+       for (i = 0; i < nr_linked_channels; i++) {
+               int cur_chan = chan[i];
+               int nex_chan =
+                   ((nr_linked_channels - 1 ==
+                     i) ? chan[0] : chan[i + 1]);
+               omap_dma_link_lch(cur_chan, nex_chan);
+       }
+       s->linked = 1;
+       FN_OUT(0);
+}
+
+int omap_request_alsa_sound_dma(int device_id, const char *device_name,
+                          void *data, int **channels)
+{
+       int i, err = 0;
+       int *chan = NULL;
+       FN_IN;
+       if (unlikely((NULL == channels) || (NULL == device_name))) {
+               BUG();
+               return -EPERM;
+       }
+       /* Try allocate memory for the num channels */
+       *channels =
+           (int *) kmalloc(sizeof(int) * nr_linked_channels, GFP_KERNEL);
+       chan = *channels;
+       if (NULL == chan) {
+               ERR("No Memory for channel allocs!\n");
+               FN_OUT(-ENOMEM);
+               return -ENOMEM;
+       }
+       spin_lock(&dma_list_lock);
+       for (i = 0; i < nr_linked_channels; i++) {
+               err = omap_request_dma(device_id, 
+                               device_name,
+                               sound_dma_irq_handler, 
+                               data,
+                               &chan[i]);
+
+               /* Handle Failure condition here */
+               if (err < 0) {
+                       int j;
+                       for (j = 0; j < i; j++) {
+                               omap_free_dma(chan[j]);
+                       }
+                       spin_unlock(&dma_list_lock);
+                       kfree(chan);
+                       *channels = NULL;
+                       ERR("Error in requesting channel %d=0x%x\n", i,
+                           err);
+                       FN_OUT(err);
+                       return err;
+               }
+       }
+
+       /* Chain the channels together */
+       if (!cpu_is_omap15xx())
+               omap_sound_dma_link_lch(data);
+
+       spin_unlock(&dma_list_lock);
+       FN_OUT(0);
+       return 0;
+}
+
+/***************************************************************************************
+ *
+ * DMA channel requests Freeing
+ *
+ **************************************************************************************/
+static void omap_sound_dma_unlink_lch(void *data)
+{
+       struct audio_stream *s = (struct audio_stream *)data;
+       int *chan = s->lch;
+       int i;
+
+       FN_IN;
+       if (!s->linked) {
+               FN_OUT(1);
+               return;
+       }
+       for (i = 0; i < nr_linked_channels; i++) {
+               int cur_chan = chan[i];
+               int nex_chan =
+                   ((nr_linked_channels - 1 ==
+                     i) ? chan[0] : chan[i + 1]);
+               omap_dma_unlink_lch(cur_chan, nex_chan);
+       }
+       s->linked = 0;
+       FN_OUT(0);
+}
+
+int omap_free_alsa_sound_dma(void *data, int **channels)
+{
+       int i;
+       int *chan = NULL;
+       
+       FN_IN;
+       if (unlikely(NULL == channels)) {
+               BUG();
+               return -EPERM;
+       }
+       if (unlikely(NULL == *channels)) {
+               BUG();
+               return -EPERM;
+       }
+       chan = (*channels);
+
+       if (!cpu_is_omap15xx())
+               omap_sound_dma_unlink_lch(data);
+       for (i = 0; i < nr_linked_channels; i++) {
+               int cur_chan = chan[i];
+               omap_stop_dma(cur_chan);
+               omap_free_dma(cur_chan);
+       }
+       kfree(*channels);
+       *channels = NULL;
+       FN_OUT(0);
+       return 0;
+}
+
+/***************************************************************************************
+ *
+ * Stop all the DMA channels of the stream
+ *
+ **************************************************************************************/
+void omap_stop_alsa_sound_dma(struct audio_stream *s)
+{
+       int *chan = s->lch;
+       int i;
+       
+       FN_IN;
+       if (unlikely(NULL == chan)) {
+               BUG();
+               return;
+       }
+       for (i = 0; i < nr_linked_channels; i++) {
+               int cur_chan = chan[i];
+               omap_stop_dma(cur_chan);
+       }
+       s->started = 0;
+       FN_OUT(0);
+       return;
+}
+/***************************************************************************************
+ *
+ * Clear any pending transfers
+ *
+ **************************************************************************************/
+void omap_clear_alsa_sound_dma(struct audio_stream * s)
+{
+       FN_IN;
+       omap_clear_dma(s->lch[s->dma_q_head]);
+       FN_OUT(0);
+       return;
+}
+
+/***************************************************************************************
+ *
+ * DMA related functions
+ *
+ **************************************************************************************/
+static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
+                                    u_int dma_size)
+{
+       int dt = 0x1;           /* data type 16 */
+       int cen = 32;           /* Stereo */
+       int cfn = dma_size / (2 * cen);
+       
+       FN_IN;
+       omap_set_dma_dest_params(channel, 0x05, 0x00,
+                                (OMAP1510_MCBSP1_BASE + 0x06),
+                                0, 0);
+       omap_set_dma_src_params(channel, 0x00, 0x01, dma_ptr,
+                               0, 0);
+       omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00, 0, 0);
+       FN_OUT(0);
+       return 0;
+}
+
+static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
+                                       u_int dma_size)
+{
+       int dt = 0x1;           /* data type 16 */
+       int cen = 32;           /* stereo */
+       int cfn = dma_size / (2 * cen);
+       
+       FN_IN;
+       omap_set_dma_src_params(channel, 0x05, 0x00,
+                               (OMAP1510_MCBSP1_BASE + 0x02),
+                               0, 0);
+       omap_set_dma_dest_params(channel, 0x00, 0x01, dma_ptr, 0, 0);
+       omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00, 0, 0);
+       FN_OUT(0);
+       return 0;
+}
+
+static int audio_start_dma_chain(struct audio_stream *s)
+{
+       int channel = s->lch[s->dma_q_head];
+       FN_IN;
+       if (!s->started) {
+               s->hw_stop();      /* stops McBSP Interface */
+               omap_start_dma(channel);
+               s->started = 1;
+               s->hw_start();     /* start McBSP interface */
+       } else if (cpu_is_omap310())
+               omap_start_dma(channel);
+       /* else the dma itself will progress forward with out our help */
+       FN_OUT(0);
+       return 0;
+}
+
+/* Start DMA -
+ * Do the initial set of work to initialize all the channels as required.
+ * We shall then initate a transfer
+ */
+int omap_start_alsa_sound_dma(struct audio_stream *s, 
+                       dma_addr_t dma_ptr, 
+                       u_int dma_size)
+{
+       int ret = -EPERM;
+
+       FN_IN;
+
+       if (unlikely(dma_size > MAX_DMA_SIZE)) {
+               ERR("DmaSoundDma: Start: overflowed %d-%d\n", dma_size,
+                   MAX_DMA_SIZE);
+               return -EOVERFLOW;
+       }
+       //if (AUDIO_QUEUE_FULL(s)) {
+       //      ret = -2;
+       //      goto sound_out;
+       //}
+
+       if (s->stream_id == SNDRV_PCM_STREAM_PLAYBACK) {
+               /*playback */
+               ret =
+                   audio_set_dma_params_play(s->lch[s->dma_q_tail],
+                                             dma_ptr, dma_size);
+       } else {
+               ret =
+                   audio_set_dma_params_capture(s->lch[s->dma_q_tail],
+                                                dma_ptr, dma_size);
+       }
+       if (ret != 0) {
+               ret = -3;       /* indicate queue full */
+               goto sound_out;
+       }
+       AUDIO_INCREMENT_TAIL(s);
+       ret = audio_start_dma_chain(s);
+       if (ret) {
+               ERR("dma start failed");
+       }
+      sound_out:
+       FN_OUT(ret);
+       return ret;
+
+}
+
+/* 
+ * ISRs have to be short and smart.. 
+ * Here we call alsa handling, after some error checking
+ */
+static void sound_dma_irq_handler(int sound_curr_lch, u16 ch_status,
+                                 void *data)
+{
+       int dma_status = ch_status;
+       struct audio_stream *s = (struct audio_stream *) data;
+       FN_IN;
+
+       /*
+        * some register checkings
+        */ 
+       DPRINTK("lch=%d,status=0x%x, dma_status=%d, data=%p\n",
+               sound_curr_lch, ch_status, dma_status, data);
+
+       if (dma_status & (DCSR_ERROR)) {
+               OMAP_DMA_CCR_REG(sound_curr_lch) &= ~DCCR_EN;
+               ERR("DCSR_ERROR!\n");
+               FN_OUT(-1);
+               return;
+       }
+
+       if (ch_status & DCSR_END_BLOCK) 
+               callback_omap_alsa_sound_dma(s);
+       FN_OUT(0);
+       return;
+}
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("Common DMA handling for Audio driver on OMAP processors");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(omap_start_alsa_sound_dma);
+EXPORT_SYMBOL(omap_clear_alsa_sound_dma);
+EXPORT_SYMBOL(omap_request_alsa_sound_dma);
+EXPORT_SYMBOL(omap_free_alsa_sound_dma);
+EXPORT_SYMBOL(omap_stop_alsa_sound_dma);
diff --git a/sound/arm/omap/omap-alsa-dma.h b/sound/arm/omap/omap-alsa-dma.h
new file mode 100644 (file)
index 0000000..1cecc8a
--- /dev/null
@@ -0,0 +1,53 @@
+/*  
+ * linux/sound/arm/omap/omap-alsa-dma.h
+ *
+ * Common audio DMA handling for the OMAP processors
+ *
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * 
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
+ *
+ * This package 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.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ * 
+ * 2004/08/12  Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms
+ *
+ * 2005/07/25  INdT Kernel Team - Renamed to omap-alsa-dma.h. Ported to Alsa.
+ */
+
+#ifndef __OMAP_AUDIO_ALSA_DMA_H
+#define __OMAP_AUDIO_ALSA_DMA_H
+
+/************************** INCLUDES *************************************/
+
+#include <asm/arch/omap-alsa.h>
+
+/************************** GLOBAL DATA STRUCTURES *********************************/
+
+typedef void (*dma_callback_t) (int lch, u16 ch_status, void *data);
+
+/**************** ARCH SPECIFIC FUNCIONS *******************************************/
+
+void omap_clear_alsa_sound_dma(struct audio_stream * s);
+
+int omap_request_alsa_sound_dma(int device_id, const char *device_name,
+                          void *data, int **channels);
+int omap_free_alsa_sound_dma(void *data, int **channels);
+
+int omap_start_alsa_sound_dma(struct audio_stream *s, dma_addr_t dma_ptr,  u_int dma_size);
+
+void omap_stop_alsa_sound_dma(struct audio_stream *s);
+
+#endif
diff --git a/sound/arm/omap/omap-alsa-sx1-mixer.c b/sound/arm/omap/omap-alsa-sx1-mixer.c
new file mode 100644 (file)
index 0000000..631b080
--- /dev/null
@@ -0,0 +1,470 @@
+/*
+ * sound/arm/omap/omap-alsa-sx1-mixer.c
+ *
+ * Alsa codec Driver for Siemens SX1 board.
+ * based on omap-alsa-tsc2101-mixer.c
+ *
+ *  Copyright (C) 2006 Vladimir Ananiev (vovan888 at gmail com)
+ *
+ * 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.
+ *
+ * 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.
+ *
+ */
+
+#include "omap-alsa-sx1.h"
+#include "omap-alsa-sx1-mixer.h"
+
+#include <linux/types.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+
+static int current_playback_target     = PLAYBACK_TARGET_LOUDSPEAKER;
+static int current_rec_src             = REC_SRC_SINGLE_ENDED_MICIN_HED;
+static int current_volume;     /* current volume, we cant read it */
+static int current_fm_volume;  /* current FM radio volume, we cant read it */
+
+/*
+ * Select SX1 recording source.
+ */
+static void set_record_source(int val)
+{
+       /* TODO Recording is done on McBSP2 and Mic only */
+       current_rec_src = val;
+}
+
+static int set_mixer_volume(int mixer_vol)
+{
+       int ret, i;
+       if ((mixer_vol < 0) || (mixer_vol > 9)) {
+               printk(KERN_ERR "Trying a bad mixer volume (%d)!\n", mixer_vol);
+               return -EPERM;
+       }
+       ret = (current_volume != mixer_vol);
+       current_volume = mixer_vol; /* set current volume, we cant read it */
+
+       i = cn_sx1snd_send(DAC_VOLUME_UPDATE, mixer_vol, 0);
+       if (i)
+               return i;
+       return ret;
+}
+
+static void set_loudspeaker_to_playback_target(void)
+{
+       /* TODO */
+       cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_SPEAKER, 0);
+
+       current_playback_target = PLAYBACK_TARGET_LOUDSPEAKER;
+}
+
+static void set_headphone_to_playback_target(void)
+{
+       /* TODO */
+       cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_HEADPHONE, 0);
+
+       current_playback_target = PLAYBACK_TARGET_HEADPHONE;
+}
+
+static void set_telephone_to_playback_target(void)
+{
+       /* TODO */
+       cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_PHONE, 0);
+
+       current_playback_target = PLAYBACK_TARGET_CELLPHONE;
+}
+
+static void set_telephone_to_record_source(void)
+{
+       cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_PHONE, 0);
+}
+
+static void init_playback_targets(void)
+{
+       set_loudspeaker_to_playback_target();
+       set_mixer_volume(DEFAULT_OUTPUT_VOLUME);
+}
+
+/*
+ * Initializes SX1 record source (to mic) and playback target (to loudspeaker)
+ */
+void snd_omap_init_mixer(void)
+{
+       /* Select headset to record source */
+       set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED);
+       /* Init loudspeaker as a default playback target*/
+       init_playback_targets();
+}
+
+/* ---------------------------------------------------------------------- */
+static int pcm_playback_target_info(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_info *uinfo)
+{
+       static char *texts[PLAYBACK_TARGET_COUNT] = {
+               "Loudspeaker", "Headphone", "Cellphone"
+       };
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = PLAYBACK_TARGET_COUNT;
+       if (uinfo->value.enumerated.item > PLAYBACK_TARGET_COUNT - 1) {
+               uinfo->value.enumerated.item = PLAYBACK_TARGET_COUNT - 1;
+       }
+       strcpy(uinfo->value.enumerated.name,
+                       texts[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+static int pcm_playback_target_get(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = current_playback_target;
+       return 0;
+}
+
+static int pcm_playback_target_put(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       int ret_val = 0;
+       int cur_val = ucontrol->value.integer.value[0];
+
+       if ((cur_val >= 0) &&
+               (cur_val < PLAYBACK_TARGET_COUNT) &&
+               (cur_val != current_playback_target)) {
+               if (cur_val == PLAYBACK_TARGET_LOUDSPEAKER) {
+                       set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED);
+                       set_loudspeaker_to_playback_target();
+               } else if (cur_val == PLAYBACK_TARGET_HEADPHONE) {
+                       set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HND);
+                       set_headphone_to_playback_target();
+               } else if (cur_val == PLAYBACK_TARGET_CELLPHONE) {
+                       set_telephone_to_record_source();
+                       set_telephone_to_playback_target();
+               }
+               ret_val = 1;
+       }
+       return ret_val;
+}
+
+/*-----------------------------------------------------------*/
+static int pcm_playback_volume_info(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 9;
+       return 0;
+}
+
+static int pcm_playback_volume_get(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = current_volume;
+       return 0;
+}
+
+static int pcm_playback_volume_put(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       return set_mixer_volume(ucontrol->value.integer.value[0]);
+}
+
+static int pcm_playback_switch_info(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+static int pcm_playback_switch_get(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = 1;
+       return 0;
+}
+
+static int pcm_playback_switch_put(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       return 0;
+}
+
+/* ----------------------------------------------------------- */
+
+static int headset_playback_volume_info(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 9;
+       return 0;
+}
+
+static int headset_playback_volume_get(struct snd_kcontrol *kcontrol,
+                                               struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0]        = current_volume;
+       return 0;
+}
+
+static int headset_playback_volume_put(struct snd_kcontrol *kcontrol,
+                                               struct snd_ctl_elem_value *ucontrol)
+{
+       return set_mixer_volume(ucontrol->value.integer.value[0]);
+}
+
+static int headset_playback_switch_info(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+static int headset_playback_switch_get(struct snd_kcontrol *kcontrol,
+                                               struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = 1;
+       return 0;
+}
+
+static int headset_playback_switch_put(struct snd_kcontrol *kcontrol,
+                                               struct snd_ctl_elem_value *ucontrol)
+{
+       /* mute/unmute headset */
+#if 0
+       return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+                               TSC2101_HEADSET_GAIN_CTRL,
+                               15);
+#endif
+       return 0;
+}
+/* ----------------------------------------------------------- */
+static int fmradio_playback_volume_info(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 9;
+       return 0;
+}
+
+static int fmradio_playback_volume_get(struct snd_kcontrol *kcontrol,
+                                               struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = current_fm_volume;
+       return 0;
+}
+
+static int fmradio_playback_volume_put(struct snd_kcontrol *kcontrol,
+                                               struct snd_ctl_elem_value *ucontrol)
+{
+       int ret = current_fm_volume != ucontrol->value.integer.value[0];
+       int i;
+       current_fm_volume = ucontrol->value.integer.value[0];
+       i = cn_sx1snd_send(DAC_FMRADIO_OPEN, current_fm_volume, 0);
+       if (i)
+               return i;
+       return ret;
+}
+
+static int fmradio_playback_switch_info(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+static int fmradio_playback_switch_get(struct snd_kcontrol *kcontrol,
+                                               struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = 1;
+       return 0;
+}
+
+static int fmradio_playback_switch_put(struct snd_kcontrol *kcontrol,
+                                               struct snd_ctl_elem_value *ucontrol)
+{
+       /* mute/unmute FM radio */
+       if (ucontrol->value.integer.value[0])
+               cn_sx1snd_send(DAC_FMRADIO_OPEN, current_fm_volume, 0);
+       else
+               cn_sx1snd_send(DAC_FMRADIO_CLOSE, 0, 0);
+
+       return 0;
+}
+/* ----------------------------------------------------------- */
+static int cellphone_input_switch_info(struct snd_kcontrol *kcontrol,
+                                               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+static int cellphone_input_switch_get(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = 1;
+       return 0;
+}
+
+static int cellphone_input_switch_put(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+#if 0
+       return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+                               TSC2101_BUZZER_GAIN_CTRL, 15);
+#endif
+       return 0;
+}
+/* ----------------------------------------------------------- */
+
+static int buzzer_input_switch_info(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+static int buzzer_input_switch_get(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = 1;
+       return 0;
+}
+
+static int buzzer_input_switch_put(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+#if 0
+       return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+                               TSC2101_BUZZER_GAIN_CTRL, 6);
+#endif
+       return 0;
+}
+/*-----------------------------------------------------------*/
+
+static struct snd_kcontrol_new egold_control[] __devinitdata = {
+       {
+               .name   = "Playback Playback Route",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = pcm_playback_target_info,
+               .get    = pcm_playback_target_get,
+               .put    = pcm_playback_target_put,
+       }, {
+               .name   = "Master Playback Volume",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = pcm_playback_volume_info,
+               .get    = pcm_playback_volume_get,
+               .put    = pcm_playback_volume_put,
+       }, {
+               .name   = "Master Playback Switch",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = pcm_playback_switch_info,
+               .get    = pcm_playback_switch_get,
+               .put    = pcm_playback_switch_put,
+       }, {
+               .name   = "Headset Playback Volume",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 1,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = headset_playback_volume_info,
+               .get    = headset_playback_volume_get,
+               .put    = headset_playback_volume_put,
+       }, {
+               .name   = "Headset Playback Switch",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 1,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = headset_playback_switch_info,
+               .get    = headset_playback_switch_get,
+               .put    = headset_playback_switch_put,
+       }, {
+               .name   = "FM Playback Volume",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 2,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = fmradio_playback_volume_info,
+               .get    = fmradio_playback_volume_get,
+               .put    = fmradio_playback_volume_put,
+       }, {
+               .name   = "FM Playback Switch",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 2,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = fmradio_playback_switch_info,
+               .get    = fmradio_playback_switch_get,
+               .put    = fmradio_playback_switch_put,
+       }, {
+               .name   = "Cellphone Input Switch",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = cellphone_input_switch_info,
+               .get    = cellphone_input_switch_get,
+               .put    = cellphone_input_switch_put,
+       }, {
+               .name   = "Buzzer Input Switch",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = buzzer_input_switch_info,
+               .get    = buzzer_input_switch_get,
+               .put    = buzzer_input_switch_put,
+       }
+};
+
+#ifdef CONFIG_PM
+void snd_omap_suspend_mixer(void)
+{
+}
+
+void snd_omap_resume_mixer(void)
+{
+       snd_omap_init_mixer();
+}
+#endif
+
+int snd_omap_mixer(struct snd_card_omap_codec *egold)
+{
+       int i = 0;
+       int err = 0;
+
+       if (!egold)
+               return -EINVAL;
+
+       for (i=0; i < ARRAY_SIZE(egold_control); i++) {
+               err = snd_ctl_add(egold->card,
+                               snd_ctl_new1(&egold_control[i], egold->card));
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
diff --git a/sound/arm/omap/omap-alsa-sx1-mixer.h b/sound/arm/omap/omap-alsa-sx1-mixer.h
new file mode 100644 (file)
index 0000000..686b81c
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * sound/arm/omap/omap-alsa-sx1-mixer.h
+ *
+ * Alsa codec Driver for Siemens SX1 board.
+ * based on omap-alsa-tsc2101-mixer.c
+ *
+ *  Copyright (C) 2006 Vladimir Ananiev (vovan888 at gmail com)
+ *
+ *
+ * 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.
+ *
+ * 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.
+ *
+ */
+
+#ifndef OMAPALSASX1MIXER_H_
+#define OMAPALSASX1MIXER_H_
+
+#include "omap-alsa-dma.h"
+
+#define PLAYBACK_TARGET_COUNT          0x03
+#define PLAYBACK_TARGET_LOUDSPEAKER    0x00
+#define PLAYBACK_TARGET_HEADPHONE      0x01
+#define PLAYBACK_TARGET_CELLPHONE      0x02
+
+/* following are used for register 03h Mixer PGA control bits
+   D7-D5 for selecting record source */
+#define REC_SRC_TARGET_COUNT           0x08
+#define REC_SRC_SINGLE_ENDED_MICIN_HED 0x00 /* oss code referred to MIXER_LINE */
+#define REC_SRC_SINGLE_ENDED_MICIN_HND 0x01 /* oss code referred to MIXER_MIC */
+#define REC_SRC_SINGLE_ENDED_AUX1      0x02
+#define REC_SRC_SINGLE_ENDED_AUX2      0x03
+#define REC_SRC_MICIN_HED_AND_AUX1     0x04
+#define REC_SRC_MICIN_HED_AND_AUX2     0x05
+#define REC_SRC_MICIN_HND_AND_AUX1     0x06
+#define REC_SRC_MICIN_HND_AND_AUX2     0x07
+
+#define DEFAULT_OUTPUT_VOLUME 5        /* default output volume to dac dgc */
+#define DEFAULT_INPUT_VOLUME  2        /* default record volume */
+
+#endif
diff --git a/sound/arm/omap/omap-alsa-sx1.c b/sound/arm/omap/omap-alsa-sx1.c
new file mode 100644 (file)
index 0000000..eadae68
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * Alsa codec Driver for Siemens SX1 board.
+ * based on omap-alsa-tsc2101.c        and cn_test.c example by Evgeniy Polyakov
+ *
+ * Copyright (C) 2006 Vladimir Ananiev (vovan888 at gmail com)
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/soundcard.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <asm/io.h>
+#include <asm/arch/mcbsp.h>
+
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/gpio.h>
+
+#include <asm/arch/omap-alsa.h>
+#include "omap-alsa-sx1.h"
+
+#include <linux/connector.h>
+
+/* Connector implementation */
+static struct cb_id cn_sx1snd_id = { CN_IDX_SX1SND, CN_VAL_SX1SND };
+static char cn_sx1snd_name[] = "cn_sx1snd";
+
+static void cn_sx1snd_callback(void *data)
+{
+       struct cn_msg *msg = (struct cn_msg *)data;
+
+       printk("%s: %lu: idx=%x, val=%x, seq=%u, ack=%u, len=%d: %s.\n",
+                       __func__, jiffies, msg->id.idx, msg->id.val,
+                       msg->seq, msg->ack, msg->len, (char *)msg->data);
+}
+
+/* Send IPC message to sound server */
+int cn_sx1snd_send(unsigned int cmd, unsigned int arg1, unsigned int arg2)
+{
+       struct cn_msg *m;
+       unsigned short data[3];
+       int err;
+
+       m = kzalloc(sizeof(*m) + sizeof(data), gfp_any());
+       if (!m)
+               return -1;
+
+       memcpy(&m->id, &cn_sx1snd_id, sizeof(m->id));
+       m->seq = 1;
+       m->len = sizeof(data);
+
+       data[0] = (unsigned short)cmd;
+       data[1] = (unsigned short)arg1;
+       data[2] = (unsigned short)arg2;
+
+       memcpy(m + 1, data, m->len);
+
+       err = cn_netlink_send(m, CN_IDX_SX1SND, gfp_any());
+       snd_printd("sent= %02X %02X %02X, err=%d\n", cmd,arg1,arg2,err);
+       kfree(m);
+
+       if (err == -ESRCH)
+               return -1;      /* there are no listeners on socket */
+       return 0;
+}
+
+/* Hardware capabilities
+ *
+ * DAC USB-mode sampling rates (MCLK = 12 MHz)
+ * The rates and rate_reg_into MUST be in the same order
+ */
+static unsigned int rates[] = {
+        8000, 11025, 12000,
+        16000, 22050, 24000,
+        32000, 44100, 48000,
+};
+
+static snd_pcm_hw_constraint_list_t egold_hw_constraints_rates = {
+       .count  = ARRAY_SIZE(rates),
+       .list   = rates,
+       .mask   = 0,
+};
+
+static snd_pcm_hardware_t egold_snd_omap_alsa_playback = {
+       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+       .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+       .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+                 SNDRV_PCM_RATE_16000 |
+                 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+                 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                 SNDRV_PCM_RATE_KNOT),
+       .rate_min               = 8000,
+       .rate_max               = 48000,
+       .channels_min           = 2,
+       .channels_max           = 2,
+       .buffer_bytes_max       = 128 * 1024,
+       .period_bytes_min       = 32,
+       .period_bytes_max       = 8 * 1024,
+       .periods_min            = 16,
+       .periods_max            = 255,
+       .fifo_size              = 0,
+};
+
+static snd_pcm_hardware_t egold_snd_omap_alsa_capture = {
+       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+       .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+       .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+                 SNDRV_PCM_RATE_16000 |
+                 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+                 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                 SNDRV_PCM_RATE_KNOT),
+       .rate_min               = 8000,
+       .rate_max               = 48000,
+       .channels_min           = 2,
+       .channels_max           = 2,
+       .buffer_bytes_max       = 128 * 1024,
+       .period_bytes_min       = 32,
+       .period_bytes_max       = 8 * 1024,
+       .periods_min            = 16,
+       .periods_max            = 255,
+       .fifo_size              = 0,
+};
+
+static long current_rate = -1; /* current rate in egold format 0..8 */
+/*
+ * ALSA operations according to board file
+ */
+
+/*
+ * Sample rate changing
+ */
+static void egold_set_samplerate(long sample_rate)
+{
+       int egold_rate = 0;
+       int clkgdv = 0;
+       u16 srgr1, srgr2;
+
+       /* Set the sample rate */
+#if 0
+       /* fw15: 5005E490 - divs are different !!! */
+       clkgdv  = CODEC_CLOCK / (sample_rate * (DEFAULT_BITPERSAMPLE * 2 - 1));
+#endif
+       switch (sample_rate) {
+               case 8000:      clkgdv = 71; egold_rate = FRQ_8000; break;
+               case 11025:     clkgdv = 51; egold_rate = FRQ_11025; break;
+               case 12000:     clkgdv = 47; egold_rate = FRQ_12000; break;
+               case 16000:     clkgdv = 35; egold_rate = FRQ_16000; break;
+               case 22050:     clkgdv = 25; egold_rate = FRQ_22050; break;
+               case 24000:     clkgdv = 23; egold_rate = FRQ_24000; break;
+               case 32000:     clkgdv = 17; egold_rate = FRQ_32000; break;
+               case 44100:     clkgdv = 12; egold_rate = FRQ_44100; break;
+               case 48000:     clkgdv = 11; egold_rate = FRQ_48000; break;
+       }
+
+       srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+       srgr2 = ((FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)));
+
+       OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR2, srgr2);
+       OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR1, srgr1);
+       current_rate = egold_rate;
+       snd_printd("set samplerate=%ld\n", sample_rate);
+
+}
+
+static void egold_configure(void)
+{
+}
+
+/*
+ * Omap MCBSP clock and Power Management configuration
+ *
+ * Here we have some functions that allows clock to be enabled and
+ * disabled only when needed. Besides doing clock configuration
+ * it allows turn on/turn off audio when necessary.
+ */
+
+/*
+ * Do clock framework mclk search
+ */
+static void egold_clock_setup(void)
+{
+       omap_request_gpio(OSC_EN);
+       omap_set_gpio_direction(OSC_EN, 0); /* output */
+       snd_printd("\n");
+}
+
+/*
+ * Do some sanity check, set clock rate, starts it and turn codec audio on
+ */
+static int egold_clock_on(void)
+{
+       omap_set_gpio_dataout(OSC_EN, 1);
+       egold_set_samplerate(44100); /* TODO */
+       cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_SPEAKER, 0);
+       cn_sx1snd_send(DAC_OPEN_DEFAULT, current_rate , 4);
+       snd_printd("\n");
+       return 0;
+}
+
+/*
+ * Do some sanity check, turn clock off and then turn codec audio off
+ */
+static int egold_clock_off(void)
+{
+       cn_sx1snd_send(DAC_CLOSE, 0 , 0);
+       cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_PHONE, 0);
+       omap_set_gpio_dataout(OSC_EN, 0);
+       snd_printd("\n");
+       return 0;
+}
+
+static int egold_get_default_samplerate(void)
+{
+       snd_printd("\n");
+       return DEFAULT_SAMPLE_RATE;
+}
+
+static int __init snd_omap_alsa_egold_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct omap_alsa_codec_config *codec_cfg;
+
+       codec_cfg = pdev->dev.platform_data;
+       if (!codec_cfg)
+               return -ENODEV;
+
+       codec_cfg->hw_constraints_rates = &egold_hw_constraints_rates;
+       codec_cfg->snd_omap_alsa_playback= &egold_snd_omap_alsa_playback;
+       codec_cfg->snd_omap_alsa_capture  = &egold_snd_omap_alsa_capture;
+       codec_cfg->codec_configure_dev  = egold_configure;
+       codec_cfg->codec_set_samplerate = egold_set_samplerate;
+       codec_cfg->codec_clock_setup    = egold_clock_setup;
+       codec_cfg->codec_clock_on       = egold_clock_on;
+       codec_cfg->codec_clock_off      = egold_clock_off;
+       codec_cfg->get_default_samplerate = egold_get_default_samplerate;
+       ret = snd_omap_alsa_post_probe(pdev, codec_cfg);
+
+       snd_printd("\n");
+       return ret;
+}
+
+static struct platform_driver omap_alsa_driver = {
+       .probe          = snd_omap_alsa_egold_probe,
+       .remove         = snd_omap_alsa_remove,
+       .suspend        = snd_omap_alsa_suspend,
+       .resume         = snd_omap_alsa_resume,
+       .driver = {
+               .name = "omap_alsa_mcbsp",
+       },
+};
+
+static int __init omap_alsa_egold_init(void)
+{
+       int retval;
+
+       retval = cn_add_callback(&cn_sx1snd_id, cn_sx1snd_name, cn_sx1snd_callback);
+       if (retval)
+               printk(KERN_WARNING "cn_sx1snd failed to register\n");
+       return platform_driver_register(&omap_alsa_driver);
+}
+
+static void __exit omap_alsa_egold_exit(void)
+{
+       cn_del_callback(&cn_sx1snd_id);
+       platform_driver_unregister(&omap_alsa_driver);
+}
+
+module_init(omap_alsa_egold_init);
+module_exit(omap_alsa_egold_exit);
diff --git a/sound/arm/omap/omap-alsa-sx1.h b/sound/arm/omap/omap-alsa-sx1.h
new file mode 100644 (file)
index 0000000..af7a409
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Based on omap-alsa-tsc2101.h
+ *
+ * Alsa Driver for Siemens SX1.
+ * Copyright (C) 2006 Vladimir Ananiev (vovan888 at gmail com)
+ *
+ * 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.
+ */
+
+#ifndef OMAP_ALSA_SX1_H_
+#define OMAP_ALSA_SX1_H_
+
+#include <linux/types.h>
+
+#define NUMBER_SAMPLE_RATES_SUPPORTED  9
+
+/*
+ * AUDIO related MACROS
+ */
+#ifndef DEFAULT_BITPERSAMPLE
+#define DEFAULT_BITPERSAMPLE           16
+#endif
+
+#define DEFAULT_SAMPLE_RATE            44100
+/* fw15: 18356000 */
+#define CODEC_CLOCK                    18359000
+/* McBSP for playing music */
+#define AUDIO_MCBSP                    OMAP_MCBSP1
+/* McBSP for record/play audio from phone and mic */
+#define AUDIO_MCBSP_PCM                        OMAP_MCBSP2
+/* gpio pin for enable/disable clock */
+#define OSC_EN                         2
+
+/* Send IPC message to sound server */
+extern int cn_sx1snd_send(unsigned int cmd, unsigned int arg1, unsigned int arg2);
+/* cmd for IPC_GROUP_DAC */
+#define DAC_VOLUME_UPDATE              0
+#define DAC_SETAUDIODEVICE             1
+#define DAC_OPEN_RING                  2
+#define DAC_OPEN_DEFAULT               3
+#define DAC_CLOSE                      4
+#define DAC_FMRADIO_OPEN               5
+#define DAC_FMRADIO_CLOSE              6
+#define DAC_PLAYTONE                   7
+/* cmd for IPC_GROUP_PCM */
+#define PCM_PLAY                       (0+8)
+#define PCM_RECORD                     (1+8)
+#define PCM_CLOSE                      (2+8)
+
+/* for DAC_SETAUDIODEVICE */
+#define SX1_DEVICE_SPEAKER             0
+#define SX1_DEVICE_HEADPHONE           4
+#define SX1_DEVICE_PHONE               3
+/* frequencies for MdaDacOpenDefaultL, MdaDacOpenRingL */
+#define FRQ_8000       0
+#define FRQ_11025              1
+#define FRQ_12000              2
+#define FRQ_16000              3
+#define FRQ_22050              4
+#define FRQ_24000              5
+#define FRQ_32000              6
+#define FRQ_44100              7
+#define FRQ_48000              8
+
+#endif
diff --git a/sound/arm/omap/omap-alsa-tsc2101-mixer.c b/sound/arm/omap/omap-alsa-tsc2101-mixer.c
new file mode 100644 (file)
index 0000000..0f92266
--- /dev/null
@@ -0,0 +1,1095 @@
+/*
+ * sound/arm/omap/omap-alsa-tsc2101-mixer.c
+ * 
+ * Alsa Driver for TSC2101 codec for OMAP platform boards.
+ *
+ * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi> and 
+ *                  Everett Coleman II <gcc80x86@fuzzyneural.net>
+ *
+ * Board initialization code is based on the code in TSC2101 OSS driver.
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *     Written by Nishanth Menon and Sriram Kannan
+ * 
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.
+ *
+ * History:
+ *
+ * 2006-03-01   Mika Laitio - Mixer for the tsc2101 driver used in omap boards.
+ *             Can switch between headset and loudspeaker playback, 
+ *             mute and unmute dgc, set dgc volume. Record source switch,
+ *             keyclick, buzzer and headset volume and handset volume control 
+ *             are still missing.
+ *             
+ */
+#include "omap-alsa-tsc2101.h"
+#include "omap-alsa-tsc2101-mixer.h"
+
+#include <linux/types.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+
+//#define M_DPRINTK(ARGS...)  printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS)
+#define M_DPRINTK(ARGS...)             /* nop */
+
+#define CHECK_BIT(INDX, ARG) (((ARG) & TSC2101_BIT(INDX)) >> INDX)
+#define IS_UNMUTED(INDX, ARG) (((CHECK_BIT(INDX, ARG)) == 0))
+
+#define DGC_DALVL_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
+#define DGC_DARVL_EXTRACT(ARG) ((ARG & 0x007f))
+
+#define HGC_ADPGA_HED_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
+#define HNGC_ADPGA_HND_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
+#define BGC_ADPGA_BGC_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
+
+static int current_playback_target     = PLAYBACK_TARGET_LOUDSPEAKER;
+static int current_rec_src             = REC_SRC_SINGLE_ENDED_MICIN_HED;
+
+/* 
+ * Simplified write for the tsc2101 audio registers.
+ */
+inline void omap_tsc2101_audio_write(u8 address, u16 data)
+{
+       omap_tsc2101_write(PAGE2_AUDIO_CODEC_REGISTERS, address, data);
+}
+
+/* 
+ * Simplified read for the tsc2101 audio registers.
+ */
+inline u16 omap_tsc2101_audio_read(u8 address)
+{
+       return (omap_tsc2101_read(PAGE2_AUDIO_CODEC_REGISTERS, address));
+}
+
+/*
+ * For selecting tsc2101 recourd source.
+ */
+static void set_record_source(int val)
+{
+       u16     data;
+       
+       /* Mute Analog Sidetone
+        * Analog sidetone gain db?
+        * Input selected by MICSEL connected to ADC
+        */
+       data    = MPC_ASTMU | MPC_ASTG(0x45);
+       data    &= ~MPC_MICSEL(7); /* clear all MICSEL bits */
+       data    |= MPC_MICSEL(val);
+       data    |= MPC_MICADC;
+       omap_tsc2101_audio_write(TSC2101_MIXER_PGA_CTRL, data);
+       
+       current_rec_src = val;
+}
+
+/*
+ * Converts the Alsa mixer volume (0 - 100) to real 
+ * Digital Gain Control (DGC) value that can be written
+ * or read from the TSC2101 registry.
+ * 
+ * Note that the number "OUTPUT_VOLUME_MAX" is smaller than OUTPUT_VOLUME_MIN
+ * because DGC works as a volume decreaser. (The more bigger value is put
+ * to DGC, the more the volume of controlled channel is decreased)
+ * 
+ * In addition the TCS2101 chip would allow the maximum volume reduction be 63.5 DB
+ * but according to some tests user can not hear anything with this chip
+ * when the volume is set to be less than 25 db.
+ * Therefore this function will return a value that means 38.5 db (63.5 db - 25 db) 
+ * reduction in the channel volume, when mixer is set to 0.
+ * For mixer value 100, this will return a value that means 0 db volume reduction.
+ * ([mute_left_bit]0000000[mute_right_bit]0000000)
+*/
+int get_mixer_volume_as_dac_gain_control_volume(int vol)
+{
+       u16 retVal;
+
+       /* Convert 0 -> 100 volume to 0x7F(min) -> y(max) volume range */
+       retVal  = ((vol * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MAX;
+       /* invert the value for getting the proper range 0 min and 100 max */
+       retVal  = OUTPUT_VOLUME_MIN - retVal;
+       
+       return retVal;
+}
+
+/*
+ * Converts the Alsa mixer volume (0 - 100) to TSC2101 
+ * Digital Gain Control (DGC) volume. Alsa mixer volume 0
+ * is converted to value meaning the volume reduction of -38.5 db
+ * and Alsa mixer volume 100 is converted to value meaning the
+ * reduction of 0 db.
+ */
+int set_mixer_volume_as_dac_gain_control_volume(int mixerVolL, int mixerVolR) 
+{
+       u16 val;
+       int retVal;
+       int volL;
+       int volR;
+       
+       if ((mixerVolL < 0) || 
+           (mixerVolL > 100) ||
+           (mixerVolR < 0) ||
+           (mixerVolR > 100)) {
+               printk(KERN_ERR "Trying a bad mixer volume as dac gain control volume value, left (%d), right (%d)!\n", mixerVolL, mixerVolR);
+               return -EPERM;
+       }
+       M_DPRINTK("mixer volume left = %d, right = %d\n", mixerVolL, mixerVolR);        
+       volL    = get_mixer_volume_as_dac_gain_control_volume(mixerVolL);
+       volR    = get_mixer_volume_as_dac_gain_control_volume(mixerVolR);
+       
+       val     = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
+       /* keep the old mute bit settings */
+       val     &= ~(DGC_DALVL(OUTPUT_VOLUME_MIN) | DGC_DARVL(OUTPUT_VOLUME_MIN));
+       val     |= DGC_DALVL(volL) | DGC_DARVL(volR);
+       retVal  = 2;
+       if (retVal) {
+               omap_tsc2101_audio_write(TSC2101_DAC_GAIN_CTRL, val);
+       }
+       M_DPRINTK("to registry: left = %d, right = %d, total = %d\n", DGC_DALVL_EXTRACT(val), DGC_DARVL_EXTRACT(val), val);
+       return retVal;
+}
+
+/**
+ * If unmuteLeft/unmuteRight == 0  --> mute
+ * If unmuteLeft/unmuteRight == 1 --> unmute
+ */
+int dac_gain_control_unmute(int unmuteLeft, int unmuteRight)
+{
+       u16 val;
+       int count;
+
+       count   = 0;
+       val     = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
+       /* in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off, 0 --> on
+        * so if values are same, it's time to change the registry value.
+        */
+       if (unmuteLeft != IS_UNMUTED(15, val)) {
+               if (unmuteLeft == 0) {
+                       /* mute --> turn bit on */
+                       val     = val | DGC_DALMU;
+               }
+               else {
+                       /* unmute --> turn bit off */
+                       val     = val & ~DGC_DALMU;
+               }
+               count++;
+       } /* L */
+       if (unmuteRight != IS_UNMUTED(7, val)) {
+               if (unmuteRight == 0) {
+                       /* mute --> turn bit on */
+                       val     = val | DGC_DARMU;
+               }
+               else {
+                       /* unmute --> turn bit off */
+                       val     = val & ~DGC_DARMU;
+               }               
+               count++;
+       } /* R */
+       if (count) {
+               omap_tsc2101_audio_write(TSC2101_DAC_GAIN_CTRL, val);
+               M_DPRINTK("changed value, is_unmuted left = %d, right = %d\n", 
+                       IS_UNMUTED(15, val),
+                       IS_UNMUTED(7, val));
+       }
+       return count;   
+}
+
+/**
+ * unmute: 0 --> mute, 1 --> unmute
+ * page2RegIndx: Registry index in tsc2101 page2.
+ * muteBitIndx: Index number for the bit in registry that indicates whether muted or unmuted.
+ */
+int adc_pga_unmute_control(int unmute, int page2regIndx, int muteBitIndx)
+{
+       int count;
+       u16 val;
+       
+       count   = 0;
+       val     = omap_tsc2101_audio_read(page2regIndx);
+       /* in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off, 0 --> on
+        * so if the values are same, it's time to change the registry value...
+        */
+       if (unmute != IS_UNMUTED(muteBitIndx, val)) {
+               if (unmute == 0) {
+                       /* mute --> turn bit on */
+                       val     = val | TSC2101_BIT(muteBitIndx);
+               }
+               else {
+                       /* unmute --> turn bit off */
+                       val     = val & ~TSC2101_BIT(muteBitIndx);
+               }
+               M_DPRINTK("changed value, is_unmuted = %d\n", IS_UNMUTED(muteBitIndx, val));
+               count++;
+       }
+       if (count) {
+               omap_tsc2101_audio_write(page2regIndx, val);
+       }
+       return count;
+}
+
+/*
+ * Converts the DGC registry value read from the TSC2101 registry to 
+ * Alsa mixer volume format (0 - 100).
+ */
+int get_dac_gain_control_volume_as_mixer_volume(u16 vol) 
+{
+       u16 retVal;     
+
+       retVal  = OUTPUT_VOLUME_MIN - vol;
+       retVal  = ((retVal - OUTPUT_VOLUME_MAX) * 100) / OUTPUT_VOLUME_RANGE;
+       /* fix scaling error */
+       if ((retVal > 0) && (retVal < 100)) {
+               retVal++;
+       }
+       return retVal;
+}
+
+/*
+ * Converts the headset gain control volume (0 - 63.5 db)
+ * to Alsa mixer volume (0 - 100)
+ */
+int get_headset_gain_control_volume_as_mixer_volume(u16 registerVal) 
+{
+       u16 retVal;
+       
+       retVal  = ((registerVal * 100) / INPUT_VOLUME_RANGE);
+       return retVal;
+}
+
+/*
+ * Converts the handset gain control volume (0 - 63.5 db)
+ * to Alsa mixer volume (0 - 100)
+ */
+int get_handset_gain_control_volume_as_mixer_volume(u16 registerVal) 
+{
+       return get_headset_gain_control_volume_as_mixer_volume(registerVal);
+}
+
+/*
+ * Converts the Alsa mixer volume (0 - 100) to 
+ * headset gain control volume (0 - 63.5 db)
+ */
+int get_mixer_volume_as_headset_gain_control_volume(u16 mixerVal) 
+{
+       u16 retVal;
+       
+       retVal  = ((mixerVal * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;   
+       return retVal;
+}
+
+/*
+ * Writes Alsa mixer volume (0 - 100) to TSC2101 headset volume registry in
+ * a TSC2101 format. (0 - 63.5 db)
+ * In TSC2101 OSS driver this functionality was controlled with "SET_LINE" parameter.
+ */
+int set_mixer_volume_as_headset_gain_control_volume(int mixerVol) 
+{
+       int volume;
+       int retVal;
+       u16 val;
+
+       if (mixerVol < 0 || mixerVol > 100) {
+               M_DPRINTK("Trying a bad headset mixer volume value(%d)!\n", mixerVol);
+               return -EPERM;
+       }
+       M_DPRINTK("mixer volume = %d\n", mixerVol);
+       /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range */
+       /* NOTE: 0 is minimum volume and not mute */
+       volume  = get_mixer_volume_as_headset_gain_control_volume(mixerVol);    
+       val     = omap_tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL);
+       /* preserve the old mute settings */
+       val     &= ~(HGC_ADPGA_HED(INPUT_VOLUME_MAX));
+       val     |= HGC_ADPGA_HED(volume);
+       omap_tsc2101_audio_write(TSC2101_HEADSET_GAIN_CTRL, val);       
+       retVal  = 1;
+       
+       M_DPRINTK("to registry = %d\n", val);   
+       return retVal;
+}
+
+/*
+ * Writes Alsa mixer volume (0 - 100) to TSC2101 handset volume registry in
+ * a TSC2101 format. (0 - 63.5 db)
+ * In TSC2101 OSS driver this functionality was controlled with "SET_MIC" parameter.
+ */
+int set_mixer_volume_as_handset_gain_control_volume(int mixerVol) 
+{
+       int volume;
+       int retVal;
+       u16 val;        
+
+       if (mixerVol < 0 || mixerVol > 100) {
+               M_DPRINTK("Trying a bad mic mixer volume value(%d)!\n", mixerVol);
+               return -EPERM;
+       }
+       M_DPRINTK("mixer volume = %d\n", mixerVol);
+       /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range
+        * NOTE: 0 is minimum volume and not mute 
+        */
+       volume  = get_mixer_volume_as_headset_gain_control_volume(mixerVol);
+       val     = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL);
+       /* preserve the old mute settigns */
+       val     &= ~(HNGC_ADPGA_HND(INPUT_VOLUME_MAX));
+       val     |= HNGC_ADPGA_HND(volume);
+       omap_tsc2101_audio_write(TSC2101_HANDSET_GAIN_CTRL, val);
+       retVal  = 1;
+       
+       M_DPRINTK("to registry = %d\n", val);   
+       return retVal;
+}
+
+void set_loudspeaker_to_playback_target(void)
+{
+       /* power down SPK1, SPK2 and loudspeaker */
+       omap_tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL,
+                       CPC_SP1PWDN | CPC_SP2PWDN | CPC_LDAPWDF);       
+       /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled
+        * 1dB AGC hysteresis
+        * MICes bias 2V
+        */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
+
+       /* DAC left and right routed to SPK1/SPK2
+        * SPK1/SPK2 unmuted
+        * Keyclicks routed to SPK1/SPK2 */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_5, 
+                       AC5_DIFFIN |
+                       AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
+                       AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2);
+       
+       /* routing selected to SPK1 goes also to OUT8P/OUT8N. (loudspeaker)
+        * analog sidetone routed to loudspeaker
+        * buzzer pga routed to loudspeaker
+        * keyclick routing to loudspeaker
+        * cellphone input routed to loudspeaker
+        * mic selection (control register 04h/page2) routed to cell phone output (CP_OUT)
+        * routing selected for SPK1 goes also to cellphone output (CP_OUT)
+        * OUT8P/OUT8N (loudspeakers) unmuted (0 = unmuted)
+        * Cellphone output is not muted (0 = unmuted)
+        * Enable loudspeaker short protection control (0 = enable protection)
+        * VGND short protection control (0 = enable protection)
+        */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_6,
+                       AC6_SPL2LSK | AC6_AST2LSK | AC6_BUZ2LSK | AC6_KCL2LSK |
+                       AC6_CPI2LSK | AC6_MIC2CPO | AC6_SPL2CPO);
+       current_playback_target = PLAYBACK_TARGET_LOUDSPEAKER;
+}
+
+void set_headphone_to_playback_target(void)
+{
+       /* power down SPK1, SPK2 and loudspeaker */
+       omap_tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL,
+                       CPC_SP1PWDN | CPC_SP2PWDN | CPC_LDAPWDF);
+       /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */
+       /* 1dB AGC hysteresis */
+       /* MICes bias 2V */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
+                               
+       /* DAC left and right routed to SPK1/SPK2
+        * SPK1/SPK2 unmuted
+        * Keyclicks routed to SPK1/SPK2 */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_5,
+                       AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
+                       AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
+                       AC5_HDSCPTC);
+                       
+       /* OUT8P/OUT8N muted, CPOUT muted */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_6,
+                       AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC |
+                       AC6_VGNDSCPTC);
+       current_playback_target = PLAYBACK_TARGET_HEADPHONE;
+}
+
+void set_telephone_to_playback_target(void)
+{
+       /* 
+        * 0110 1101 0101 1100
+        * power down MICBIAS_HED, Analog sidetone, SPK2, DAC, 
+        * Driver virtual ground, loudspeaker. Values D2-d5 are flags.
+        */      
+       omap_tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL,
+                       CPC_MBIAS_HED | CPC_ASTPWD | CPC_SP2PWDN | CPC_DAPWDN |
+                       CPC_VGPWDN | CPC_LSPWDN);
+                       
+       /* 
+        * 0010 1010 0100 0000
+        * ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled
+        * 1dB AGC hysteresis
+        * MICes bias 2V
+        */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4,
+                       AC4_MB_HND | AC4_MB_HED(0) | AC4_AGCHYS(1) | 
+                       AC4_BISTPD | AC4_ASSTPD | AC4_DASTPD);
+       printk("set_telephone_to_playback_target(), TSC2101_AUDIO_CTRL_4 = %d\n", omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_4));
+                       
+       /* 
+        * 1110 0010 0000 0010
+        * DAC left and right routed to SPK1/SPK2
+        * SPK1/SPK2 unmuted
+        * keyclicks routed to SPK1/SPK2
+        */      
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_5,
+                       AC5_DIFFIN | AC5_DAC2SPK1(3) | 
+                       AC5_CPI2SPK1 | AC5_MUTSPK2);
+       
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_6,
+                       AC6_MIC2CPO | AC6_MUTLSPK | 
+                       AC6_LDSCPTC | AC6_VGNDSCPTC | AC6_CAPINTF);
+       current_playback_target = PLAYBACK_TARGET_CELLPHONE;
+}
+
+/*
+ * 1100 0101 1101 0000
+ * 
+ * #define MPC_ASTMU           TSC2101_BIT(15)
+ * #define MPC_ASTG(ARG)       (((ARG) & 0x7F) << 8)
+ * #define MPC_MICSEL(ARG)     (((ARG) & 0x07) << 5)
+ * #define MPC_MICADC          TSC2101_BIT(4)
+ * #define MPC_CPADC           TSC2101_BIT(3)
+ * #define MPC_ASTGF           (0x01)
+ */
+static void set_telephone_to_record_source(void)
+{
+       u16     val;
+       
+       /* 
+        * D0       = 0: 
+        *              --> AGC is off for handset input.
+        *              --> ADC PGA is controlled by the ADMUT_HDN + ADPGA_HND
+        *          (D15, D14-D8)
+        * D4 - D1  = 0000 
+        *              --> AGC time constant for handset input, 
+        *              attack time = 8 mc, decay time = 100 ms
+        * D7 - D5  = 000
+        *              --> AGC Target gain for handset input = -5.5 db
+        * D14 - D8 = 011 1100
+        *              --> ADC handset PGA settings = 60 = 30 db
+        * D15          = 0
+        *              --> Handset input ON (unmuted)
+        */
+       val     = 0x3c00;       // 0011 1100 0000 0000 = 60 = 30
+       omap_tsc2101_audio_write(TSC2101_HANDSET_GAIN_CTRL, val);
+       
+       /*
+        * D0           = 0
+        *              --> AGC is off for headset/Aux input
+        *              --> ADC headset/Aux PGA is contoller by ADMUT_HED + ADPGA_HED
+        *          (D15, D14-D8)
+        * D4 - D1      = 0000 
+        *              --> Agc constant for headset/Aux input,
+        *              attack time = 8 mc, decay time = 100 ms      
+        * D7 - D5      = 000
+        *              --> AGC target gain for headset input = -5.5 db
+        * D14 - D8 = 000 0000
+        *              --> Adc headset/AUX pga settings = 0 db
+        * D15          = 1
+        *              --> Headset/AUX input muted
+        * 
+        * Mute headset aux input
+        */
+       val     = 0x8000;       // 1000 0000 0000 0000
+       omap_tsc2101_audio_write(TSC2101_HEADSET_GAIN_CTRL, val);
+       set_record_source(REC_SRC_MICIN_HND_AND_AUX1);
+
+       // hacks start
+       /* D0           = flag, Headset/Aux or handset PGA flag
+        *              --> & with 1 (= 1 -->gain applied == pga register settings)
+        * D1           = 0, DAC channel PGA soft stepping control
+        *              --> 0.5 db change every WCLK
+        * D2           = flag, DAC right channel PGA flag
+        *              --> & with 1
+        * D3           = flag, DAC left channel PGA flag
+        *              -- > & with 1
+        * D7 - D4      = 0001, keyclick length
+        *              --> 4 periods key clicks
+        * D10 - D8 = 100, keyclick frequenzy
+        *              --> 1 kHz, 
+        * D11          = 0, Headset/Aux or handset soft stepping control
+        *              --> 0,5 db change every WCLK or ADWS
+        * D14 -D12 = 100, Keyclick applitude control
+        *              --> Medium amplitude
+        * D15          = 0, keyclick disabled
+        */
+       val     = omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_2);
+       val     = val & 0x441d;
+       val     = val | 0x4410; // D14, D10, D4 bits == 1
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_2, val);
+
+       /*
+        * D0           = 0     (reserved, write always 0)
+        * D1           = flag,
+        *                      --> & with 1
+        * D2 - D5      = 0000 (reserved, write always 0000)
+        * D6           = 1
+        *                      --> MICBIAS_HND = 2.0 v
+        * D8 - D7      = 00
+        *                      --> MICBIAS_HED = 3.3 v
+        * D10 - D9     = 01, 
+        *                      --> Mic AGC hysteric selection = 2 db
+        * D11          = 1, 
+        *                      --> Disable buzzer PGA soft stepping
+        * D12          = 0,
+        *                      --> Enable CELL phone PGA soft stepping control
+        * D13          = 1
+        *                      --> Disable analog sidetone soft stepping control
+        * D14          = 0
+        *                      --> Enable DAC PGA soft stepping control
+        * D15          = 0,
+        *                      --> Enable headset/Aux or Handset soft stepping control
+        */
+       val     = omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_4);
+       val     = val & 0x2a42; // 0010 1010 0100 0010
+       val     = val | 0x2a40; // bits D13, D11, D9, D6 == 1
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4, val);
+       printk("set_telephone_to_record_source(), TSC2101_AUDIO_CTRL_4 = %d\n", omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_4));
+       /*
+        * D0           = 0
+        *              --> reserved, write always = 0
+        * D1           = flag, read only
+        *              --> & with 1
+        * D5 - D2      = 1111, Buzzer input PGA settings
+        *              --> 0 db
+        * D6           = 1,
+        *              --> power down buzzer input pga
+        * D7           = flag, read only
+        *              --> & with 1
+        * D14 - D8     = 101 1101
+        *              --> 12 DB
+        * D15          = 0
+        *              --> power up cell phone input PGA
+        */
+       val     = omap_tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL);
+       val     = val & 0x5dfe;
+       val     = val | 0x5dfe; // bits, D14, D12, D11, D10, D8, D6, D5,D4,D3,D2
+       omap_tsc2101_audio_write(TSC2101_BUZZER_GAIN_CTRL, val);
+       
+       /* D6 - D0      = 000 1001
+        *              --> -4.5 db for DAC right channel volume control
+        * D7           = 1
+        *              -->  DAC right channel muted
+        * D14 - D8 = 000 1001
+        *              --> -4.5 db for DAC left channel volume control
+        * D15          = 1
+        *              --> DAC left channel muted
+        */
+       //val   = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
+       val     = 0x8989;
+       omap_tsc2101_audio_write(TSC2101_DAC_GAIN_CTRL, val);   
+       
+       /*  0000 0000 0100 0000
+        * 
+        * D1 - D0      = 0
+        *              --> GPIO 1 pin output is three stated
+        * D2           = 0
+        *              --> Disaple GPIO2 for CLKOUT mode
+        * D3           = 0
+        *              --> Disable GPUI1 for interrupt detection
+        * D4           = 0
+        *              --> Disable GPIO2 for headset detection interrupt
+        * D5           = reserved, always 0
+        * D7 - D6      = 01
+        *              --> 8 ms clitch detection
+        * D8           = reserved, write only 0
+        * D10 -D9      = 00
+        *              --> 16 ms de bouncing programmatitily 
+        *          for glitch detection during headset detection
+        * D11          = flag for button press
+        * D12          = flag for headset detection
+        * D14-D13      = 00
+        *              --> type of headset detected = 00 == no stereo headset deected
+        * D15          = 0
+        *              --> Disable headset detection
+        * 
+        * */
+       val     = 0x40;
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_7, val);    
+}
+
+/*
+ * Checks whether the headset is detected.
+ * If headset is detected, the type is returned. Type can be
+ *     0x01    = stereo headset detected
+ *     0x02    = cellurar headset detected
+ *     0x03    = stereo + cellurar headset detected
+ * If headset is not detected 0 is returned.
+ */
+u16 get_headset_detected(void)
+{
+       u16     curDetected;
+       u16     curType;
+       u16     curVal;
+       
+       curType = 0;    /* not detected */
+       curVal  = omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_7);
+       curDetected     = curVal & AC7_HDDETFL;
+       if (curDetected) {
+               printk("headset detected, checking type from %d \n", curVal);
+               curType = ((curVal & 0x6000) >> 13);
+               printk("headset type detected = %d \n", curType);
+       }
+       else {
+               printk("headset not detected\n");
+       }
+       return curType;
+}
+
+void init_playback_targets(void)
+{
+       u16     val;
+
+       set_loudspeaker_to_playback_target();
+       /* Left line input volume control
+        * = SET_LINE in the OSS driver
+        */
+       set_mixer_volume_as_headset_gain_control_volume(DEFAULT_INPUT_VOLUME);
+
+       /* Set headset to be controllable by handset mixer
+        * AGC enable for handset input
+        * Handset input not muted
+        */
+       val     = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL);
+       val     = val | HNGC_AGCEN_HND; 
+       val     = val & ~HNGC_ADMUT_HND;
+       omap_tsc2101_audio_write(TSC2101_HANDSET_GAIN_CTRL, val);       
+                       
+       /* mic input volume control
+        * SET_MIC in the OSS driver 
+        */
+       set_mixer_volume_as_handset_gain_control_volume(DEFAULT_INPUT_VOLUME);
+
+       /* Left/Right headphone channel volume control
+        * Zero-cross detect on
+        */
+       set_mixer_volume_as_dac_gain_control_volume(DEFAULT_OUTPUT_VOLUME, DEFAULT_OUTPUT_VOLUME);      
+       /* unmute */
+       dac_gain_control_unmute(1, 1);
+}
+
+/*
+ * Initializes tsc2101 recourd source (to line) and playback target (to loudspeaker)
+ */
+void snd_omap_init_mixer(void)
+{      
+       FN_IN;
+       
+       /* Headset/Hook switch detect enabled */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_7, AC7_DETECT);
+
+       /* Select headset to record source (MIC_INHED)*/
+       set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED);
+       /* Init loudspeaker as a default playback target*/
+       init_playback_targets();
+
+       FN_OUT(0);
+}
+
+static int __pcm_playback_target_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
+{
+       static char *texts[PLAYBACK_TARGET_COUNT] = {
+               "Loudspeaker", "Headphone", "Cellphone"
+       };
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = PLAYBACK_TARGET_COUNT;
+       if (uinfo->value.enumerated.item > PLAYBACK_TARGET_COUNT - 1) {
+               uinfo->value.enumerated.item = PLAYBACK_TARGET_COUNT - 1;
+       }
+       strcpy(uinfo->value.enumerated.name,
+               texts[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+static int __pcm_playback_target_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       ucontrol->value.integer.value[0] = current_playback_target;
+       return 0;
+}
+
+static int __pcm_playback_target_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       int     retVal;
+       int     curVal;
+       
+       retVal  = 0;
+       curVal  = ucontrol->value.integer.value[0];
+       if ((curVal >= 0) &&
+           (curVal < PLAYBACK_TARGET_COUNT) &&
+           (curVal != current_playback_target)) {              
+               if (curVal == PLAYBACK_TARGET_LOUDSPEAKER) {
+                       set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED);
+                       set_loudspeaker_to_playback_target();
+               }
+               else if (curVal == PLAYBACK_TARGET_HEADPHONE) {
+                       set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HND);
+                       set_headphone_to_playback_target();
+               }
+               else if (curVal == PLAYBACK_TARGET_CELLPHONE) {
+                       set_telephone_to_record_source();
+                       set_telephone_to_playback_target();
+               }
+               retVal  = 1;
+       }
+       return retVal;
+}      
+
+static int __pcm_playback_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count                    = 2;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 100;
+       return 0;
+}
+
+/*
+ * Alsa mixer interface function for getting the volume read from the DGC in a 
+ * 0 -100 alsa mixer format.
+ */
+static int __pcm_playback_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       u16 volL;
+       u16 volR;       
+       u16 val;
+       
+       val     = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
+       M_DPRINTK("registry value = %d!\n", val);
+       volL    = DGC_DALVL_EXTRACT(val);
+       volR    = DGC_DARVL_EXTRACT(val);
+       /* make sure that other bits are not on */
+       volL    = volL & ~DGC_DALMU;
+       volR    = volR & ~DGC_DARMU;
+
+       volL    = get_dac_gain_control_volume_as_mixer_volume(volL);
+       volR    = get_dac_gain_control_volume_as_mixer_volume(volR);
+       
+       ucontrol->value.integer.value[0]        = volL; /* L */
+       ucontrol->value.integer.value[1]        = volR; /* R */
+       
+       M_DPRINTK("mixer volume left = %ld, right = %ld\n", ucontrol->value.integer.value[0], ucontrol->value.integer.value[1]);
+       return 0;
+}
+
+static int __pcm_playback_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       return set_mixer_volume_as_dac_gain_control_volume(ucontrol->value.integer.value[0], 
+                                                       ucontrol->value.integer.value[1]);
+}
+
+static int __pcm_playback_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 2;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+/* 
+ * When DGC_DALMU (bit 15) is 1, the left channel is muted.
+ * When DGC_DALMU is 0, left channel is not muted.
+ * Same logic apply also for the right channel.
+ */
+static int __pcm_playback_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       u16 val = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
+       
+       ucontrol->value.integer.value[0]        = IS_UNMUTED(15, val);  // left
+       ucontrol->value.integer.value[1]        = IS_UNMUTED(7, val);   // right
+       return 0;
+}
+
+static int __pcm_playback_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       return dac_gain_control_unmute(ucontrol->value.integer.value[0], 
+                                       ucontrol->value.integer.value[1]);
+}
+
+static int __headset_playback_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 100;
+       return 0;
+}
+
+static int __headset_playback_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       u16 val;
+       u16 vol;
+       
+       val     = omap_tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL);
+       M_DPRINTK("registry value = %d\n", val);
+       vol     = HGC_ADPGA_HED_EXTRACT(val);
+       vol     = vol & ~HGC_ADMUT_HED;
+
+       vol     = get_headset_gain_control_volume_as_mixer_volume(vol);
+       ucontrol->value.integer.value[0]        = vol;
+       
+       M_DPRINTK("mixer volume returned = %ld\n", ucontrol->value.integer.value[0]);
+       return 0;
+}
+
+static int __headset_playback_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       return set_mixer_volume_as_headset_gain_control_volume(ucontrol->value.integer.value[0]);       
+}
+
+static int __headset_playback_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+/* When HGC_ADMUT_HED (bit 15) is 1, the headset is muted.
+ * When HGC_ADMUT_HED is 0, headset is not muted.
+ */
+static int __headset_playback_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       u16 val = omap_tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL);
+       ucontrol->value.integer.value[0]        = IS_UNMUTED(15, val);
+       return 0;
+}
+
+static int __headset_playback_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       // mute/unmute headset
+       return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+                               TSC2101_HEADSET_GAIN_CTRL,
+                               15);
+}
+
+static int __handset_playback_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 100;
+       return 0;
+}
+
+static int __handset_playback_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       u16 val;
+       u16 vol;
+       
+       val     = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL);
+       M_DPRINTK("registry value = %d\n", val);
+       vol     = HNGC_ADPGA_HND_EXTRACT(val);
+       vol     = vol & ~HNGC_ADMUT_HND;
+       vol     = get_handset_gain_control_volume_as_mixer_volume(vol);
+       ucontrol->value.integer.value[0]        = vol;
+       
+       M_DPRINTK("mixer volume returned = %ld\n", ucontrol->value.integer.value[0]);
+       return 0;
+}
+
+static int __handset_playback_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       return set_mixer_volume_as_handset_gain_control_volume(ucontrol->value.integer.value[0]);       
+}
+
+static int __handset_playback_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+/* When HNGC_ADMUT_HND (bit 15) is 1, the handset is muted.
+ * When HNGC_ADMUT_HND is 0, handset is not muted.
+ */
+static int __handset_playback_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       u16 val = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL);
+       ucontrol->value.integer.value[0]        = IS_UNMUTED(15, val);
+       return 0;
+}
+
+static int __handset_playback_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       // handset mute/unmute
+       return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+                               TSC2101_HANDSET_GAIN_CTRL,
+                               15);
+}
+
+static int __cellphone_input_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+/* When BGC_MUT_CP (bit 15) = 1, power down cellphone input pga.
+ * When BGC_MUT_CP = 0, power up cellphone input pga.
+ */
+static int __cellphone_input_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       u16 val = omap_tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL);
+       ucontrol->value.integer.value[0]        = IS_UNMUTED(15, val);
+       return 0;
+}
+
+static int __cellphone_input_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+                               TSC2101_BUZZER_GAIN_CTRL,
+                               15);    
+}
+
+static int __buzzer_input_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+/* When BGC_MUT_BU (bit 6) = 1, power down cellphone input pga.
+ * When BGC_MUT_BU = 0, power up cellphone input pga.
+ */
+static int __buzzer_input_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       u16 val = omap_tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL);
+       ucontrol->value.integer.value[0]        = IS_UNMUTED(6, val);
+       return 0;
+}
+
+static int __buzzer_input_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+                               TSC2101_BUZZER_GAIN_CTRL,
+                               6);     
+}
+
+static snd_kcontrol_new_t tsc2101_control[] __devinitdata = {
+       {
+               .name  = "Target Playback Route",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index = 0,
+               .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info  = __pcm_playback_target_info,
+               .get   = __pcm_playback_target_get,
+               .put   = __pcm_playback_target_put,
+       }, {
+               .name  = "Master Playback Volume",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index = 0,
+               .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info  = __pcm_playback_volume_info,
+               .get   = __pcm_playback_volume_get,
+               .put   = __pcm_playback_volume_put,
+       }, {
+               .name  = "Master Playback Switch",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index = 0,
+               .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info  = __pcm_playback_switch_info,
+               .get   = __pcm_playback_switch_get,
+               .put   = __pcm_playback_switch_put,
+       }, {
+               .name  = "Headset Playback Volume",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index = 0,
+               .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info  = __headset_playback_volume_info,
+               .get   = __headset_playback_volume_get,
+               .put   = __headset_playback_volume_put,
+       }, {
+               .name  = "Headset Playback Switch",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index = 0,
+               .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info  = __headset_playback_switch_info,
+               .get   = __headset_playback_switch_get,
+               .put   = __headset_playback_switch_put,
+       }, {
+               .name  = "Handset Playback Volume",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index = 0,
+               .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info  = __handset_playback_volume_info,
+               .get   = __handset_playback_volume_get,
+               .put   = __handset_playback_volume_put,
+       }, {
+               .name  = "Handset Playback Switch",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index = 0,
+               .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info  = __handset_playback_switch_info,
+               .get   = __handset_playback_switch_get,
+               .put   = __handset_playback_switch_put,
+       }, {
+               .name  = "Cellphone Input Switch",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index = 0,
+               .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info  = __cellphone_input_switch_info,
+               .get   = __cellphone_input_switch_get,
+               .put   = __cellphone_input_switch_put,
+       }, {
+               .name  = "Buzzer Input Switch",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index = 0,
+               .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info  = __buzzer_input_switch_info,
+               .get   = __buzzer_input_switch_get,
+               .put   = __buzzer_input_switch_put,
+       }
+};
+
+#ifdef CONFIG_PM
+
+void snd_omap_suspend_mixer(void)
+{
+}
+
+void snd_omap_resume_mixer(void)
+{
+       snd_omap_init_mixer();
+}
+#endif
+
+int snd_omap_mixer(struct snd_card_omap_codec *tsc2101) 
+{
+       int i=0;
+       int err=0;
+
+       if (!tsc2101) {
+               return -EINVAL;
+       }
+       for (i=0; i < ARRAY_SIZE(tsc2101_control); i++) {
+               if ((err = snd_ctl_add(tsc2101->card, 
+                               snd_ctl_new1(&tsc2101_control[i], 
+                               tsc2101->card))) < 0) {
+                       return err;
+               }
+       }
+       return 0;
+}
diff --git a/sound/arm/omap/omap-alsa-tsc2101-mixer.h b/sound/arm/omap/omap-alsa-tsc2101-mixer.h
new file mode 100644 (file)
index 0000000..3f27e27
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * sound/arm/omap/omap-alsa-tsc2101-mixer.c
+ * 
+ * Alsa Driver for TSC2101 codec for OMAP platform boards.
+ *
+ * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi> and 
+ *                  Everett Coleman II <gcc80x86@fuzzyneural.net>
+ *
+ * Based on the ideas in omap-aic23.c and sa11xx-uda1341.c
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Copyright (C) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.
+ *
+ * History:
+ *
+ * 2006-03-01   Mika Laitio - Mixer for the tsc2101 driver used in omap boards.
+ *             Can switch between headset and loudspeaker playback, 
+ *             mute and unmute dgc, set dgc volume. Record source switch,
+ *             keyclick, buzzer and headset volume and handset volume control 
+ *             are still missing.
+ */
+
+#ifndef OMAPALSATSC2101MIXER_H_
+#define OMAPALSATSC2101MIXER_H_
+
+#include <asm/hardware/tsc2101.h>
+#include <../drivers/ssi/omap-tsc2101.h>
+#include "omap-alsa-dma.h"
+
+/* tsc2101 DAC gain control volume specific  */
+#define OUTPUT_VOLUME_MIN              0x7F    // 1111111 = -63.5 DB
+#define OUTPUT_VOLUME_MAX              0x32    // 110010
+#define OUTPUT_VOLUME_RANGE            (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX)
+
+/* use input vol of 75 for 0dB gain */
+#define INPUT_VOLUME_MIN               0x0
+#define INPUT_VOLUME_MAX               0x7D
+#define INPUT_VOLUME_RANGE             (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
+
+#define PLAYBACK_TARGET_COUNT          0x03
+#define PLAYBACK_TARGET_LOUDSPEAKER    0x00
+#define PLAYBACK_TARGET_HEADPHONE      0x01
+#define PLAYBACK_TARGET_CELLPHONE      0x02
+
+/* following are used for register 03h Mixer PGA control bits D7-D5 for selecting record source */
+#define REC_SRC_TARGET_COUNT           0x08
+#define REC_SRC_SINGLE_ENDED_MICIN_HED 0x00    // oss code referred to MIXER_LINE
+#define REC_SRC_SINGLE_ENDED_MICIN_HND 0x01    // oss code referred to MIXER_MIC
+#define REC_SRC_SINGLE_ENDED_AUX1      0x02
+#define REC_SRC_SINGLE_ENDED_AUX2      0x03
+#define REC_SRC_MICIN_HED_AND_AUX1     0x04
+#define REC_SRC_MICIN_HED_AND_AUX2     0x05
+#define REC_SRC_MICIN_HND_AND_AUX1     0x06
+#define REC_SRC_MICIN_HND_AND_AUX2     0x07
+
+#define DEFAULT_OUTPUT_VOLUME          90      // default output volume to dac dgc
+#define DEFAULT_INPUT_VOLUME           20      // default record volume
+
+#define TSC2101_AUDIO_CODEC_REGISTERS_PAGE2     (2)
+
+#endif /*OMAPALSATSC2101MIXER_H_*/
diff --git a/sound/arm/omap/omap-alsa-tsc2101.c b/sound/arm/omap/omap-alsa-tsc2101.c
new file mode 100644 (file)
index 0000000..9bbf0c7
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+ * arch/arm/mach-omap1/omap-alsa-tsc2101.c
+ * 
+ * Alsa codec Driver for TSC2101 chip for OMAP platform boards. 
+ * Code obtained from oss omap drivers
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *     Written by Nishanth Menon and Sriram Kannan
+ *     
+ * Copyright (C) 2006 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ *     Alsa modularization by Daniel Petrini (d.pensator@gmail.com)
+ * 
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/soundcard.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <asm/io.h>
+#include <asm/arch/mcbsp.h>
+
+#include <linux/slab.h>
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+#include <asm/mach-types.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/clock.h>
+
+#include <asm/hardware/tsc2101.h>
+#include <../drivers/ssi/omap-tsc2101.h>
+
+#include <asm/arch/omap-alsa.h>
+#include "omap-alsa-tsc2101.h"
+
+static struct clk *tsc2101_mclk = 0;
+
+//#define DUMP_TSC2101_AUDIO_REGISTERS
+#undef DUMP_TSC2101_AUDIO_REGISTERS
+
+/*
+ * Hardware capabilities 
+ */
+
+/*
+ * DAC USB-mode sampling rates (MCLK = 12 MHz)
+ * The rates and rate_reg_into MUST be in the same order
+ */
+static unsigned int rates[] = {
+       7350, 8000, 8018, 8727,
+       8820, 9600, 11025, 12000,
+       14700, 16000, 22050, 24000,
+       29400, 32000, 44100, 48000,
+};
+
+static snd_pcm_hw_constraint_list_t tsc2101_hw_constraints_rates = {
+       .count = ARRAY_SIZE(rates),
+       .list = rates,
+       .mask = 0,
+};
+
+static const struct tsc2101_samplerate_reg_info
+    rate_reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
+       /* Div 6 */
+       {7350, 7, 1},
+       {8000, 7, 0},
+       /* Div 5.5 */
+       {8018, 6, 1},
+       {8727, 6, 0},
+       /* Div 5 */
+       {8820, 5, 1},
+       {9600, 5, 0},   
+       /* Div 4 */
+       {11025, 4, 1},
+       {12000, 4, 0},
+       /* Div 3 */
+       {14700, 3, 1},
+       {16000, 3, 0},
+       /* Div 2 */
+       {22050, 2, 1},
+       {24000, 2, 0},
+       /* Div 1.5 */
+       {29400, 1, 1},
+       {32000, 1, 0},
+       /* Div 1 */
+       {44100, 0, 1},
+       {48000, 0, 0},          
+};
+
+static snd_pcm_hardware_t tsc2101_snd_omap_alsa_playback = {
+       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),      
+#ifdef CONFIG_MACH_OMAP_H6300
+       .formats = (SNDRV_PCM_FMTBIT_S8),
+#else
+       .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+#endif
+       .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+                 SNDRV_PCM_RATE_16000 |
+                 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+                 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                 SNDRV_PCM_RATE_KNOT),
+       .rate_min = 7350,
+       .rate_max = 48000,
+       .channels_min = 2,
+       .channels_max = 2,
+       .buffer_bytes_max = 128 * 1024,
+       .period_bytes_min = 32,
+       .period_bytes_max = 8 * 1024,
+       .periods_min = 16,
+       .periods_max = 255,
+       .fifo_size = 0,
+};
+
+static snd_pcm_hardware_t tsc2101_snd_omap_alsa_capture = {
+       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+       .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+       .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+                 SNDRV_PCM_RATE_16000 |
+                 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+                 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                 SNDRV_PCM_RATE_KNOT),
+       .rate_min = 7350,
+       .rate_max = 48000,
+       .channels_min = 2,
+       .channels_max = 2,
+       .buffer_bytes_max = 128 * 1024,
+       .period_bytes_min = 32,
+       .period_bytes_max = 8 * 1024,
+       .periods_min = 16,
+       .periods_max = 255,
+       .fifo_size = 0,
+};
+
+/* 
+ * Simplified write for tsc2101 audio registers.
+ */
+inline void tsc2101_audio_write(u8 address, u16 data)
+{
+       omap_tsc2101_write(PAGE2_AUDIO_CODEC_REGISTERS, address, data);
+}
+
+/* 
+ * Simplified read for tsc2101 audio registers.
+ */
+inline u16 tsc2101_audio_read(u8 address)
+{
+       return (omap_tsc2101_read(PAGE2_AUDIO_CODEC_REGISTERS, address));
+}
+
+#ifdef DUMP_TSC2101_AUDIO_REGISTERS
+void dump_tsc2101_audio_reg(void) {
+       printk("TSC2101_AUDIO_CTRL_1 = 0x%04x\n",       tsc2101_audio_read(TSC2101_AUDIO_CTRL_1));
+       printk("TSC2101_HEADSET_GAIN_CTRL = 0x%04x\n",  tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL));
+       printk("TSC2101_DAC_GAIN_CTRL = 0x%04x\n", tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL));
+       printk("TSC2101_MIXER_PGA_CTRL = 0x%04x\n",     tsc2101_audio_read(TSC2101_MIXER_PGA_CTRL));
+       printk("TSC2101_AUDIO_CTRL_2 = 0x%04x\n",       tsc2101_audio_read(TSC2101_AUDIO_CTRL_2));
+       printk("TSC2101_CODEC_POWER_CTRL = 0x%04x\n",   tsc2101_audio_read(TSC2101_CODEC_POWER_CTRL));
+       printk("TSC2101_AUDIO_CTRL_3 = 0x%04x\n",       tsc2101_audio_read(TSC2101_AUDIO_CTRL_3));
+       printk("TSC2101_LCH_BASS_BOOST_N0 = 0x%04x\n",  tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N0));
+       printk("TSC2101_LCH_BASS_BOOST_N1 = 0x%04x\n",  tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N1));
+       printk("TSC2101_LCH_BASS_BOOST_N2 = 0x%04x\n",  tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N2));
+       printk("TSC2101_LCH_BASS_BOOST_N3 = 0x%04x\n",  tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N3));
+       printk("TSC2101_LCH_BASS_BOOST_N4 = 0x%04x\n",  tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N4));
+       printk("TSC2101_LCH_BASS_BOOST_N5 = 0x%04x\n",  tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N5));
+       printk("TSC2101_LCH_BASS_BOOST_D1 = 0x%04x\n",  tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_D1));
+       printk("TSC2101_LCH_BASS_BOOST_D2 = 0x%04x\n",  tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_D2));
+       printk("TSC2101_LCH_BASS_BOOST_D4 = 0x%04x\n",  tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_D4));
+       printk("TSC2101_LCH_BASS_BOOST_D5 = 0x%04x\n",  tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_D5));
+       
+       printk("TSC2101_RCH_BASS_BOOST_N0 = 0x%04x\n",  tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N0));
+       printk("TSC2101_RCH_BASS_BOOST_N1 = 0x%04x\n",  tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N1));
+       printk("TSC2101_RCH_BASS_BOOST_N2 = 0x%04x\n",  tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N2));
+       printk("TSC2101_RCH_BASS_BOOST_N3 = 0x%04x\n",  tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N3));
+       printk("TSC2101_RCH_BASS_BOOST_N4 = 0x%04x\n",  tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N4));
+       printk("TSC2101_RCH_BASS_BOOST_N5 = 0x%04x\n",  tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N5));
+       printk("TSC2101_RCH_BASS_BOOST_D1 = 0x%04x\n",  tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_D1));
+       printk("TSC2101_RCH_BASS_BOOST_D2 = 0x%04x\n",  tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_D2));
+       printk("TSC2101_RCH_BASS_BOOST_D4 = 0x%04x\n",  tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_D4));
+       printk("TSC2101_RCH_BASS_BOOST_D5 = 0x%04x\n",  tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_D5));
+                                       
+       printk("TSC2101_PLL_PROG_1 = 0x%04x\n", tsc2101_audio_read(TSC2101_PLL_PROG_1));
+       printk("TSC2101_PLL_PROG_1 = 0x%04x\n", tsc2101_audio_read(TSC2101_PLL_PROG_2));
+       printk("TSC2101_AUDIO_CTRL_4 = 0x%04x\n",       tsc2101_audio_read(TSC2101_AUDIO_CTRL_4));
+       printk("TSC2101_HANDSET_GAIN_CTRL = 0x%04x\n",  tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL));
+       printk("TSC2101_BUZZER_GAIN_CTRL = 0x%04x\n",   tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL));
+       printk("TSC2101_AUDIO_CTRL_5 = 0x%04x\n",       tsc2101_audio_read(TSC2101_AUDIO_CTRL_5));
+       printk("TSC2101_AUDIO_CTRL_6 = 0x%04x\n",       tsc2101_audio_read(TSC2101_AUDIO_CTRL_6));
+       printk("TSC2101_AUDIO_CTRL_7 = 0x%04x\n",       tsc2101_audio_read(TSC2101_AUDIO_CTRL_7));
+       printk("TSC2101_GPIO_CTRL = 0x%04x\n",  tsc2101_audio_read(TSC2101_GPIO_CTRL));
+       printk("TSC2101_AGC_CTRL = 0x%04x\n",   tsc2101_audio_read(TSC2101_AGC_CTRL));
+       printk("TSC2101_POWERDOWN_STS = 0x%04x\n",      tsc2101_audio_read(TSC2101_POWERDOWN_STS));
+       printk("TSC2101_MIC_AGC_CONTROL = 0x%04x\n",    tsc2101_audio_read(TSC2101_MIC_AGC_CONTROL));
+       printk("TSC2101_CELL_AGC_CONTROL = 0x%04x\n",   tsc2101_audio_read(TSC2101_CELL_AGC_CONTROL));
+}
+#endif
+
+/*
+ * ALSA operations according to board file
+ */
+
+/*
+ * Sample rate changing
+ */
+void tsc2101_set_samplerate(long sample_rate)
+{
+       u8 count = 0;
+       u16 data = 0;
+       int clkgdv = 0;
+
+       u16 srgr1, srgr2;
+       /* wait for any frame to complete */
+       udelay(125);
+       ADEBUG();
+
+       sample_rate     = sample_rate;
+       /* Search for the right sample rate */
+       while ((rate_reg_info[count].sample_rate != sample_rate) &&
+              (count < NUMBER_SAMPLE_RATES_SUPPORTED)) {
+               count++;
+       }
+       if (count == NUMBER_SAMPLE_RATES_SUPPORTED) {
+               printk(KERN_ERR "Invalid Sample Rate %d requested\n",
+                      (int) sample_rate);
+               return;         // -EPERM;
+       }
+
+       /* Set AC1 */
+       data    = tsc2101_audio_read(TSC2101_AUDIO_CTRL_1);
+       /* Clear prev settings */
+       data    &= ~(AC1_DACFS(0x07) | AC1_ADCFS(0x07));
+       data    |= AC1_DACFS(rate_reg_info[count].divisor) | 
+                       AC1_ADCFS(rate_reg_info[count].divisor);
+       tsc2101_audio_write(TSC2101_AUDIO_CTRL_1, data);
+
+       /* Set the AC3 */
+       data    = tsc2101_audio_read(TSC2101_AUDIO_CTRL_3);
+       /*Clear prev settings */
+       data    &= ~(AC3_REFFS | AC3_SLVMS);
+       data    |= (rate_reg_info[count].fs_44kHz) ? AC3_REFFS : 0;
+#ifdef TSC_MASTER
+       data    |= AC3_SLVMS;
+#endif                         /* #ifdef TSC_MASTER */
+       tsc2101_audio_write(TSC2101_AUDIO_CTRL_3, data);
+
+       /* Program the PLLs. This code assumes that the 12 Mhz MCLK is in use.
+         * If MCLK rate is something else, these values must be changed.
+        * See the tsc2101 specification for the details.
+        */
+       if (rate_reg_info[count].fs_44kHz) {
+               /* samplerate = (44.1kHZ / x), where x is int. */
+               tsc2101_audio_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL |
+                               PLL1_PVAL(1) | PLL1_I_VAL(7));  /* PVAL 1; I_VAL 7 */
+               tsc2101_audio_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x1490));    /* D_VAL 5264 */
+       } else {
+               /* samplerate = (48.kHZ / x), where x is int. */
+               tsc2101_audio_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL |
+                              PLL1_PVAL(1) | PLL1_I_VAL(8));   /* PVAL 1; I_VAL 8 */
+               tsc2101_audio_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x780));     /* D_VAL 1920 */
+       }
+
+       /* Set the sample rate */
+#ifndef TSC_MASTER
+       clkgdv  = CODEC_CLOCK / (sample_rate * (DEFAULT_BITPERSAMPLE * 2 - 1));
+       if (clkgdv)
+               srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+       else
+               return (1);
+
+       /* Stereo Mode */
+       srgr2 = (CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1));
+#else
+       srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+       srgr2 = ((GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)));
+
+#endif                         /* end of #ifdef TSC_MASTER */
+       OMAP_MCBSP_WRITE(OMAP1610_MCBSP1_BASE, SRGR2, srgr2);
+       OMAP_MCBSP_WRITE(OMAP1610_MCBSP1_BASE, SRGR1, srgr1);
+}
+
+void tsc2101_configure(void)
+{
+}
+
+/*
+ *  Omap MCBSP clock and Power Management configuration
+ *  
+ *  Here we have some functions that allows clock to be enabled and
+ *   disabled only when needed. Besides doing clock configuration 
+ *   it allows turn on/turn off audio when necessary. 
+ */
+/*
+ * Do clock framework mclk search
+ */
+void tsc2101_clock_setup(void)
+{
+       tsc2101_mclk = clk_get(0, "mclk");
+}
+
+/*
+ * Do some sanity check, set clock rate, starts it and turn codec audio on
+ */
+int tsc2101_clock_on(void) 
+{
+       int     curUseCount;
+       uint    curRate;
+       int     err;
+
+       curUseCount     = clk_get_usecount(tsc2101_mclk);
+       DPRINTK("clock use count = %d\n", curUseCount);
+       if (curUseCount > 0) {
+               // MCLK is already in use
+               printk(KERN_WARNING
+                      "MCLK already in use at %d Hz. We change it to %d Hz\n",
+                      (uint) clk_get_rate(tsc2101_mclk),
+                      CODEC_CLOCK);
+       }
+       curRate = (uint)clk_get_rate(tsc2101_mclk);
+       if (curRate != CODEC_CLOCK) {
+               err     = clk_set_rate(tsc2101_mclk, CODEC_CLOCK);
+               if (err) {
+                       printk(KERN_WARNING
+                              "Cannot set MCLK clock rate for TSC2101 CODEC, error code = %d\n", err);
+                       return -ECANCELED;
+               }
+       }
+       err             = clk_enable(tsc2101_mclk);
+       curRate         = (uint)clk_get_rate(tsc2101_mclk);
+       curUseCount     = clk_get_usecount(tsc2101_mclk);
+       DPRINTK("MCLK = %d [%d], usecount = %d, clk_enable retval = %d\n",
+              curRate, 
+              CODEC_CLOCK,
+              curUseCount,
+              err);
+
+       // Now turn the audio on
+       omap_tsc2101_write(PAGE2_AUDIO_CODEC_REGISTERS,
+                       TSC2101_CODEC_POWER_CTRL,
+                       0x0000);        
+       return 0;       
+}
+
+/*
+ * Do some sanity check, turn clock off and then turn codec audio off
+ */
+int tsc2101_clock_off(void) 
+{
+       int curUseCount;
+       int curRate;
+
+       curUseCount     = clk_get_usecount(tsc2101_mclk);
+       DPRINTK("clock use count = %d\n", curUseCount);
+       if  (curUseCount > 0) {
+               curRate = clk_get_rate(tsc2101_mclk);
+               DPRINTK("clock rate = %d\n", curRate);
+               if (curRate != CODEC_CLOCK) {
+                       printk(KERN_WARNING
+                              "MCLK for audio should be %d Hz. But is %d Hz\n",
+                              (uint) clk_get_rate(tsc2101_mclk),
+                              CODEC_CLOCK);
+               }
+               clk_disable(tsc2101_mclk);
+               DPRINTK("clock disabled\n");
+       }
+       tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL,
+                           ~(CPC_SP1PWDN | CPC_SP2PWDN | CPC_BASSBC));
+       DPRINTK("audio codec off\n");
+       return 0;       
+}
+
+int tsc2101_get_default_samplerate(void)
+{
+       return DEFAULT_SAMPLE_RATE;
+}
+
+static int __devinit snd_omap_alsa_tsc2101_probe(struct platform_device *pdev)
+{
+       int     ret;
+       struct  omap_alsa_codec_config *codec_cfg;
+       
+       codec_cfg = pdev->dev.platform_data;
+       if (codec_cfg != NULL) {
+               codec_cfg->hw_constraints_rates = &tsc2101_hw_constraints_rates;
+               codec_cfg->snd_omap_alsa_playback  = &tsc2101_snd_omap_alsa_playback;
+               codec_cfg->snd_omap_alsa_capture  = &tsc2101_snd_omap_alsa_capture;
+               codec_cfg->codec_configure_dev  = tsc2101_configure;
+               codec_cfg->codec_set_samplerate = tsc2101_set_samplerate;
+               codec_cfg->codec_clock_setup    = tsc2101_clock_setup;
+               codec_cfg->codec_clock_on       = tsc2101_clock_on;
+               codec_cfg->codec_clock_off      = tsc2101_clock_off;
+               codec_cfg->get_default_samplerate = tsc2101_get_default_samplerate;
+               ret     = snd_omap_alsa_post_probe(pdev, codec_cfg);
+       }
+       else
+               ret = -ENODEV;
+       return ret;
+}
+
+static struct platform_driver omap_alsa_driver = {
+       .probe          = snd_omap_alsa_tsc2101_probe,
+       .remove         = snd_omap_alsa_remove,
+       .suspend        = snd_omap_alsa_suspend,
+       .resume         = snd_omap_alsa_resume,
+       .driver = {
+               .name = "omap_alsa_mcbsp",
+       },
+};
+
+static int __init omap_alsa_tsc2101_init(void)
+{      
+       ADEBUG();
+#ifdef DUMP_TSC2101_AUDIO_REGISTERS
+       printk("omap_alsa_tsc2101_init()\n");
+       dump_tsc2101_audio_reg();
+#endif
+       return platform_driver_register(&omap_alsa_driver);
+}
+
+static void __exit omap_alsa_tsc2101_exit(void)
+{
+       ADEBUG();
+#ifdef DUMP_TSC2101_AUDIO_REGISTERS
+       printk("omap_alsa_tsc2101_exit()\n");
+       dump_tsc2101_audio_reg();
+#endif
+       platform_driver_unregister(&omap_alsa_driver);
+}
+
+module_init(omap_alsa_tsc2101_init);
+module_exit(omap_alsa_tsc2101_exit);
diff --git a/sound/arm/omap/omap-alsa-tsc2101.h b/sound/arm/omap/omap-alsa-tsc2101.h
new file mode 100644 (file)
index 0000000..803d215
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * arch/arc/mach-omap1/omap-alsa-tsc2101.h
+ * 
+ * Alsa Driver for TSC2101 codec for OMAP platform boards.
+ *
+ * Based on former omap-aic23.h and tsc2101 OSS drivers.
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *     Written by Nishanth Menon and Sriram Kannan
+ *
+ * Copyright (C) 2006 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ *          Alsa modularization by Daniel Petrini (d.pensator@gmail.com)
+ * 
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ *
+ * 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.
+ */
+
+#ifndef OMAP_ALSA_TSC2101_H_
+#define OMAP_ALSA_TSC2101_H_
+
+#include <linux/types.h>
+
+/* Define to set the tsc as the master w.r.t McBSP */
+#define TSC_MASTER
+
+#define NUMBER_SAMPLE_RATES_SUPPORTED  16
+
+/*
+ * AUDIO related MACROS
+ */
+#ifndef DEFAULT_BITPERSAMPLE
+#define DEFAULT_BITPERSAMPLE           16
+#endif
+
+#define DEFAULT_SAMPLE_RATE            44100
+#define CODEC_CLOCK                    12000000
+#define AUDIO_MCBSP                    OMAP_MCBSP1
+
+#define PAGE2_AUDIO_CODEC_REGISTERS    (2)
+
+struct tsc2101_samplerate_reg_info {
+       u16 sample_rate;
+       u8 divisor;
+       u8 fs_44kHz;    /* if 0 48 khz, if 1 44.1 khz fsref */
+};
+
+/*
+ * Defines codec specific functions pointers that can be used from the 
+ * common omap-alse base driver for all omap codecs. (tsc2101 and aic23)
+ */
+inline void tsc2101_configure(void);
+void tsc2101_set_samplerate(long rate);
+void tsc2101_clock_setup(void);
+int tsc2101_clock_on(void);
+int tsc2101_clock_off(void);
+int tsc2101_get_default_samplerate(void);
+
+#endif /*OMAP_ALSA_TSC2101_H_*/
diff --git a/sound/arm/omap/omap-alsa-tsc2102-mixer.c b/sound/arm/omap/omap-alsa-tsc2102-mixer.c
new file mode 100644 (file)
index 0000000..2e06d70
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * sound/arm/omap/omap-alsa-tsc2102-mixer.c
+ *
+ * Alsa mixer driver for TSC2102 chip for OMAP platforms.
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
+ * Code based on the TSC2101 ALSA driver.
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.
+ */
+
+#include <linux/types.h>
+#include <linux/spi/tsc2102.h>
+
+#include <asm/arch/omap-alsa.h>
+
+#include <sound/driver.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+
+#include "omap-alsa-tsc2102.h"
+#include "omap-alsa-dma.h"
+
+static int vol[2], mute[2], filter[2];
+
+/*
+ * Converts the Alsa mixer volume (0 - 100) to actual Digital
+ * Gain Control (DGC) value that can be written or read from the
+ * TSC2102 registers.
+ *
+ * Note that the number "OUTPUT_VOLUME_MAX" is smaller than
+ * OUTPUT_VOLUME_MIN because DGC works as a volume decreaser.  (The
+ * higher the value sent to DAC, the more the volume of controlled
+ * channel is decreased)
+ */
+static void set_dac_gain_stereo(int left_ch, int right_ch)
+{
+       int lch, rch;
+
+       if (left_ch > 100)
+               vol[0] = 100;
+       else if (left_ch < 0)
+               vol[0] = 0;
+       else
+               vol[0] = left_ch;
+       lch = OUTPUT_VOLUME_MIN - vol[0] *
+               (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX) / 100;
+
+       if (right_ch > 100)
+               vol[1] = 100;
+       else if (right_ch < 0)
+               vol[1] = 0;
+       else
+               vol[1] = right_ch;
+       rch = OUTPUT_VOLUME_MIN - vol[1] *
+               (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX) / 100;
+
+       tsc2102_set_volume(lch, rch);
+}
+
+void init_playback_targets(void)
+{
+       set_dac_gain_stereo(DEFAULT_OUTPUT_VOLUME, DEFAULT_OUTPUT_VOLUME);
+
+       /* Unmute */
+       tsc2102_set_mute(0, 0);
+
+       mute[0] = mute[1] = 0;
+       filter[0] = filter[1] = 0;
+}
+
+/*
+ * Initializes TSC 2102 and playback target.
+ */
+void snd_omap_init_mixer(void)
+{
+       FN_IN;
+
+       init_playback_targets();
+
+       FN_OUT(0);
+}
+
+static int __pcm_playback_volume_info(
+               snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count                    = 2;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 100;
+       return 0;
+}
+
+static int __pcm_playback_volume_get(
+               snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ucontrol->value.integer.value[0] = vol[0];      /* L */
+       ucontrol->value.integer.value[1] = vol[1];      /* R */
+
+       return 0;
+}
+
+static int __pcm_playback_volume_put(
+               snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       set_dac_gain_stereo(
+                       ucontrol->value.integer.value[0],       /* L */
+                       ucontrol->value.integer.value[1]);      /* R */
+       return 1;
+}
+
+static int __pcm_playback_switch_info(
+               snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 2;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+static int __pcm_playback_switch_get(
+               snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ucontrol->value.integer.value[0] = !mute[0];            /* L */
+       ucontrol->value.integer.value[1] = !mute[1];            /* R */
+
+       return 0;
+}
+
+static int __pcm_playback_switch_put(
+               snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       mute[0] = (ucontrol->value.integer.value[0] == 0);      /* L */
+       mute[1] = (ucontrol->value.integer.value[1] == 0);      /* R */
+
+       tsc2102_set_mute(mute[0], mute[1]);
+       return 1;
+}
+
+static int __pcm_playback_deemphasis_info(
+               snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+static int __pcm_playback_deemphasis_get(
+               snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ucontrol->value.integer.value[0] = filter[0];
+       return 0;
+}
+
+static int __pcm_playback_deemphasis_put(
+               snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       filter[0] = (ucontrol->value.integer.value[0] > 0);
+
+       tsc2102_set_deemphasis(filter[0]);
+       return 1;
+}
+
+static int __pcm_playback_bassboost_info(
+               snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+static int __pcm_playback_bassboost_get(
+               snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ucontrol->value.integer.value[0] = filter[1];
+       return 0;
+}
+
+static int __pcm_playback_bassboost_put(
+               snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
+{
+       filter[1] = (ucontrol->value.integer.value[0] > 0);
+
+       tsc2102_set_bassboost(filter[1]);
+       return 1;
+}
+
+static snd_kcontrol_new_t tsc2102_control[] __devinitdata = {
+       {
+               .name   = "Master Playback Volume",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = __pcm_playback_volume_info,
+               .get    = __pcm_playback_volume_get,
+               .put    = __pcm_playback_volume_put,
+       },
+       {
+               .name   = "Master Playback Switch",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = __pcm_playback_switch_info,
+               .get    = __pcm_playback_switch_get,
+               .put    = __pcm_playback_switch_put,
+       },
+       {
+               .name   = "De-emphasis Filter Switch",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = __pcm_playback_deemphasis_info,
+               .get    = __pcm_playback_deemphasis_get,
+               .put    = __pcm_playback_deemphasis_put,
+       },
+       {
+               .name   = "Bass-boost Filter Switch",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = __pcm_playback_bassboost_info,
+               .get    = __pcm_playback_bassboost_get,
+               .put    = __pcm_playback_bassboost_put,
+       },
+};
+
+#ifdef CONFIG_PM
+void snd_omap_suspend_mixer(void)
+{
+       /* Nothing to do */
+}
+
+void snd_omap_resume_mixer(void)
+{
+       /* The chip was reset, restore the last used values */
+       set_dac_gain_stereo(vol[0], vol[1]);
+
+       tsc2102_set_mute(mute[0], mute[1]);
+       tsc2102_set_deemphasis(filter[0]);
+       tsc2102_set_bassboost(filter[1]);
+}
+#endif
+
+int snd_omap_mixer(struct snd_card_omap_codec *tsc2102)
+{
+       int i, err;
+
+       if (!tsc2102)
+               return -EINVAL;
+
+       for (i = 0; i < ARRAY_SIZE(tsc2102_control); i ++) {
+               err = snd_ctl_add(tsc2102->card,
+                               snd_ctl_new1(&tsc2102_control[i],
+                               tsc2102->card));
+
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
diff --git a/sound/arm/omap/omap-alsa-tsc2102.c b/sound/arm/omap/omap-alsa-tsc2102.c
new file mode 100644 (file)
index 0000000..41e2d07
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ * sound/arm/omap/omap-alsa-tsc2102.c
+ * 
+ * Alsa codec driver for TSC2102 chip for OMAP platforms.
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
+ * Code based on the TSC2101 ALSA driver.
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/soundcard.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/spi/tsc2102.h>
+
+#include <asm/arch/mcbsp.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/omap-alsa.h>
+
+#include "omap-alsa-tsc2102.h"
+
+static struct clk *tsc2102_bclk = 0;
+
+/*
+ * Hardware capabilities
+ */
+
+/* DAC sampling rates (BCLK = 12 MHz) */
+static unsigned int rates[] = {
+       7350, 8000, 8820, 9600, 11025, 12000, 14700,
+       16000, 22050, 24000, 29400, 32000, 44100, 48000,
+};
+
+static snd_pcm_hw_constraint_list_t tsc2102_hw_constraints_rates = {
+       .count = ARRAY_SIZE(rates),
+       .list = rates,
+       .mask = 0,
+};
+
+static snd_pcm_hardware_t tsc2102_snd_omap_alsa_playback = {
+       .info                   = SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_MMAP_VALID,
+       .formats                = SNDRV_PCM_FMTBIT_S16_LE,
+       .rates                  = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+               SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
+               SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+               SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_KNOT,
+       .rate_min               = 7350,
+       .rate_max               = 48000,
+       .channels_min           = 2,
+       .channels_max           = 2,
+       .buffer_bytes_max       = 128 * 1024,
+       .period_bytes_min       = 32,
+       .period_bytes_max       = 8 * 1024,
+       .periods_min            = 16,
+       .periods_max            = 255,
+       .fifo_size              = 0,
+};
+
+#ifdef DUMP_TSC2102_AUDIO_REGISTERS
+static void dump_tsc2102_audio_regs(void) {
+       printk("TSC2102_AUDIO1_CTRL = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_AUDIO1_CTRL));
+       printk("TSC2102_DAC_GAIN_CTRL = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_DAC_GAIN_CTRL));
+       printk("TSC2102_AUDIO2_CTRL = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_AUDIO2_CTRL));
+       printk("TSC2102_DAC_POWER_CTRL = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_DAC_POWER_CTRL));
+       printk("TSC2102_AUDIO3_CTRL = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_AUDIO_CTRL_3));
+       printk("TSC2102_LCH_BASS_BOOST_N0 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N0));
+       printk("TSC2102_LCH_BASS_BOOST_N1 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N1));
+       printk("TSC2102_LCH_BASS_BOOST_N2 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N2));
+       printk("TSC2102_LCH_BASS_BOOST_N3 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N3));
+       printk("TSC2102_LCH_BASS_BOOST_N4 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N4));
+       printk("TSC2102_LCH_BASS_BOOST_N5 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N5));
+       printk("TSC2102_LCH_BASS_BOOST_D1 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D1));
+       printk("TSC2102_LCH_BASS_BOOST_D2 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D2));
+       printk("TSC2102_LCH_BASS_BOOST_D4 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D4));
+       printk("TSC2102_LCH_BASS_BOOST_D5 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D5));
+       printk("TSC2102_RCH_BASS_BOOST_N0 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N0));
+       printk("TSC2102_RCH_BASS_BOOST_N1 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N1));
+       printk("TSC2102_RCH_BASS_BOOST_N2 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N2));
+       printk("TSC2102_RCH_BASS_BOOST_N3 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N3));
+       printk("TSC2102_RCH_BASS_BOOST_N4 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N4));
+       printk("TSC2102_RCH_BASS_BOOST_N5 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N5));
+       printk("TSC2102_RCH_BASS_BOOST_D1 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D1));
+       printk("TSC2102_RCH_BASS_BOOST_D2 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D2));
+       printk("TSC2102_RCH_BASS_BOOST_D4 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D4));
+       printk("TSC2102_RCH_BASS_BOOST_D5 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D5));
+       printk("TSC2102_PLL1_CTRL = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_PLL1_CTRL));
+       printk("TSC2102_PLL2_CTRL = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_PLL2_CTRL));
+       printk("TSC2102_AUDIO4_CTRL = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_AUDIO4_CTRL));
+}
+#endif
+
+/*
+ * ALSA operations according to board file
+ */
+
+static long current_rate = 0;
+
+/*
+ * Sample rate changing
+ */
+static void tsc2102_set_samplerate(long sample_rate)
+{
+       int clkgdv = 0;
+       u16 srgr1, srgr2;
+
+       if (sample_rate == current_rate)
+               return;
+       current_rate = 0;
+
+       if (tsc2102_set_rate(sample_rate))
+               return;
+
+       /* Set the sample rate */
+#ifndef TSC_MASTER
+       clkgdv = CODEC_CLOCK / (sample_rate * (DEFAULT_BITPERSAMPLE * 2 - 1));
+       if (clkgdv)
+               srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+       else
+               return;
+
+       /* Stereo Mode */
+       srgr2 = CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1);
+#else
+       srgr1 = FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv);
+       srgr2 = GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1);
+#endif
+       OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR2, srgr2);
+       OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR1, srgr1);
+       current_rate = sample_rate;
+}
+
+static void tsc2102_configure(void)
+{
+       tsc2102_dac_power(1);
+
+#ifdef TSC_MASTER
+       tsc2102_set_i2s_master(1);
+#else
+       tsc2102_set_i2s_master(0);
+#endif
+}
+
+/*
+ * Omap McBSP clock and Power Management configuration
+ *  
+ * Here we have some functions that allow clock to be enabled and
+ * disabled only when needed.  Besides doing clock configuration
+ * they allow turn audio on and off when necessary.
+ */
+
+/*
+ * Do clock framework bclk search
+ */
+static void tsc2102_clock_setup(void)
+{
+       tsc2102_bclk = clk_get(0, "bclk");
+}
+
+/*
+ * Do some sanity checks, set clock rate, start it.
+ */
+static int tsc2102_clock_on(void)
+{
+       int err;
+
+       if (clk_get_usecount(tsc2102_bclk) > 0 &&
+                       clk_get_rate(tsc2102_bclk) != CODEC_CLOCK) {
+               /* BCLK is already in use */
+               printk(KERN_WARNING
+                       "BCLK already in use at %d Hz. We change it to %d Hz\n",
+                       (uint) clk_get_rate(tsc2102_bclk), CODEC_CLOCK);
+
+               err = clk_set_rate(tsc2102_bclk, CODEC_CLOCK);
+               if (err)
+                       printk(KERN_WARNING "Cannot set BCLK clock rate "
+                               "for TSC2102 codec, error code = %d\n", err);
+       }
+
+       clk_enable(tsc2102_bclk);
+       return 0;
+}
+
+/*
+ * Turn off the audio codec and then stop the clock.
+ */
+static int tsc2102_clock_off(void)
+{
+       DPRINTK("clock use count = %d\n", clk_get_usecount(tsc2102_bclk));
+
+       clk_disable(tsc2102_bclk);
+       return 0;
+}
+
+static int tsc2102_get_default_samplerate(void)
+{
+       return DEFAULT_SAMPLE_RATE;
+}
+
+static int snd_omap_alsa_tsc2102_suspend(
+               struct platform_device *pdev, pm_message_t state)
+{
+       tsc2102_dac_power(0);
+       current_rate = 0;
+
+       return snd_omap_alsa_suspend(pdev, state);
+}
+
+static int snd_omap_alsa_tsc2102_resume(struct platform_device *pdev)
+{
+       tsc2102_dac_power(1);
+
+#ifdef TSC_MASTER
+       tsc2102_set_i2s_master(1);
+#else
+       tsc2102_set_i2s_master(0);
+#endif
+
+       return snd_omap_alsa_resume(pdev);
+}
+
+static int __init snd_omap_alsa_tsc2102_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct omap_alsa_codec_config *codec_cfg = pdev->dev.platform_data;
+
+       if (codec_cfg) {
+               codec_cfg->hw_constraints_rates =
+                       &tsc2102_hw_constraints_rates;
+               codec_cfg->snd_omap_alsa_playback =
+                       &tsc2102_snd_omap_alsa_playback;
+               codec_cfg->codec_configure_dev = tsc2102_configure;
+               codec_cfg->codec_set_samplerate = tsc2102_set_samplerate;
+               codec_cfg->codec_clock_setup = tsc2102_clock_setup;
+               codec_cfg->codec_clock_on = tsc2102_clock_on;
+               codec_cfg->codec_clock_off = tsc2102_clock_off;
+               codec_cfg->get_default_samplerate =
+                       tsc2102_get_default_samplerate;
+               ret = snd_omap_alsa_post_probe(pdev, codec_cfg);
+       } else
+               ret = -ENODEV;
+
+       return ret;
+}
+
+static int snd_omap_alsa_tsc2102_remove(struct platform_device *pdev)
+{
+       tsc2102_dac_power(0);
+
+       return snd_omap_alsa_remove(pdev);
+}
+
+static struct platform_driver omap_alsa_driver = {
+       .probe          = snd_omap_alsa_tsc2102_probe,
+       .remove         = snd_omap_alsa_tsc2102_remove,
+       .suspend        = snd_omap_alsa_tsc2102_suspend,
+       .resume         = snd_omap_alsa_tsc2102_resume,
+       .driver         = {
+               .name   = "tsc2102-alsa",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init omap_alsa_tsc2102_init(void)
+{
+       int err;
+
+       ADEBUG();
+       err = platform_driver_register(&omap_alsa_driver);
+
+       return err;
+}
+
+static void __exit omap_alsa_tsc2102_exit(void)
+{
+       ADEBUG();
+       platform_driver_unregister(&omap_alsa_driver);
+}
+
+module_init(omap_alsa_tsc2102_init);
+module_exit(omap_alsa_tsc2102_exit);
diff --git a/sound/arm/omap/omap-alsa-tsc2102.h b/sound/arm/omap/omap-alsa-tsc2102.h
new file mode 100644 (file)
index 0000000..c4b34f8
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * sound/arm/omap/omap-alsa-tsc2102.h
+ * 
+ * Alsa codec driver for TSC2102 chip for OMAP platforms.
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
+ * Code based on the TSC2101 ALSA driver.
+ *
+ * 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.
+ */
+
+#ifndef OMAP_ALSA_TSC2102_H_
+#define OMAP_ALSA_TSC2102_H_
+
+/* Define to set the tsc as the master w.r.t McBSP */
+#define TSC_MASTER
+
+/*
+ * Audio related macros
+ */
+#ifndef DEFAULT_BITPERSAMPLE
+#define DEFAULT_BITPERSAMPLE           16
+#endif
+
+#define DEFAULT_SAMPLE_RATE            44100
+#define CODEC_CLOCK                    12000000
+#define AUDIO_MCBSP                    OMAP_MCBSP1
+
+/*
+ * ALSA mixer related macros
+ */
+#define OUTPUT_VOLUME_MIN              0x7f    /* 1111111 = -63.5 dB */
+#define OUTPUT_VOLUME_MAX              0x00    /* 0000000 */
+#define OUTPUT_VOLUME_RANGE            (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX)
+
+#define DEFAULT_OUTPUT_VOLUME          90      /* Default output volume */
+
+#endif /* OMAP_ALSA_TSC2102_H_ */
diff --git a/sound/arm/omap/omap-alsa.c b/sound/arm/omap/omap-alsa.c
new file mode 100644 (file)
index 0000000..11675f2
--- /dev/null
@@ -0,0 +1,580 @@
+/*
+ * sound/arm/omap-alsa.c
+ * 
+ * Alsa Driver for OMAP
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Written by Daniel Petrini, David Cohen, Anderson Briglia
+ *            {daniel.petrini, david.cohen, anderson.briglia}@indt.org.br
+ *
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ *
+ * Based on sa11xx-uda1341.c, 
+ * Copyright (C) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.
+ *
+ * History:
+ *
+ * 2005-07-29   INdT Kernel Team - Alsa driver for omap osk. Creation of new 
+ *                                 file omap-aic23.c
+ * 
+ * 2005-12-18   Dirk Behme       - Added L/R Channel Interchange fix as proposed 
+ *                                 by Ajaya Babu
+ *
+ */
+
+#include <linux/platform_device.h>
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+#include <sound/driver.h>
+#include <sound/core.h>
+
+#include <asm/arch/omap-alsa.h>
+#include "omap-alsa-dma.h"
+
+MODULE_AUTHOR("Mika Laitio, Daniel Petrini, David Cohen, Anderson Briglia - INdT");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("OMAP driver for ALSA");
+MODULE_ALIAS("omap_alsa_mcbsp.1");
+
+static char *id        = NULL; 
+static struct snd_card_omap_codec      *alsa_codec             = NULL;
+static struct omap_alsa_codec_config   *alsa_codec_config      = NULL;
+
+/*
+ * HW interface start and stop helper functions
+ */
+static int audio_ifc_start(void)
+{
+       omap_mcbsp_start(AUDIO_MCBSP);
+       return 0;
+}
+
+static int audio_ifc_stop(void)
+{
+       omap_mcbsp_stop(AUDIO_MCBSP);
+       return 0;
+}
+
+static void omap_alsa_audio_init(struct snd_card_omap_codec *omap_alsa)
+{
+       /* Setup DMA stuff */
+       omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].id = "Alsa omap out";
+       omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].stream_id =
+           SNDRV_PCM_STREAM_PLAYBACK;
+       omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].dma_dev =
+           OMAP_DMA_MCBSP1_TX;
+       omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].hw_start =
+           audio_ifc_start;
+       omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].hw_stop =
+           audio_ifc_stop;
+
+       omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].id = "Alsa omap in";
+       omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].stream_id =
+           SNDRV_PCM_STREAM_CAPTURE;
+       omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].dma_dev =
+           OMAP_DMA_MCBSP1_RX;
+       omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].hw_start =
+           audio_ifc_start;
+       omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].hw_stop =
+           audio_ifc_stop;
+}
+
+/* 
+ * DMA functions 
+ * Depends on omap-alsa-dma.c functions and (omap) dma.c
+ * 
+ */
+static int audio_dma_request(struct audio_stream *s,
+                            void (*callback) (void *))
+{
+       int err;
+       ADEBUG();
+
+       err = omap_request_alsa_sound_dma(s->dma_dev, s->id, s, &s->lch);
+       if (err < 0)
+               printk(KERN_ERR "Unable to grab audio dma 0x%x\n", s->dma_dev);
+       return err;
+}
+
+static int audio_dma_free(struct audio_stream *s)
+{
+       int err = 0;
+       ADEBUG();
+
+       err = omap_free_alsa_sound_dma(s, &s->lch);
+       if (err < 0)
+               printk(KERN_ERR "Unable to free audio dma channels!\n");
+       return err;
+}
+
+/*
+ *  This function should calculate the current position of the dma in the
+ *  buffer. It will help alsa middle layer to continue update the buffer.
+ *  Its correctness is crucial for good functioning.
+ */
+static u_int audio_get_dma_pos(struct audio_stream *s)
+{
+       snd_pcm_substream_t *substream = s->stream;
+       snd_pcm_runtime_t *runtime = substream->runtime;
+       unsigned int offset;
+       unsigned long flags;
+       dma_addr_t count;
+       ADEBUG();
+
+       /* this must be called w/ interrupts locked as requested in dma.c */
+       spin_lock_irqsave(&s->dma_lock, flags);
+
+       /* For the current period let's see where we are */
+       count = omap_get_dma_src_addr_counter(s->lch[s->dma_q_head]);
+
+       spin_unlock_irqrestore(&s->dma_lock, flags);
+
+       /* Now, the position related to the end of that period */
+       offset = bytes_to_frames(runtime, s->offset) - bytes_to_frames(runtime, count);
+
+       if (offset >= runtime->buffer_size)
+               offset = 0;
+
+       return offset;
+}
+
+/*
+ * this stops the dma and clears the dma ptrs
+ */
+static void audio_stop_dma(struct audio_stream *s)
+{
+       unsigned long flags;
+       ADEBUG();
+
+       spin_lock_irqsave(&s->dma_lock, flags);
+       s->active = 0;
+       s->period = 0;
+       s->periods = 0;
+
+       /* this stops the dma channel and clears the buffer ptrs */
+       omap_stop_alsa_sound_dma(s);
+
+       omap_clear_alsa_sound_dma(s);
+
+       spin_unlock_irqrestore(&s->dma_lock, flags);
+}
+
+/*
+ *  Main dma routine, requests dma according where you are in main alsa buffer
+ */
+static void audio_process_dma(struct audio_stream *s)
+{
+       snd_pcm_substream_t *substream = s->stream;
+       snd_pcm_runtime_t *runtime;
+       unsigned int dma_size;
+       unsigned int offset;
+       int ret;
+       
+       ADEBUG();
+       runtime = substream->runtime;
+       if (s->active) {
+               dma_size = frames_to_bytes(runtime, runtime->period_size);
+               offset = dma_size * s->period;
+               snd_assert(dma_size <= DMA_BUF_SIZE,);
+               /*
+                * On omap1510 based devices, we need to call the stop_dma
+                * before calling the start_dma or we will not receive the
+                * irq from DMA after the first transfered/played buffer.
+                * (invocation of callback_omap_alsa_sound_dma() method).
+                */
+               if (cpu_is_omap1510()) {
+                       omap_stop_alsa_sound_dma(s);
+               }
+               ret = omap_start_alsa_sound_dma(s,
+                               (dma_addr_t)runtime->dma_area + offset,
+                               dma_size);
+               if (ret) {
+                       printk(KERN_ERR
+                              "audio_process_dma: cannot queue DMA buffer (%i)\n",
+                              ret);
+                       return;
+               }
+
+               s->period++;
+               s->period %= runtime->periods;
+               s->periods++;
+               s->offset = offset;
+       }
+}
+
+/* 
+ *  This is called when dma IRQ occurs at the end of each transmited block
+ */
+void callback_omap_alsa_sound_dma(void *data)
+{
+       struct audio_stream *s = data;
+       
+       ADEBUG();
+       /* 
+        * If we are getting a callback for an active stream then we inform
+        * the PCM middle layer we've finished a period
+        */
+       if (s->active)
+               snd_pcm_period_elapsed(s->stream);
+
+       spin_lock(&s->dma_lock);
+       if (s->periods > 0) 
+               s->periods--;
+       
+       audio_process_dma(s);
+       spin_unlock(&s->dma_lock);
+}
+
+/* 
+ * Alsa section
+ * PCM settings and callbacks
+ */
+static int snd_omap_alsa_trigger(snd_pcm_substream_t * substream, int cmd)
+{
+       struct snd_card_omap_codec *chip =
+           snd_pcm_substream_chip(substream);
+       int stream_id = substream->pstr->stream;
+       struct audio_stream *s = &chip->s[stream_id];
+       int err = 0;
+       
+       ADEBUG();
+       /* note local interrupts are already disabled in the midlevel code */
+       spin_lock(&s->dma_lock);
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               /* requested stream startup */
+               s->active = 1;
+               audio_process_dma(s);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               /* requested stream shutdown */
+               audio_stop_dma(s);
+               break;
+       default:
+               err = -EINVAL;
+               break;
+       }
+       spin_unlock(&s->dma_lock);
+       
+       return err;
+}
+
+static int snd_omap_alsa_prepare(snd_pcm_substream_t * substream)
+{
+       struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
+       snd_pcm_runtime_t *runtime = substream->runtime;
+       struct audio_stream *s = &chip->s[substream->pstr->stream];
+       
+       ADEBUG();
+       /* set requested samplerate */
+       alsa_codec_config->codec_set_samplerate(runtime->rate);
+       chip->samplerate = runtime->rate;
+
+       s->period = 0;
+       s->periods = 0;
+
+       return 0;
+}
+
+static snd_pcm_uframes_t snd_omap_alsa_pointer(snd_pcm_substream_t *substream)
+{
+       struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
+
+       ADEBUG();       
+       return audio_get_dma_pos(&chip->s[substream->pstr->stream]);
+}
+
+static int snd_card_omap_alsa_open(snd_pcm_substream_t * substream)
+{
+       struct snd_card_omap_codec *chip =
+           snd_pcm_substream_chip(substream);
+       snd_pcm_runtime_t *runtime = substream->runtime;
+       int stream_id = substream->pstr->stream;
+       int err;
+       
+       ADEBUG();
+       chip->s[stream_id].stream = substream;
+       alsa_codec_config->codec_clock_on();
+       if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) 
+               runtime->hw = *(alsa_codec_config->snd_omap_alsa_playback);
+       else 
+               runtime->hw = *(alsa_codec_config->snd_omap_alsa_capture);
+       
+       if ((err = snd_pcm_hw_constraint_integer(runtime,
+                                          SNDRV_PCM_HW_PARAM_PERIODS)) < 0) 
+               return err;
+       
+       if ((err = snd_pcm_hw_constraint_list(runtime,
+                                       0,
+                                       SNDRV_PCM_HW_PARAM_RATE,
+                                       alsa_codec_config->hw_constraints_rates)) < 0) 
+               return err;
+       
+       return 0;
+}
+
+static int snd_card_omap_alsa_close(snd_pcm_substream_t * substream)
+{
+       struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
+       
+       ADEBUG();
+       alsa_codec_config->codec_clock_off();
+       chip->s[substream->pstr->stream].stream = NULL;
+       
+       return 0;
+}
+
+/* HW params & free */
+static int snd_omap_alsa_hw_params(snd_pcm_substream_t * substream,
+                                   snd_pcm_hw_params_t * hw_params)
+{
+       return snd_pcm_lib_malloc_pages(substream,
+                                       params_buffer_bytes(hw_params));
+}
+
+static int snd_omap_alsa_hw_free(snd_pcm_substream_t * substream)
+{
+       return snd_pcm_lib_free_pages(substream);
+}
+
+/* pcm operations */
+static snd_pcm_ops_t snd_card_omap_alsa_playback_ops = {
+       .open =         snd_card_omap_alsa_open,
+       .close =        snd_card_omap_alsa_close,
+       .ioctl =        snd_pcm_lib_ioctl,
+       .hw_params =    snd_omap_alsa_hw_params,
+       .hw_free =      snd_omap_alsa_hw_free,
+       .prepare =      snd_omap_alsa_prepare,
+       .trigger =      snd_omap_alsa_trigger,
+       .pointer =      snd_omap_alsa_pointer,
+};
+
+static snd_pcm_ops_t snd_card_omap_alsa_capture_ops = {
+       .open =         snd_card_omap_alsa_open,
+       .close =        snd_card_omap_alsa_close,
+       .ioctl =        snd_pcm_lib_ioctl,
+       .hw_params =    snd_omap_alsa_hw_params,
+       .hw_free =      snd_omap_alsa_hw_free,
+       .prepare =      snd_omap_alsa_prepare,
+       .trigger =      snd_omap_alsa_trigger,
+       .pointer =      snd_omap_alsa_pointer,
+};
+
+/*
+ *  Alsa init and exit section
+ *  
+ *  Inits pcm alsa structures, allocate the alsa buffer, suspend, resume
+ */
+static int __init snd_card_omap_alsa_pcm(struct snd_card_omap_codec *omap_alsa, 
+                                       int device)
+{
+       snd_pcm_t *pcm;
+       int err;
+       
+       ADEBUG();
+       if ((err = snd_pcm_new(omap_alsa->card, "OMAP PCM", device, 1, 1, &pcm)) < 0)
+               return err;
+
+       /* sets up initial buffer with continuous allocation */
+       snd_pcm_lib_preallocate_pages_for_all(pcm,
+                                             SNDRV_DMA_TYPE_CONTINUOUS,
+                                             snd_dma_continuous_data
+                                             (GFP_KERNEL),
+                                             128 * 1024, 128 * 1024);
+
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                       &snd_card_omap_alsa_playback_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+                       &snd_card_omap_alsa_capture_ops);
+       pcm->private_data = omap_alsa;
+       pcm->info_flags = 0;
+       strcpy(pcm->name, "omap alsa pcm");
+
+       omap_alsa_audio_init(omap_alsa);
+
+       /* setup DMA controller */
+       audio_dma_request(&omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK],
+                         callback_omap_alsa_sound_dma);
+       audio_dma_request(&omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE],
+                         callback_omap_alsa_sound_dma);
+
+       omap_alsa->pcm = pcm;
+
+       return 0;
+}
+
+
+#ifdef CONFIG_PM
+/*
+ * Driver suspend/resume - calls alsa functions. Some hints from aaci.c
+ */
+int snd_omap_alsa_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct snd_card_omap_codec *chip;
+       snd_card_t *card = platform_get_drvdata(pdev);
+       
+       if (card->power_state != SNDRV_CTL_POWER_D3hot) {
+               chip = card->private_data;
+               if (chip->card->power_state != SNDRV_CTL_POWER_D3hot) {
+                       snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
+                       snd_pcm_suspend_all(chip->pcm);
+                       /* Mutes and turn clock off */
+                       alsa_codec_config->codec_clock_off();
+                       snd_omap_suspend_mixer();
+               }
+       }
+       return 0;
+}
+
+int snd_omap_alsa_resume(struct platform_device *pdev)
+{
+       struct snd_card_omap_codec *chip;
+       snd_card_t *card = platform_get_drvdata(pdev);
+
+       if (card->power_state != SNDRV_CTL_POWER_D0) {                          
+               chip = card->private_data;
+               if (chip->card->power_state != SNDRV_CTL_POWER_D0) {
+                       snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
+                       alsa_codec_config->codec_clock_on();
+                       snd_omap_resume_mixer();
+               }
+       }
+       return 0;
+}
+
+#endif /* CONFIG_PM */
+
+void snd_omap_alsa_free(snd_card_t * card)
+{
+       struct snd_card_omap_codec *chip = card->private_data;
+       ADEBUG();
+       
+       /*
+        * Turn off codec after it is done.
+        * Can't do it immediately, since it may still have
+        * buffered data.
+        */
+       schedule_timeout_interruptible(2);
+
+       omap_mcbsp_stop(AUDIO_MCBSP);
+       omap_mcbsp_free(AUDIO_MCBSP);
+
+       audio_dma_free(&chip->s[SNDRV_PCM_STREAM_PLAYBACK]);
+       audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]);
+}
+
+/* module init & exit */
+
+/* 
+ * Inits alsa soudcard structure.
+ * Called by the probe method in codec after function pointers has been set.
+ */
+int snd_omap_alsa_post_probe(struct platform_device *pdev, struct omap_alsa_codec_config *config)
+{
+       int err = 0;
+       int def_rate;
+       snd_card_t *card;
+       
+       ADEBUG();
+       alsa_codec_config       = config;
+
+       alsa_codec_config->codec_clock_setup();
+       alsa_codec_config->codec_clock_on(); 
+
+       omap_mcbsp_request(AUDIO_MCBSP);
+       omap_mcbsp_stop(AUDIO_MCBSP);
+       omap_mcbsp_config(AUDIO_MCBSP, alsa_codec_config->mcbsp_regs_alsa);
+       omap_mcbsp_start(AUDIO_MCBSP);
+       
+       if (alsa_codec_config && alsa_codec_config->codec_configure_dev)
+               alsa_codec_config->codec_configure_dev();
+
+       alsa_codec_config->codec_clock_off();
+
+       /* register the soundcard */
+       card = snd_card_new(-1, id, THIS_MODULE, sizeof(alsa_codec));
+       if (card == NULL)
+               goto nodev1;
+
+       alsa_codec = kcalloc(1, sizeof(*alsa_codec), GFP_KERNEL);
+       if (alsa_codec == NULL)
+               goto nodev2;
+
+       card->private_data = (void *)alsa_codec;
+       card->private_free = snd_omap_alsa_free;
+
+       alsa_codec->card        = card;
+       def_rate                = alsa_codec_config->get_default_samplerate(); 
+       alsa_codec->samplerate  = def_rate;
+
+       spin_lock_init(&alsa_codec->s[0].dma_lock);
+       spin_lock_init(&alsa_codec->s[1].dma_lock);
+
+       /* mixer */
+       if ((err = snd_omap_mixer(alsa_codec)) < 0)
+               goto nodev3;
+
+       /* PCM */
+       if ((err = snd_card_omap_alsa_pcm(alsa_codec, 0)) < 0)
+               goto nodev3;
+
+       strcpy(card->driver, "OMAP_ALSA");
+       strcpy(card->shortname, alsa_codec_config->name);
+       sprintf(card->longname, alsa_codec_config->name);
+
+       snd_omap_init_mixer();
+       snd_card_set_dev(card, &pdev->dev);
+       
+       if ((err = snd_card_register(card)) == 0) {
+               printk(KERN_INFO "audio support initialized\n");
+               platform_set_drvdata(pdev, card);
+               return 0;
+       }
+       
+nodev3:
+       kfree(alsa_codec);      
+nodev2:        
+       snd_card_free(card);
+nodev1:
+       omap_mcbsp_stop(AUDIO_MCBSP);
+       omap_mcbsp_free(AUDIO_MCBSP);
+
+       return err;
+}
+
+int snd_omap_alsa_remove(struct platform_device *pdev)
+{
+       snd_card_t *card = platform_get_drvdata(pdev);
+       struct snd_card_omap_codec *chip = card->private_data;
+       
+       snd_card_free(card);
+
+       alsa_codec = NULL;
+       card->private_data = NULL;
+       kfree(chip);
+       
+       platform_set_drvdata(pdev, NULL);
+       
+       return 0;
+}
index 2489bd6bb08561ab5e8cc296eca87d20427a354b..e0b15e9d4f16242d6f7797822a9a38f1745386ca 100644 (file)
@@ -8,6 +8,10 @@
 obj-$(CONFIG_SOUND_OSS)                += sound.o
 obj-$(CONFIG_SOUND_CS4232)     += cs4232.o ad1848.o 
 
+obj-$(CONFIG_SOUND_OMAP)        += omap-audio-dma-intfc.o omap-audio.o
+obj-$(CONFIG_SOUND_OMAP_TSC2101)+= omap-audio-tsc2101.o
+obj-$(CONFIG_SOUND_OMAP_AIC23)  += omap-audio-aic23.o
+
 # Please leave it as is, cause the link order is significant !
 
 obj-$(CONFIG_SOUND_SH_DAC_AUDIO)       += sh_dac_audio.o
diff --git a/sound/oss/omap-audio-aic23.c b/sound/oss/omap-audio-aic23.c
new file mode 100644 (file)
index 0000000..0ecb2f7
--- /dev/null
@@ -0,0 +1,754 @@
+/*
+ * linux/sound/oss/omap-audio-aic23.c
+ *
+ * Glue audio driver for TI TLV320AIC23 codec
+ *
+ * Copyright (c) 2000 Nicolas Pitre <nico@cam.org>
+ * Copyright (C) 2001, Steve Johnson <stevej@ridgerun.com>
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ * Copyright (C) 2005 Dirk Behme <dirk.behme@de.bosch.com>
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/errno.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+
+#include <asm/uaccess.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/mcbsp.h>
+#include <asm/arch/fpga.h>
+#include <asm/arch/aic23.h>
+#include <asm/arch/clock.h>
+
+#include "omap-audio.h"
+#include "omap-audio-dma-intfc.h"
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#define PROC_START_FILE "driver/aic23-audio-start"
+#define PROC_STOP_FILE  "driver/aic23-audio-stop"
+#endif
+
+//#define DEBUG
+
+#ifdef DEBUG
+#define DPRINTK(ARGS...)  printk("<%s>: ",__FUNCTION__);printk(ARGS)
+#else
+#define DPRINTK( x... )
+#endif
+
+#define CODEC_NAME              "AIC23"
+
+#if CONFIG_MACH_OMAP_OSK
+#define PLATFORM_NAME            "OMAP OSK"
+#elif CONFIG_MACH_OMAP_INNOVATOR
+#define PLATFORM_NAME            "OMAP INNOVATOR"
+#else
+#error "Unsupported plattform"
+#endif
+
+/* Define to set the AIC23 as the master w.r.t McBSP */
+#define AIC23_MASTER
+
+#define CODEC_CLOCK                   12000000
+
+/*
+ * AUDIO related MACROS
+ */
+#define DEFAULT_BITPERSAMPLE          16
+#define AUDIO_RATE_DEFAULT           44100
+
+/* Select the McBSP For Audio */
+#define AUDIO_MCBSP                   OMAP_MCBSP1
+
+#define REC_MASK                     (SOUND_MASK_LINE | SOUND_MASK_MIC)
+#define DEV_MASK                     (REC_MASK | SOUND_MASK_VOLUME)
+
+#define SET_VOLUME                   1
+#define SET_LINE                     2
+
+#define DEFAULT_OUTPUT_VOLUME         93
+#define DEFAULT_INPUT_VOLUME          0        /* 0 ==> mute line in */
+
+#define OUTPUT_VOLUME_MIN             LHV_MIN
+#define OUTPUT_VOLUME_MAX             LHV_MAX
+#define OUTPUT_VOLUME_RANGE           (OUTPUT_VOLUME_MAX - OUTPUT_VOLUME_MIN)
+#define OUTPUT_VOLUME_MASK            OUTPUT_VOLUME_MAX
+
+#define INPUT_VOLUME_MIN             LIV_MIN
+#define INPUT_VOLUME_MAX             LIV_MAX
+#define INPUT_VOLUME_RANGE           (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
+#define INPUT_VOLUME_MASK            INPUT_VOLUME_MAX
+
+#define NUMBER_SAMPLE_RATES_SUPPORTED 9
+
+/*
+ * HW interface start and stop helper functions
+ */
+static int audio_ifc_start(void)
+{
+       omap_mcbsp_start(AUDIO_MCBSP);
+       return 0;
+}
+
+static int audio_ifc_stop(void)
+{
+       omap_mcbsp_stop(AUDIO_MCBSP);
+       return 0;
+}
+
+static audio_stream_t output_stream = {
+        .id              = "AIC23 out",
+        .dma_dev         = OMAP_DMA_MCBSP1_TX,
+       .input_or_output = FMODE_WRITE,
+       .hw_start       = audio_ifc_start,
+       .hw_stop         = audio_ifc_stop
+};
+
+static audio_stream_t input_stream = {
+        .id              = "AIC23 in",
+        .dma_dev         = OMAP_DMA_MCBSP1_RX,
+       .input_or_output = FMODE_READ,
+       .hw_start       = audio_ifc_start,
+       .hw_stop         = audio_ifc_stop
+};
+
+static struct clk *aic23_mclk = 0;
+
+static int audio_dev_id, mixer_dev_id;
+
+static struct aic23_local_info {
+        u8  volume;
+        u16 volume_reg;
+        u8  line;
+        u8  mic;
+        u16 input_volume_reg;
+        int mod_cnt;
+} aic23_local;
+
+struct sample_rate_reg_info {
+        u32 sample_rate;
+        u8  control;            /* SR3, SR2, SR1, SR0 and BOSR */
+        u8  divider;           /* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */
+};
+
+/* To Store the default sample rate */
+static long audio_samplerate = AUDIO_RATE_DEFAULT;
+
+/* DAC USB-mode sampling rates (MCLK = 12 MHz) */
+static const struct sample_rate_reg_info
+reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
+        {96000, 0x0E, 0},
+        {88200, 0x1F, 0},
+        {48000, 0x00, 0},
+        {44100, 0x11, 0},
+        {32000, 0x0C, 0},
+        {24000, 0x00, 1},
+        {16000, 0x0C, 1},
+        { 8000, 0x06, 0},
+        { 4000, 0x06, 1},
+};
+
+static struct omap_mcbsp_reg_cfg initial_config = {
+        .spcr2 = FREE | FRST | GRST | XRST | XINTM(3),
+        .spcr1 = RINTM(3) | RRST,
+        .rcr2  = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) |
+       RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(0),
+        .rcr1  = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16),
+        .xcr2  = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) |
+        XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(0) | XFIG,
+        .xcr1  = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16),
+        .srgr1 = FWID(DEFAULT_BITPERSAMPLE - 1),
+        .srgr2 = GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1),
+#ifndef AIC23_MASTER
+        /* configure McBSP to be the I2S master */
+        .pcr0  = FSXM | FSRM | CLKXM | CLKRM | CLKXP | CLKRP,
+#else
+        /* configure McBSP to be the I2S slave */
+        .pcr0  = CLKXP | CLKRP,
+#endif /* AIC23_MASTER */
+};
+
+static void omap_aic23_initialize(void *dummy);
+static void omap_aic23_shutdown(void *dummy);
+static int  omap_aic23_ioctl(struct inode *inode, struct file *file,
+                             uint cmd, ulong arg);
+static int  omap_aic23_probe(void);
+#ifdef MODULE
+static void omap_aic23_remove(void);
+#endif
+static int  omap_aic23_suspend(void);
+static int  omap_aic23_resume(void);
+static inline void aic23_configure(void);
+static int  mixer_open(struct inode *inode, struct file *file);
+static int  mixer_release(struct inode *inode, struct file *file);
+static int  mixer_ioctl(struct inode *inode, struct file *file, uint cmd,
+                        ulong arg);
+
+#ifdef CONFIG_PROC_FS
+static int codec_start(char *buf, char **start, off_t offset, int count,
+                       int *eof, void *data);
+static int codec_stop(char *buf, char **start, off_t offset, int count,
+                      int *eof, void *data);
+#endif
+
+
+/* File Op structure for mixer */
+static struct file_operations omap_mixer_fops = {
+        .open           = mixer_open,
+        .release        = mixer_release,
+        .ioctl          = mixer_ioctl,
+        .owner          = THIS_MODULE
+};
+
+/* To store characteristic info regarding the codec for the audio driver */
+static audio_state_t aic23_state = {
+        .output_stream  = &output_stream,
+        .input_stream   = &input_stream,
+/*     .need_tx_for_rx = 1, //Once the Full Duplex works  */
+        .need_tx_for_rx = 0,
+        .hw_init        = omap_aic23_initialize,
+        .hw_shutdown    = omap_aic23_shutdown,
+        .client_ioctl   = omap_aic23_ioctl,
+        .hw_probe       = omap_aic23_probe,
+        .hw_remove      =  __exit_p(omap_aic23_remove),
+        .hw_suspend     = omap_aic23_suspend,
+        .hw_resume      = omap_aic23_resume,
+};
+
+/* This will be defined in the audio.h */
+static struct file_operations *omap_audio_fops;
+
+extern int aic23_write_value(u8 reg, u16 value);
+
+/* TLV320AIC23 is a write only device */
+static __inline__ void audio_aic23_write(u8 address, u16 data)
+{
+        aic23_write_value(address, data);
+}
+
+static int aic23_update(int flag, int val)
+{
+        u16 volume;
+
+        /* Ignore separate left/right channel for now,
+           even the codec does support it. */
+        val &= 0xff;
+
+        if (val < 0 || val > 100) {
+                printk(KERN_ERR "Trying a bad volume value(%d)!\n",val);
+                return -EPERM;
+        }
+
+        switch (flag) {
+        case SET_VOLUME:
+                // Convert 0 -> 100 volume to 0x00 (LHV_MIN) -> 0x7f (LHV_MAX) 
+                // volume range
+                volume = ((val * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MIN;
+                
+                // R/LHV[6:0] 1111111 (+6dB) to 0000000 (-73dB) in 1db steps,
+                // default 1111001 (0dB)
+                aic23_local.volume_reg &= ~OUTPUT_VOLUME_MASK;
+                aic23_local.volume_reg |= volume;
+                audio_aic23_write(LEFT_CHANNEL_VOLUME_ADDR, aic23_local.volume_reg);
+                audio_aic23_write(RIGHT_CHANNEL_VOLUME_ADDR, aic23_local.volume_reg);
+                break;
+
+        case SET_LINE:
+                // Convert 0 -> 100 volume to 0x0 (LIV_MIN) -> 0x1f (LIV_MAX) 
+                // volume range
+                volume = ((val * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
+
+                // R/LIV[4:0] 11111 (+12dB) to 00000 (-34.5dB) in 1.5dB steps,
+                // default 10111 (0dB)
+                aic23_local.input_volume_reg &= ~INPUT_VOLUME_MASK;
+                aic23_local.input_volume_reg |= volume;
+                audio_aic23_write(LEFT_LINE_VOLUME_ADDR, aic23_local.input_volume_reg);
+                audio_aic23_write(RIGHT_LINE_VOLUME_ADDR, aic23_local.input_volume_reg);
+                break;
+        }
+        return 0;
+}
+
+static int mixer_open(struct inode *inode, struct file *file)
+{
+        /* Any mixer specific initialization */
+
+        return 0;
+}
+
+static int mixer_release(struct inode *inode, struct file *file)
+{
+        /* Any mixer specific Un-initialization */
+
+        return 0;
+}
+
+static int
+mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+        int val;
+        int ret = 0;
+        int nr = _IOC_NR(cmd);
+
+        /*
+         * We only accept mixer (type 'M') ioctls.
+         */
+        if (_IOC_TYPE(cmd) != 'M')
+                return -EINVAL;
+
+        DPRINTK(" 0x%08x\n", cmd);
+
+        if (cmd == SOUND_MIXER_INFO) {
+                struct mixer_info mi;
+
+                strncpy(mi.id, "AIC23", sizeof(mi.id));
+                strncpy(mi.name, "TI AIC23", sizeof(mi.name));
+                mi.modify_counter = aic23_local.mod_cnt;
+                return copy_to_user((void *)arg, &mi, sizeof(mi));
+        }
+
+        if (_IOC_DIR(cmd) & _IOC_WRITE) {
+                ret = get_user(val, (int *)arg);
+                if (ret)
+                        goto out;
+
+        
+                switch (nr) {
+                case SOUND_MIXER_VOLUME:
+                        aic23_local.volume = val;
+                        aic23_local.mod_cnt++;
+                        ret = aic23_update(SET_VOLUME, val);
+                        break;
+
+                case SOUND_MIXER_LINE:
+                        aic23_local.line = val;
+                        aic23_local.mod_cnt++;
+                        ret = aic23_update(SET_LINE, val);
+                        break;
+
+                case SOUND_MIXER_MIC:
+                        aic23_local.mic = val;
+                        aic23_local.mod_cnt++;
+                        ret = aic23_update(SET_LINE, val);
+                        break;
+
+                case SOUND_MIXER_RECSRC:
+                        break;
+
+                default:
+                        ret = -EINVAL;
+                }
+        }
+
+        if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {
+                ret = 0;
+
+                switch (nr) {
+                case SOUND_MIXER_VOLUME:
+                        val = aic23_local.volume;
+                        break;
+                case SOUND_MIXER_LINE:
+                        val = aic23_local.line;
+                        break;
+                case SOUND_MIXER_MIC:
+                        val = aic23_local.mic;
+                        break;
+                case SOUND_MIXER_RECSRC:
+                        val = REC_MASK;
+                        break;
+                case SOUND_MIXER_RECMASK:
+                        val = REC_MASK;
+                        break;
+                case SOUND_MIXER_DEVMASK:
+                        val = DEV_MASK;
+                        break;
+                case SOUND_MIXER_CAPS:
+                        val = 0;
+                        break;
+                case SOUND_MIXER_STEREODEVS:
+                        val = 0;
+                        break;
+                default:
+                        val = 0;
+                        ret = -EINVAL;
+                        break;
+                }
+
+                if (ret == 0)
+                        ret = put_user(val, (int *)arg);
+        }
+out:
+        return ret;
+
+}
+
+int omap_set_samplerate(long sample_rate)
+{
+        u8 count = 0;
+        u16 data = 0;
+        /* wait for any frame to complete */
+        udelay(125);
+
+        /* Search for the right sample rate */
+        while ((reg_info[count].sample_rate != sample_rate) &&
+               (count < NUMBER_SAMPLE_RATES_SUPPORTED)) {
+                count++;
+        }
+        if (count == NUMBER_SAMPLE_RATES_SUPPORTED) {
+                printk(KERN_ERR "Invalid Sample Rate %d requested\n",
+                       (int)sample_rate);
+                return -EPERM;
+        }
+
+        if (machine_is_omap_innovator()) {
+                /* set the CODEC clock input source to 12.000MHz */
+                fpga_write(fpga_read(OMAP1510_FPGA_POWER) & ~0x01, 
+                           OMAP1510_FPGA_POWER);
+        }
+
+        data = (reg_info[count].divider << CLKIN_SHIFT) | 
+                (reg_info[count].control << BOSR_SHIFT) | USB_CLK_ON;
+
+        audio_aic23_write(SAMPLE_RATE_CONTROL_ADDR, data);
+
+        audio_samplerate = sample_rate;
+
+#ifndef AIC23_MASTER
+        {
+                int clkgdv = 0;
+                /* 
+                   Set Sample Rate at McBSP
+
+                   Formula : 
+                   Codec System Clock = CODEC_CLOCK, or half if clock_divider = 1;
+                   clkgdv = ((Codec System Clock / (SampleRate * BitsPerSample * 2)) - 1);
+
+                   FWID = BitsPerSample - 1;
+                   FPER = (BitsPerSample * 2) - 1;
+                */  
+                if (reg_info[count].divider)
+                        clkgdv = CODEC_CLOCK / 2;
+                else 
+                        clkgdv = CODEC_CLOCK;
+
+                clkgdv = (clkgdv / (sample_rate * DEFAULT_BITPERSAMPLE * 2)) - 1;
+
+                initial_config.srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+
+                initial_config.srgr2 =
+                        (CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1));
+
+                omap_mcbsp_config(AUDIO_MCBSP, &initial_config);
+        }
+#endif /* AIC23_MASTER */
+
+        return 0;
+}
+
+static void omap_aic23_initialize(void *dummy)
+{
+        DPRINTK("entry\n");
+
+        /* initialize with default sample rate */
+        audio_samplerate = AUDIO_RATE_DEFAULT;
+
+        omap_mcbsp_request(AUDIO_MCBSP);
+
+        /* if configured, then stop mcbsp */
+        omap_mcbsp_stop(AUDIO_MCBSP);
+
+        omap_mcbsp_config(AUDIO_MCBSP, &initial_config);
+        omap_mcbsp_start(AUDIO_MCBSP);
+        aic23_configure();
+
+        DPRINTK("exit\n");
+}
+
+static void omap_aic23_shutdown(void *dummy)
+{
+        /*
+          Turn off codec after it is done.
+          Can't do it immediately, since it may still have
+          buffered data.
+
+          Wait 20ms (arbitrary value) and then turn it off.
+        */
+
+        set_current_state(TASK_INTERRUPTIBLE);
+        schedule_timeout(2);
+
+        omap_mcbsp_stop(AUDIO_MCBSP);
+        omap_mcbsp_free(AUDIO_MCBSP);
+
+        audio_aic23_write(RESET_CONTROL_ADDR, 0);
+        audio_aic23_write(POWER_DOWN_CONTROL_ADDR, 0xff);
+}
+
+static inline void aic23_configure()
+{
+        /* Reset codec */
+        audio_aic23_write(RESET_CONTROL_ADDR, 0);
+
+        /* Initialize the AIC23 internal state */
+
+        /* Left/Right line input volume control */
+        aic23_local.line = DEFAULT_INPUT_VOLUME;
+        aic23_local.mic = DEFAULT_INPUT_VOLUME;
+        aic23_update(SET_LINE, DEFAULT_INPUT_VOLUME);
+
+        /* Left/Right headphone channel volume control */
+        /* Zero-cross detect on */
+        aic23_local.volume_reg = LZC_ON;
+        aic23_update(SET_VOLUME, aic23_local.volume);
+
+        /* Analog audio path control, DAC selected, delete INSEL_MIC for line in */
+        audio_aic23_write(ANALOG_AUDIO_CONTROL_ADDR, DAC_SELECTED | INSEL_MIC);
+
+        /* Digital audio path control, de-emphasis control 44.1kHz */
+        audio_aic23_write(DIGITAL_AUDIO_CONTROL_ADDR, DEEMP_44K);
+
+        /* Power control, everything is on */
+        audio_aic23_write(POWER_DOWN_CONTROL_ADDR, 0);
+
+        /* Digital audio interface, master/slave mode, I2S, 16 bit */
+#ifdef AIC23_MASTER
+        audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR, MS_MASTER | IWL_16 | FOR_DSP);
+#else
+        audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR, IWL_16 | FOR_DSP);
+#endif /* AIC23_MASTER */
+
+        /* Enable digital interface */
+        audio_aic23_write(DIGITAL_INTERFACE_ACT_ADDR, ACT_ON);
+
+        /* clock configuration */
+        omap_set_samplerate(audio_samplerate);
+}
+
+static int
+omap_aic23_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+        long val;
+        int ret = 0;
+
+        DPRINTK(" 0x%08x\n", cmd);
+
+        /*
+         * These are platform dependent ioctls which are not handled by the
+         * generic omap-audio module.
+         */
+        switch (cmd) {
+        case SNDCTL_DSP_STEREO:
+                ret = get_user(val, (int *)arg);
+                if (ret)
+                        return ret;
+                /* the AIC23 is stereo only */
+                ret = (val == 0) ? -EINVAL : 1;
+                return put_user(ret, (int *)arg);
+
+        case SNDCTL_DSP_CHANNELS:
+        case SOUND_PCM_READ_CHANNELS:
+                /* the AIC23 is stereo only */
+                return put_user(2, (long *)arg);
+
+        case SNDCTL_DSP_SPEED:
+                ret = get_user(val, (long *)arg);
+                if (ret)
+                        break;
+                ret = omap_set_samplerate(val);
+                if (ret)
+                        break;
+                /* fall through */
+
+        case SOUND_PCM_READ_RATE:
+                return put_user(audio_samplerate, (long *)arg);
+
+        case SOUND_PCM_READ_BITS:
+        case SNDCTL_DSP_SETFMT:
+        case SNDCTL_DSP_GETFMTS:
+                /* we can do 16-bit only */
+                return put_user(AFMT_S16_LE, (long *)arg);
+
+        default:
+                /* Maybe this is meant for the mixer (As per OSS Docs) */
+                return mixer_ioctl(inode, file, cmd, arg);
+        }
+
+        return ret;
+}
+
+static int omap_aic23_probe(void)
+{
+        /* Get the fops from audio oss driver */
+        if (!(omap_audio_fops = audio_get_fops())) {
+                printk(KERN_ERR "Unable to get the file operations for AIC23 OSS driver\n");
+                audio_unregister_codec(&aic23_state);
+                return -EPERM;
+        }
+
+        aic23_local.volume = DEFAULT_OUTPUT_VOLUME;
+
+        /* register devices */
+        audio_dev_id = register_sound_dsp(omap_audio_fops, -1);
+        mixer_dev_id = register_sound_mixer(&omap_mixer_fops, -1);
+
+#ifdef CONFIG_PROC_FS
+        create_proc_read_entry(PROC_START_FILE, 0 /* default mode */ ,
+                               NULL /* parent dir */ ,
+                               codec_start, NULL /* client data */ );
+
+        create_proc_read_entry(PROC_STOP_FILE, 0 /* default mode */ ,
+                               NULL /* parent dir */ ,
+                               codec_stop, NULL /* client data */ );
+#endif
+
+        /* Announcement Time */
+        printk(KERN_INFO PLATFORM_NAME " " CODEC_NAME
+               " audio support initialized\n");
+        return 0;
+}
+
+#ifdef MODULE
+static void __exit omap_aic23_remove(void)
+{
+        /* Un-Register the codec with the audio driver */
+        unregister_sound_dsp(audio_dev_id);
+        unregister_sound_mixer(mixer_dev_id);
+
+#ifdef CONFIG_PROC_FS
+        remove_proc_entry(PROC_START_FILE, NULL);
+        remove_proc_entry(PROC_STOP_FILE, NULL);
+#endif
+}
+#endif /* MODULE */
+
+static int omap_aic23_suspend(void)
+{
+        /* Empty for the moment */
+        return 0;
+}
+
+static int omap_aic23_resume(void)
+{
+        /* Empty for the moment */
+        return 0;
+}
+
+static int __init audio_aic23_init(void)
+{
+
+        int err = 0;
+
+       if (machine_is_omap_h2() || machine_is_omap_h3())
+               return -ENODEV;
+
+       mutex_init(&aic23_state.mutex);
+
+        if (machine_is_omap_osk()) {
+                /* Set MCLK to be clock input for AIC23 */
+                aic23_mclk = clk_get(0, "mclk");
+            
+                if(clk_get_rate( aic23_mclk) != CODEC_CLOCK){
+                        /* MCLK ist not at CODEC_CLOCK */
+                        if( clk_get_usecount(aic23_mclk) > 0 ){
+                                /* MCLK is already in use */
+                                printk(KERN_WARNING "MCLK in use at %d Hz. We change it to %d Hz\n",
+                                       (uint)clk_get_rate( aic23_mclk), CODEC_CLOCK);
+                        }
+                        if( clk_set_rate( aic23_mclk, CODEC_CLOCK ) ){
+                                printk(KERN_ERR "Cannot set MCLK for AIC23 CODEC\n");
+                                return -ECANCELED;
+                       }
+               }
+
+                clk_enable( aic23_mclk );
+
+                DPRINTK("MCLK = %d [%d], usecount = %d\n",(uint)clk_get_rate( aic23_mclk ), 
+                        CODEC_CLOCK, clk_get_usecount( aic23_mclk));
+        }
+
+        if (machine_is_omap_innovator()) {
+                u8 fpga;
+                /*
+                  Turn on chip select for CODEC (shared with touchscreen).  
+                  Don't turn it back off, in case touch screen needs it.
+                */                           
+                fpga = fpga_read(OMAP1510_FPGA_TOUCHSCREEN);
+                fpga |= 0x4;
+                fpga_write(fpga, OMAP1510_FPGA_TOUCHSCREEN);
+        }
+
+        /* register the codec with the audio driver */
+        if ((err = audio_register_codec(&aic23_state))) {
+                printk(KERN_ERR
+                       "Failed to register AIC23 driver with Audio OSS Driver\n");
+        }
+
+        return err;
+}
+
+static void __exit audio_aic23_exit(void)
+{
+        (void)audio_unregister_codec(&aic23_state);
+        return;
+}
+
+#ifdef CONFIG_PROC_FS
+static int codec_start(char *buf, char **start, off_t offset, int count,
+                       int *eof, void *data)
+{
+        void *foo = NULL;
+
+        omap_aic23_initialize(foo);
+
+        printk("AIC23 codec initialization done.\n");
+        return 0;
+}
+static int codec_stop(char *buf, char **start, off_t offset, int count,
+                      int *eof, void *data)
+{
+        void *foo = NULL;
+
+        omap_aic23_shutdown(foo);
+
+        printk("AIC23 codec shutdown.\n");
+        return 0;
+}
+#endif /* CONFIG_PROC_FS */
+
+module_init(audio_aic23_init);
+module_exit(audio_aic23_exit);
+
+MODULE_AUTHOR("Dirk Behme <dirk.behme@de.bosch.com>");
+MODULE_DESCRIPTION("Glue audio driver for the TI AIC23 codec.");
+MODULE_LICENSE("GPL");
diff --git a/sound/oss/omap-audio-dma-intfc.c b/sound/oss/omap-audio-dma-intfc.c
new file mode 100644 (file)
index 0000000..146e288
--- /dev/null
@@ -0,0 +1,986 @@
+/*
+ * linux/sound/oss/omap-audio-dma-intfc.c
+ *
+ * Common audio DMA handling for the OMAP processors
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
+ *
+ * This package 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.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ * 2004-06-07  Sriram Kannan   - Created new file from omap_audio_dma_intfc.c. This file
+ *                               will contain only the DMA interface and buffer handling of OMAP
+ *                               audio driver.
+ *
+ * 2004-06-22  Sriram Kannan   - removed legacy code (auto-init). Self-linking of DMA logical channel.
+ *
+ * 2004-08-12   Nishanth Menon  - Modified to integrate Audio requirements on 1610,1710 platforms
+ *
+ * 2004-11-01   Nishanth Menon  - 16xx platform code base modified to support multi channel chaining.
+ *
+ * 2004-12-15   Nishanth Menon  - Improved 16xx platform channel logic introduced - tasklets, queue handling updated
+ *
+ * 2005-12-10   Dirk Behme      - Added L/R Channel Interchange fix as proposed by Ajaya Babu
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/pm.h>
+#include <linux/errno.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <linux/sysrq.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/completion.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/semaphore.h>
+
+#include <asm/arch/dma.h>
+#include "omap-audio-dma-intfc.h"
+
+#include <asm/arch/mcbsp.h>
+
+#include "omap-audio.h"
+
+#undef DEBUG
+//#define DEBUG
+#ifdef DEBUG
+#define DPRINTK(ARGS...)  printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS)
+#define FN_IN printk(KERN_INFO "[%s]: start\n", __FUNCTION__)
+#define FN_OUT(n) printk(KERN_INFO "[%s]: end(%u)\n",__FUNCTION__, n)
+#else
+
+#define DPRINTK( x... )
+#define FN_IN
+#define FN_OUT(x)
+#endif
+
+#define ERR(ARGS...) printk(KERN_ERR "{%s}-ERROR: ", __FUNCTION__);printk(ARGS);
+
+#define AUDIO_NAME             "omap-audio"
+#define AUDIO_NBFRAGS_DEFAULT  8
+#define AUDIO_FRAGSIZE_DEFAULT 8192
+
+#define AUDIO_ACTIVE(state)    ((state)->rd_ref || (state)->wr_ref)
+
+#define SPIN_ADDR              (dma_addr_t)0
+#define SPIN_SIZE              2048
+
+/* Channel Queue Handling macros
+ * tail always points to the current free entry
+ * Head always points to the current entry being used
+ * end is either head or tail
+ */
+
+#define AUDIO_QUEUE_INIT(s) s->dma_q_head = s->dma_q_tail = s->dma_q_count = 0;
+#define AUDIO_QUEUE_FULL(s) (nr_linked_channels == s->dma_q_count)
+#define AUDIO_QUEUE_LAST(s) (1 == s->dma_q_count)
+#define AUDIO_QUEUE_EMPTY(s) (0 == s->dma_q_count)
+#define __AUDIO_INCREMENT_QUEUE(end) ((end)=((end)+1) % nr_linked_channels)
+#define AUDIO_INCREMENT_HEAD(s) __AUDIO_INCREMENT_QUEUE(s->dma_q_head); s->dma_q_count--;
+#define AUDIO_INCREMENT_TAIL(s) __AUDIO_INCREMENT_QUEUE(s->dma_q_tail); s->dma_q_count++;
+
+/* DMA buffer fragmentation sizes */
+#define MAX_DMA_SIZE            0x1000000
+#define CUT_DMA_SIZE            0x1000
+/* TODO: To be moved to more appropriate location */
+#define DCSR_ERROR           0x3
+#define DCSR_SYNC_SET        (1 << 6)
+
+#define DCCR_FS              (1 << 5)
+#define DCCR_PRIO            (1 << 6)
+#define DCCR_EN              (1 << 7)
+#define DCCR_AI              (1 << 8)
+#define DCCR_REPEAT          (1 << 9)
+/* if 0 the channel works in 3.1 compatible mode*/
+#define DCCR_N31COMP         (1 << 10)
+#define DCCR_EP              (1 << 11)
+#define DCCR_SRC_AMODE_BIT   12
+#define DCCR_SRC_AMODE_MASK  (0x3<<12)
+#define DCCR_DST_AMODE_BIT   14
+#define DCCR_DST_AMODE_MASK  (0x3<<14)
+#define AMODE_CONST          0x0
+#define AMODE_POST_INC       0x1
+#define AMODE_SINGLE_INDEX   0x2
+#define AMODE_DOUBLE_INDEX   0x3
+
+/**************************** DATA STRUCTURES *****************************************/
+
+static spinlock_t dma_list_lock = SPIN_LOCK_UNLOCKED;
+
+struct audio_isr_work_item {
+       int current_lch;
+       u16 ch_status;
+       audio_stream_t *s;
+};
+
+static char work_item_running = 0;
+static char nr_linked_channels = 1;
+static struct audio_isr_work_item work1, work2;
+
+
+/*********************************** MODULE SPECIFIC FUNCTIONS PROTOTYPES *************/
+
+static void audio_dsr_handler(unsigned long);
+static DECLARE_TASKLET(audio_isr_work1, audio_dsr_handler,
+               (unsigned long)&work1);
+static DECLARE_TASKLET(audio_isr_work2, audio_dsr_handler,
+               (unsigned long)&work2);
+
+static void sound_dma_irq_handler(int lch, u16 ch_status, void *data);
+static void audio_dma_callback(int lch, u16 ch_status, void *data);
+static int omap_start_sound_dma(audio_stream_t * s, dma_addr_t dma_ptr,
+                               u_int size);
+static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
+                                    u_int dma_size);
+static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
+                                       u_int dma_size);
+static int audio_start_dma_chain(audio_stream_t * s);
+
+/*********************************** GLOBAL FUNCTIONS DEFINTIONS ***********************/
+
+/***************************************************************************************
+ *
+ * Buffer creation/destruction
+ *
+ **************************************************************************************/
+int audio_setup_buf(audio_stream_t * s)
+{
+       int frag;
+       int dmasize = 0;
+       char *dmabuf = NULL;
+       dma_addr_t dmaphys = 0;
+       FN_IN;
+       if (s->buffers) {
+               FN_OUT(1);
+               return -EBUSY;
+       }
+       s->buffers = kmalloc(sizeof(audio_buf_t) * s->nbfrags, GFP_KERNEL);
+       if (!s->buffers)
+               goto err;
+       memset(s->buffers, 0, sizeof(audio_buf_t) * s->nbfrags);
+       for (frag = 0; frag < s->nbfrags; frag++) {
+               audio_buf_t *b = &s->buffers[frag];
+               /*
+                * Let's allocate non-cached memory for DMA buffers.
+                * We try to allocate all memory at once.
+                * If this fails (a common reason is memory fragmentation),
+                * then we allocate more smaller buffers.
+                */
+               if (!dmasize) {
+                       dmasize = (s->nbfrags - frag) * s->fragsize;
+                       do {
+                               dmabuf =
+                                   dma_alloc_coherent(NULL, dmasize, &dmaphys,
+                                                      0);
+                               if (!dmabuf)
+                                       dmasize -= s->fragsize;
+                       }
+                       while (!dmabuf && dmasize);
+                       if (!dmabuf)
+                               goto err;
+                       b->master = dmasize;
+                       memzero(dmabuf, dmasize);
+               }
+               b->data = dmabuf;
+               b->dma_addr = dmaphys;
+               dmabuf += s->fragsize;
+               dmaphys += s->fragsize;
+               dmasize -= s->fragsize;
+       }
+       s->usr_head = s->dma_head = s->dma_tail = 0;
+       AUDIO_QUEUE_INIT(s);
+       s->started = 0;
+       s->bytecount = 0;
+       s->fragcount = 0;
+       init_completion(&s->wfc);
+       s->wfc.done = s->nbfrags;
+       FN_OUT(0);
+       return 0;
+      err:
+       audio_discard_buf(s);
+       FN_OUT(1);
+       return -ENOMEM;
+}
+
+void audio_discard_buf(audio_stream_t * s)
+{
+       FN_IN;
+       /* ensure DMA isn't using those buffers */
+       audio_reset(s);
+       if (s->buffers) {
+               int frag;
+               for (frag = 0; frag < s->nbfrags; frag++) {
+                       if (!s->buffers[frag].master)
+                               continue;
+                       dma_free_coherent(NULL,
+                                         s->buffers[frag].master,
+                                         s->buffers[frag].data,
+                                         s->buffers[frag].dma_addr);
+               }
+               kfree(s->buffers);
+               s->buffers = NULL;
+       }
+       FN_OUT(0);
+}
+
+/***************************************************************************************
+ *
+ * DMA channel requests
+ *
+ **************************************************************************************/
+static void omap_sound_dma_link_lch(void *data)
+{
+       audio_stream_t *s = (audio_stream_t *) data;
+       int *chan = s->lch;
+       int i;
+
+       FN_IN;
+       if (s->linked) {
+               FN_OUT(1);
+               return;
+       }
+       for (i = 0; i < nr_linked_channels; i++) {
+               int cur_chan = chan[i];
+               int nex_chan =
+                   ((nr_linked_channels - 1 ==
+                     i) ? chan[0] : chan[i + 1]);
+               omap_dma_link_lch(cur_chan, nex_chan);
+       }
+       s->linked = 1;
+       FN_OUT(0);
+}
+
+int
+omap_request_sound_dma(int device_id, const char *device_name, void *data,
+                      int **channels)
+{
+       int i, err = 0;
+       int *chan = NULL;
+       FN_IN;
+       if (unlikely((NULL == channels) || (NULL == device_name))) {
+               BUG();
+               return -EPERM;
+       }
+       /* Try allocate memory for the num channels */
+       *channels =
+           (int *)kmalloc(sizeof(int) * nr_linked_channels,
+                          GFP_KERNEL);
+       chan = *channels;
+       if (NULL == chan) {
+               ERR("No Memory for channel allocs!\n");
+               FN_OUT(-ENOMEM);
+               return -ENOMEM;
+       }
+       spin_lock(&dma_list_lock);
+       for (i = 0; i < nr_linked_channels; i++) {
+               err =
+                   omap_request_dma(device_id, device_name,
+                                    sound_dma_irq_handler, data, &chan[i]);
+               /* Handle Failure condition here */
+               if (err < 0) {
+                       int j;
+                       for (j = 0; j < i; j++) {
+                               omap_free_dma(chan[j]);
+                       }
+                       spin_unlock(&dma_list_lock);
+                       kfree(chan);
+                       *channels = NULL;
+                       ERR("Error in requesting channel %d=0x%x\n", i, err);
+                       FN_OUT(err);
+                       return err;
+               }
+       }
+
+       /* Chain the channels together */
+       if (!cpu_is_omap15xx())
+               omap_sound_dma_link_lch(data);
+
+       spin_unlock(&dma_list_lock);
+       FN_OUT(0);
+       return 0;
+}
+
+/***************************************************************************************
+ *
+ * DMA channel requests Freeing
+ *
+ **************************************************************************************/
+static void omap_sound_dma_unlink_lch(void *data)
+{
+       audio_stream_t *s = (audio_stream_t *) data;
+       int *chan = s->lch;
+       int i;
+
+       FN_IN;
+       if (!s->linked) {
+               FN_OUT(1);
+               return;
+       }
+       for (i = 0; i < nr_linked_channels; i++) {
+               int cur_chan = chan[i];
+               int nex_chan =
+                   ((nr_linked_channels - 1 ==
+                     i) ? chan[0] : chan[i + 1]);
+               omap_dma_unlink_lch(cur_chan, nex_chan);
+       }
+       s->linked = 0;
+       FN_OUT(0);
+}
+
+int omap_free_sound_dma(void *data, int **channels)
+{
+       int i;
+       int *chan = NULL;
+       FN_IN;
+       if (unlikely(NULL == channels)) {
+               BUG();
+               return -EPERM;
+       }
+       if (unlikely(NULL == *channels)) {
+               BUG();
+               return -EPERM;
+       }
+       chan = (*channels);
+
+       if (!cpu_is_omap15xx())
+               omap_sound_dma_unlink_lch(data);
+       for (i = 0; i < nr_linked_channels; i++) {
+               int cur_chan = chan[i];
+               omap_stop_dma(cur_chan);
+               omap_free_dma(cur_chan);
+       }
+       kfree(*channels);
+       *channels = NULL;
+       FN_OUT(0);
+       return 0;
+}
+
+/***************************************************************************************
+ *
+ * Process DMA requests - This will end up starting the transfer. Proper fragments of
+ * Transfers will be initiated.
+ *
+ **************************************************************************************/
+int audio_process_dma(audio_stream_t * s)
+{
+       int ret = 0;
+       unsigned long flags;
+       FN_IN;
+
+       /* Dont let the ISR over ride touching the in_use flag */
+       local_irq_save(flags);
+       if (1 == s->in_use) {
+               local_irq_restore(flags);
+               ERR("Called again while In Use\n");
+               return 0;
+       }
+       s->in_use = 1;
+       local_irq_restore(flags);
+
+       if (s->stopped)
+               goto spin;
+
+       if (s->dma_spinref > 0 && s->pending_frags) {
+               s->dma_spinref = 0;
+               DMA_CLEAR(s);
+       }
+       while (s->pending_frags) {
+               audio_buf_t *b = &s->buffers[s->dma_head];
+               u_int dma_size = s->fragsize - b->offset;
+               if (dma_size > MAX_DMA_SIZE)
+                       dma_size = CUT_DMA_SIZE;
+               ret =
+                   omap_start_sound_dma(s, b->dma_addr + b->offset, dma_size);
+               if (ret) {
+                       goto process_out;
+               }
+               b->dma_ref++;
+               b->offset += dma_size;
+               if (b->offset >= s->fragsize) {
+                       s->pending_frags--;
+                       if (++s->dma_head >= s->nbfrags)
+                               s->dma_head = 0;
+               }
+       }
+      spin:
+       if (s->spin_idle) {
+               int spincnt = 0;
+               ERR("we are spinning\n");
+               while (omap_start_sound_dma(s, SPIN_ADDR, SPIN_SIZE) == 0)
+                       spincnt++;
+               /*
+                * Note: if there is still a data buffer being
+                * processed then the ref count is negative.  This
+                * allows for the DMA termination to be accounted in
+                * the proper order.  Of course dma_spinref can't be
+                * greater than 0 if dma_ref is not 0 since we kill
+                * the spinning above as soon as there is real data to process.
+                */
+               if (s->buffers && s->buffers[s->dma_tail].dma_ref)
+                       spincnt = -spincnt;
+               s->dma_spinref += spincnt;
+       }
+
+      process_out:
+       s->in_use = 0;
+
+       FN_OUT(ret);
+       return ret;
+}
+
+/***************************************************************************************
+ *
+ * Prime Rx - Since the recieve buffer has no time limit as to when it would arrive,
+ *            we need to prime it
+ *            
+ **************************************************************************************/
+void audio_prime_rx(audio_state_t * state)
+{
+       audio_stream_t *is = state->input_stream;
+
+       FN_IN;
+       if (state->need_tx_for_rx) {
+               /*
+                * With some codecs like the Philips UDA1341 we must ensure
+                * there is an output stream at any time while recording since
+                * this is how the UDA1341 gets its clock from the SA1100.
+                * So while there is no playback data to send, the output DMA
+                * will spin with all zeroes.  We use the cache flush special
+                * area for that.
+                */
+               state->output_stream->spin_idle = 1;
+               audio_process_dma(state->output_stream);
+       }
+       is->pending_frags = is->nbfrags;
+       init_completion(&is->wfc);
+       is->wfc.done = 0;
+
+       is->active = 1;
+       audio_process_dma(is);
+
+       FN_OUT(0);
+       return;
+}
+
+/***************************************************************************************
+ *
+ * set the fragment size
+ *
+ **************************************************************************************/
+int audio_set_fragments(audio_stream_t * s, int val)
+{
+       FN_IN;
+       if (s->active)
+               return -EBUSY;
+       if (s->buffers)
+               audio_discard_buf(s);
+       s->nbfrags = (val >> 16) & 0x7FFF;
+       val &= 0xFFFF;
+       if (val < 4)
+               val = 4;
+       if (val > 15)
+               val = 15;
+       s->fragsize = 1 << val;
+       if (s->nbfrags < 2)
+               s->nbfrags = 2;
+       if (s->nbfrags * s->fragsize > 128 * 1024)
+               s->nbfrags = 128 * 1024 / s->fragsize;
+       FN_OUT(0);
+       if (audio_setup_buf(s))
+               return -ENOMEM;
+       return val | (s->nbfrags << 16);
+
+}
+
+/***************************************************************************************
+ *
+ * Sync up the buffers before we shutdown, else under-run errors will happen
+ *
+ **************************************************************************************/
+int audio_sync(struct file *file)
+{
+       audio_state_t *state = file->private_data;
+       audio_stream_t *s = state->output_stream;
+       audio_buf_t *b;
+       u_int shiftval = 0;
+       unsigned long flags;
+
+       DECLARE_WAITQUEUE(wait, current);
+
+       FN_IN;
+
+       if (!(file->f_mode & FMODE_WRITE) || !s->buffers || s->mapped) {
+               FN_OUT(1);
+               return 0;
+       }
+
+       /*
+        * Send current buffer if it contains data.  Be sure to send
+        * a full sample count.
+        */
+       b = &s->buffers[s->usr_head];
+       if (b->offset &= ~3) {
+               /* Wait for a buffer to become free */
+               if (wait_for_completion_interruptible(&s->wfc))
+                       return 0;
+               /*
+                * HACK ALERT !
+                * To avoid increased complexity in the rest of the code
+                * where full fragment sizes are assumed, we cheat a little
+                * with the start pointer here and don't forget to restore
+                * it later.
+                */
+               
+               /* As this is a last frag we need only one dma channel
+                * to complete. So it's need to unlink dma channels
+                * to avoid empty dma work.
+                */
+               if (!cpu_is_omap15xx() && AUDIO_QUEUE_EMPTY(s))
+                       omap_sound_dma_unlink_lch(s);
+
+               shiftval = s->fragsize - b->offset;
+               b->offset = shiftval;
+               b->dma_addr -= shiftval;
+               b->data -= shiftval;
+               local_irq_save(flags);
+               s->bytecount -= shiftval;
+               if (++s->usr_head >= s->nbfrags)
+                       s->usr_head = 0;
+
+               s->pending_frags++;
+               audio_process_dma(s);
+               local_irq_restore(flags);
+       }
+
+       /* Let's wait for all buffers to complete */
+       set_current_state(TASK_INTERRUPTIBLE);
+       add_wait_queue(&s->wq, &wait);
+       while ((s->pending_frags || (s->wfc.done < s->nbfrags))
+              && !signal_pending(current)) {
+               schedule();
+               set_current_state(TASK_INTERRUPTIBLE);
+       }
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&s->wq, &wait);
+
+       /* undo the pointer hack above */
+       if (shiftval) {
+               local_irq_save(flags);
+               b->dma_addr += shiftval;
+               b->data += shiftval;
+               /* ensure sane DMA code behavior if not yet processed */
+               if (b->offset != 0)
+                       b->offset = s->fragsize;
+               local_irq_restore(flags);
+       }
+
+       FN_OUT(0);
+       return 0;
+}
+
+/***************************************************************************************
+ *
+ * Stop all the DMA channels of the stream
+ *
+ **************************************************************************************/
+void audio_stop_dma(audio_stream_t * s)
+{
+       int *chan = s->lch;
+       int i;
+       FN_IN;
+       if (unlikely(NULL == chan)) {
+               BUG();
+               return;
+       }
+       for (i = 0; i < nr_linked_channels; i++) {
+               int cur_chan = chan[i];
+               omap_stop_dma(cur_chan);
+       }
+       s->started = 0;
+       FN_OUT(0);
+       return;
+}
+
+/***************************************************************************************
+ *
+ * Get the dma posn
+ *
+ **************************************************************************************/
+u_int audio_get_dma_pos(audio_stream_t * s)
+{
+       audio_buf_t *b = &s->buffers[s->dma_tail];
+       u_int offset;
+
+       FN_IN;
+       if (b->dma_ref) {
+               offset = omap_get_dma_src_pos(s->lch[s->dma_q_head]) - b->dma_addr;
+               if (offset >= s->fragsize)
+                       offset = s->fragsize - 4;
+       } else if (s->pending_frags) {
+               offset = b->offset;
+       } else {
+               offset = 0;
+       }
+       FN_OUT(offset);
+       return offset;
+}
+
+/***************************************************************************************
+ *
+ * Reset the audio buffers
+ *
+ **************************************************************************************/
+void audio_reset(audio_stream_t * s)
+{
+       FN_IN;
+       if (s->buffers) {
+               audio_stop_dma(s);
+               s->buffers[s->dma_head].offset = 0;
+               s->buffers[s->usr_head].offset = 0;
+               s->usr_head = s->dma_head;
+               s->pending_frags = 0;
+               init_completion(&s->wfc);
+               s->wfc.done = s->nbfrags;
+       }
+       s->active = 0;
+       s->stopped = 0;
+       s->started = 0;
+       FN_OUT(0);
+       return;
+}
+
+/***************************************************************************************
+ *
+ * Clear any pending transfers
+ *
+ **************************************************************************************/
+void omap_clear_sound_dma(audio_stream_t * s)
+{
+       FN_IN;
+       omap_clear_dma(s->lch[s->dma_q_head]);
+       FN_OUT(0);
+       return;
+}
+
+/***************************************************************************************
+ *
+ * DMA related functions
+ *
+ **************************************************************************************/
+static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
+                                    u_int dma_size)
+{
+       int dt = 0x1;           /* data type 16 */
+       int cen = 32;           /* Stereo */
+       int cfn = dma_size / (2 * cen);
+       unsigned long dest_start;
+       int dest_port = 0;
+       int sync_dev = 0;
+
+       FN_IN;
+
+       if (cpu_is_omap15xx() || cpu_is_omap16xx()) {
+               dest_start = AUDIO_MCBSP_DATAWRITE;
+               dest_port = OMAP_DMA_PORT_MPUI;
+       }
+       if (cpu_is_omap24xx()) {
+               dest_start = AUDIO_MCBSP_DATAWRITE;
+               sync_dev = AUDIO_DMA_TX;
+       }
+
+       omap_set_dma_dest_params(channel, dest_port, OMAP_DMA_AMODE_CONSTANT, dest_start, 0, 0);
+       omap_set_dma_src_params(channel, 0, OMAP_DMA_AMODE_POST_INC, dma_ptr, 0, 0);
+       omap_set_dma_transfer_params(channel, dt, cen, cfn, OMAP_DMA_SYNC_ELEMENT, sync_dev, 0);
+
+       FN_OUT(0);
+       return 0;
+}
+
+static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
+                                       u_int dma_size)
+{
+       int dt = 0x1;           /* data type 16 */
+       int cen = 16;           /* mono */
+       int cfn = dma_size / (2 * cen);
+       unsigned long src_start;
+       int src_port = 0;
+       int sync_dev = 0;
+       int src_sync = 0;
+
+       FN_IN;
+
+       if (cpu_is_omap15xx() || cpu_is_omap16xx()) {
+               src_start = AUDIO_MCBSP_DATAREAD;
+               src_port = OMAP_DMA_PORT_MPUI;
+       }
+       if (cpu_is_omap24xx()) {
+               src_start = AUDIO_MCBSP_DATAREAD;
+               sync_dev = AUDIO_DMA_RX;
+               src_sync = 1;
+       }
+
+       omap_set_dma_src_params(channel, src_port, OMAP_DMA_AMODE_CONSTANT, src_start, 0, 0);
+       omap_set_dma_dest_params(channel, 0, OMAP_DMA_AMODE_POST_INC, dma_ptr, 0, 0);
+       omap_set_dma_transfer_params(channel, dt, cen, cfn, OMAP_DMA_SYNC_ELEMENT, sync_dev, src_sync);
+
+       FN_OUT(0);
+       return 0;
+}
+
+static int audio_start_dma_chain(audio_stream_t * s)
+{
+       int channel = s->lch[s->dma_q_head];
+       FN_IN;
+       if (!s->started) {
+               s->hw_stop();           /* stops McBSP Interface */
+               omap_start_dma(channel);
+               s->started = 1;
+               s->hw_start();          /* start McBSP interface */
+       }
+       /* else the dma itself will progress forward with out our help */
+       FN_OUT(0);
+       return 0;
+}
+
+/* Start DMA -
+ * Do the initial set of work to initialize all the channels as required.
+ * We shall then initate a transfer
+ */
+static int omap_start_sound_dma(audio_stream_t * s, dma_addr_t dma_ptr,
+                               u_int dma_size)
+{
+       int ret = -EPERM;
+
+       FN_IN;
+       if (unlikely(dma_size > MAX_DMA_SIZE)) {
+               ERR("DmaSoundDma: Start: overflowed %d-%d\n", dma_size,
+                   MAX_DMA_SIZE);
+               return -EOVERFLOW;
+       }
+
+       if (AUDIO_QUEUE_FULL(s)) {
+               ret = -2;
+               goto sound_out;
+       }
+       
+       if (s->input_or_output == FMODE_WRITE)
+               /*playback */
+       {
+               ret =
+                   audio_set_dma_params_play(s->lch[s->dma_q_tail], dma_ptr,
+                                             dma_size);
+       } else {
+               ret =
+                   audio_set_dma_params_capture(s->lch[s->dma_q_tail], dma_ptr,
+                                                dma_size);
+       }
+       if (ret != 0) {
+               ret = -2;       /* indicate queue full */
+               goto sound_out;
+       }
+       AUDIO_INCREMENT_TAIL(s);
+       ret = audio_start_dma_chain(s);
+       if (ret) {
+               ERR("dma start failed");
+       }
+      sound_out:
+       FN_OUT(ret);
+       return ret;
+
+}
+
+/***************************************************************************************
+ *
+ * ISR related functions
+ *
+ **************************************************************************************/
+/* The work item handler */
+static void audio_dsr_handler(unsigned long inData)
+{
+       void *data = (void *)inData;
+       struct audio_isr_work_item *work = data;
+       audio_stream_t *s = (work->s);
+       int sound_curr_lch = work->current_lch;
+       u16 ch_status = work->ch_status;
+
+       FN_IN;
+       DPRINTK("lch=%d,status=0x%x, data=%p as=%p\n", sound_curr_lch,
+               ch_status, data, s);
+       if (AUDIO_QUEUE_EMPTY(s)) {
+               ERR("Interrupt(%d)  for empty queue(h=%d, T=%d)???\n",
+                   sound_curr_lch, s->dma_q_head, s->dma_q_tail);
+               ERR("nbfrag=%d,pendfrags=%d,USR-H=%d, QH-%d QT-%d\n",
+                   s->nbfrags, s->pending_frags, s->usr_head, s->dma_head,
+                   s->dma_tail);
+               FN_OUT(-1);
+               return;
+       }
+
+       AUDIO_INCREMENT_HEAD(s);        /* Empty the queue */
+
+       /* Try to fill again */
+       audio_dma_callback(sound_curr_lch, ch_status, s);
+       FN_OUT(0);
+
+}
+
+/* Macro to trace the IRQ calls - checks for multi-channel irqs */
+//#define IRQ_TRACE
+#ifdef IRQ_TRACE
+#define MAX_UP 10
+static char xyz[MAX_UP] = { 0 };
+static int h = 0;
+#endif
+
+/* ISRs have to be short and smart.. So we transfer every heavy duty stuff to the 
+ * work item
+ */
+static void sound_dma_irq_handler(int sound_curr_lch, u16 ch_status, void *data)
+{
+       int dma_status = ch_status;
+       audio_stream_t *s = (audio_stream_t *) data;
+       FN_IN;
+#ifdef IRQ_TRACE
+       xyz[h++] = '0' + sound_curr_lch;
+       if (h == MAX_UP - 1) {
+               printk("%s-", xyz);
+               h = 0;
+       }
+#endif
+       DPRINTK("lch=%d,status=0x%x, dma_status=%d, data=%p\n", sound_curr_lch,
+               ch_status, dma_status, data);
+
+       if (dma_status & (DCSR_ERROR)) {
+               if (cpu_is_omap15xx() || cpu_is_omap16xx())
+                       OMAP_DMA_CCR_REG(sound_curr_lch) &= ~DCCR_EN;
+               ERR("DCSR_ERROR!\n");
+               FN_OUT(-1);
+               return;
+       }
+
+       if (AUDIO_QUEUE_LAST(s))
+               audio_stop_dma(s);
+
+       /* Start the work item  - we ping pong the work items */
+       if (!work_item_running) {
+               work1.current_lch = sound_curr_lch;
+               work1.ch_status = ch_status;
+               work1.s = s;
+               /* schedule tasklet 1 */
+               tasklet_schedule(&audio_isr_work1);
+               work_item_running = 1;
+       } else {
+               work2.current_lch = sound_curr_lch;
+               work2.ch_status = ch_status;
+               work2.s = s;
+               /* schedule tasklet 2 */
+               tasklet_schedule(&audio_isr_work2);
+               work_item_running = 0;
+       }
+       FN_OUT(0);
+       return;
+}
+
+/* The call back that handles buffer stuff */
+static void audio_dma_callback(int lch, u16 ch_status, void *data)
+{
+       audio_stream_t *s = data;
+       audio_buf_t *b = &s->buffers[s->dma_tail];
+       FN_IN;
+
+       if (s->dma_spinref > 0) {
+               s->dma_spinref--;
+       } else if (!s->buffers) {
+               printk(KERN_CRIT
+                      "omap_audio: received DMA IRQ for non existent buffers!\n");
+               return;
+       } else if (b->dma_ref && --b->dma_ref == 0 && b->offset >= s->fragsize) {
+               /* This fragment is done */
+               b->offset = 0;
+               s->bytecount += s->fragsize;
+               s->fragcount++;
+               s->dma_spinref = -s->dma_spinref;
+
+               if (++s->dma_tail >= s->nbfrags)
+                       s->dma_tail = 0;
+
+               if (!s->mapped)
+                       complete(&s->wfc);
+               else
+                       s->pending_frags++;
+
+               wake_up(&s->wq);
+       }
+
+       audio_process_dma(s);
+       
+       FN_OUT(0);
+       return;
+}
+
+/*********************************************************************************
+ *
+ * audio_get_dma_callback(): return the dma interface call back function
+ *
+ *********************************************************************************/
+dma_callback_t audio_get_dma_callback(void)
+{
+       FN_IN;
+       FN_OUT(0);
+       return audio_dma_callback;
+}
+
+static int __init audio_dma_init(void)
+{
+       if (!cpu_is_omap15xx())
+               nr_linked_channels = 2;
+
+       return 0;
+}
+
+static void __exit audio_dma_exit(void)
+{
+       /* Nothing */
+}
+
+module_init(audio_dma_init);
+module_exit(audio_dma_exit);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("Common DMA handling for Audio driver on OMAP processors");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(omap_clear_sound_dma);
+EXPORT_SYMBOL(omap_request_sound_dma);
+EXPORT_SYMBOL(omap_free_sound_dma);
+
+EXPORT_SYMBOL(audio_get_dma_callback);
+EXPORT_SYMBOL(audio_setup_buf);
+EXPORT_SYMBOL(audio_process_dma);
+EXPORT_SYMBOL(audio_prime_rx);
+EXPORT_SYMBOL(audio_set_fragments);
+EXPORT_SYMBOL(audio_sync);
+EXPORT_SYMBOL(audio_stop_dma);
+EXPORT_SYMBOL(audio_get_dma_pos);
+EXPORT_SYMBOL(audio_reset);
+EXPORT_SYMBOL(audio_discard_buf);
diff --git a/sound/oss/omap-audio-dma-intfc.h b/sound/oss/omap-audio-dma-intfc.h
new file mode 100644 (file)
index 0000000..65aa528
--- /dev/null
@@ -0,0 +1,63 @@
+/*  
+ * linux/sound/oss/omap-audio-dma-intfc.h
+ *
+ * Common audio DMA handling for the OMAP processors
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
+ *
+ * This package 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.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ * 2004/08/12  Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms
+ */
+
+#ifndef __OMAP_AUDIO_DMA_INTFC_H
+#define __OMAP_AUDIO_DMA_INTFC_H
+
+/************************** INCLUDES *************************************/
+
+/* Requires omap-audio.h */
+#include "omap-audio.h"
+
+/************************** GLOBAL MACROS *************************************/
+
+/* Provide the Macro interfaces common across platforms */
+#define DMA_REQUEST(e,s, cb)   {e=omap_request_sound_dma(s->dma_dev, s->id, s, &s->lch);}
+#define DMA_FREE(s)            omap_free_sound_dma(s, &s->lch)
+#define DMA_CLEAR(s)           omap_clear_sound_dma(s)
+
+/************************** GLOBAL DATA STRUCTURES *********************************/
+
+typedef void (*dma_callback_t) (int lch, u16 ch_status, void *data);
+
+/************************** GLOBAL FUNCTIONS ***************************************/
+
+dma_callback_t audio_get_dma_callback(void);
+int audio_setup_buf(audio_stream_t * s);
+int audio_process_dma(audio_stream_t * s);
+void audio_prime_rx(audio_state_t * state);
+int audio_set_fragments(audio_stream_t * s, int val);
+int audio_sync(struct file *file);
+void audio_stop_dma(audio_stream_t * s);
+u_int audio_get_dma_pos(audio_stream_t * s);
+void audio_reset(audio_stream_t * s);
+void audio_discard_buf(audio_stream_t * s);
+
+/**************** ARCH SPECIFIC FUNCIONS *******************************************/
+
+void omap_clear_sound_dma(audio_stream_t * s);
+
+int omap_request_sound_dma(int device_id, const char *device_name, void *data,
+                          int **channels);
+int omap_free_sound_dma(void *data, int **channels);
+
+#endif                         /* #ifndef __OMAP_AUDIO_DMA_INTFC_H */
diff --git a/sound/oss/omap-audio-tsc2101.c b/sound/oss/omap-audio-tsc2101.c
new file mode 100644 (file)
index 0000000..cbabcf5
--- /dev/null
@@ -0,0 +1,1238 @@
+/*
+ * linux/sound/oss/omap-audio-tsc2101.c
+ *
+ * Glue driver for TSC2101 for OMAP processors
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * This package 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.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *  -------
+ *  2004-08-12 Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms.
+ *  2004-09-14 Sriram Kannan - Added /proc support for asynchronous starting/stopping the codec
+ *             (without affecting the normal driver flow).
+ *  2004-11-04 Nishanth Menon - Support for power management
+ *  2004-11-07 Nishanth Menon - Support for Common TSC access b/w Touchscreen and audio drivers
+ */
+
+/***************************** INCLUDES ************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/errno.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <linux/mutex.h>
+
+#include <asm/uaccess.h>
+#include <asm/hardware.h>
+#include <asm/arch/dma.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include <asm/arch/mux.h>
+#include <asm/arch/io.h>
+#include <asm/mach-types.h>
+
+#include "omap-audio.h"
+#include "omap-audio-dma-intfc.h"
+#include <asm/arch/mcbsp.h>
+#ifdef CONFIG_ARCH_OMAP16XX
+#include <../drivers/ssi/omap-uwire.h>
+#include <asm/arch/dsp_common.h>
+#elif defined(CONFIG_ARCH_OMAP24XX)
+#else
+#error "Unsupported configuration"
+#endif
+
+#include <asm/hardware/tsc2101.h>
+#include <../drivers/ssi/omap-tsc2101.h>
+
+/***************************** MACROS ************************************/
+
+#define PROC_SUPPORT
+
+#ifdef PROC_SUPPORT
+#include <linux/proc_fs.h>
+#define PROC_START_FILE "driver/tsc2101-audio-start"
+#define PROC_STOP_FILE  "driver/tsc2101-audio-stop"
+#endif
+
+#define CODEC_NAME              "TSC2101"
+
+#ifdef CONFIG_ARCH_OMAP16XX
+#define PLATFORM_NAME "OMAP16XX"
+#elif defined(CONFIG_ARCH_OMAP24XX)
+#define PLATFORM_NAME "OMAP2"
+#endif
+
+/* Define to set the tsc as the master w.r.t McBSP */
+#define TSC_MASTER
+
+/*
+ * AUDIO related MACROS
+ */
+#define DEFAULT_BITPERSAMPLE          16
+#define AUDIO_RATE_DEFAULT               44100
+#define PAGE2_AUDIO_CODEC_REGISTERS   (2)
+#define LEAVE_CS                                 0x80
+
+/* Select the McBSP For Audio */
+/* 16XX is MCBSP1 and 24XX is MCBSP2*/
+/* see include/asm-arm/arch-omap/mcbsp.h */
+#ifndef AUDIO_MCBSP
+#error "UnSupported Configuration"
+#endif
+
+#define REC_MASK                                 (SOUND_MASK_LINE | SOUND_MASK_MIC)
+#define DEV_MASK                                 (REC_MASK | SOUND_MASK_VOLUME)
+
+#define SET_VOLUME                               1
+#define SET_LINE                                 2
+#define SET_MIC              3
+#define SET_RECSRC           4
+
+#define DEFAULT_VOLUME                93
+#define DEFAULT_INPUT_VOLUME     20    /* An minimal volume */
+
+/* Tsc Audio Specific */
+#define NUMBER_SAMPLE_RATES_SUPPORTED 16
+#define OUTPUT_VOLUME_MIN 0x7F
+#define OUTPUT_VOLUME_MAX 0x32
+#define OUTPUT_VOLUME_RANGE           (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX)
+#define OUTPUT_VOLUME_MASK            OUTPUT_VOLUME_MIN
+#define DEFAULT_VOLUME_LEVEL          OUTPUT_VOLUME_MAX
+
+/* use input vol of 75 for 0dB gain */
+#define INPUT_VOLUME_MIN                     0x0
+#define INPUT_VOLUME_MAX        0x7D
+#define INPUT_VOLUME_RANGE                   (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
+#define INPUT_VOLUME_MASK                    INPUT_VOLUME_MAX
+
+/*********** Debug Macros ********/
+/* To Generate a rather shrill tone -test the entire path */
+//#define TONE_GEN
+/* To Generate a tone for each keyclick - test the tsc,spi paths*/
+//#define TEST_KEYCLICK
+/* To dump the tsc registers for debug */
+//#define TSC_DUMP_REGISTERS
+
+#ifdef DPRINTK
+#undef DPRINTK
+#endif
+#undef DEBUG
+
+//#define DEBUG
+#ifdef DEBUG
+#define DPRINTK(ARGS...)  printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS)
+#define FN_IN printk(KERN_INFO "[%s]: start\n", __FUNCTION__)
+#define FN_OUT(n) printk(KERN_INFO "[%s]: end(%u)\n",__FUNCTION__, n)
+#else
+#define DPRINTK( x... )
+#define FN_IN
+#define FN_OUT(n)
+#endif
+
+/***************************** Data Structures **********************************/
+
+static int audio_ifc_start(void)
+{
+       omap_mcbsp_start(AUDIO_MCBSP);
+       return 0;
+}
+
+static int audio_ifc_stop(void)
+{
+       omap_mcbsp_stop(AUDIO_MCBSP);
+       return 0;
+}
+
+static audio_stream_t output_stream = {
+       .id                     = "TSC2101 out",
+       .dma_dev                = AUDIO_DMA_TX,
+       .input_or_output        = FMODE_WRITE,
+       .hw_start               = audio_ifc_start,
+       .hw_stop                = audio_ifc_stop,
+};
+
+static audio_stream_t input_stream = {
+       .id                     = "TSC2101 in",
+       .dma_dev                = AUDIO_DMA_RX,
+       .input_or_output        = FMODE_READ,
+       .hw_start               = audio_ifc_start,
+       .hw_stop                = audio_ifc_stop,
+};
+
+static int audio_dev_id, mixer_dev_id;
+
+typedef struct {
+       u8      volume;
+       u8      line;
+       u8      mic;
+       int     recsrc;
+       int     mod_cnt;
+} tsc2101_local_info;
+
+static tsc2101_local_info tsc2101_local = {
+       volume:         DEFAULT_VOLUME,
+       line:           DEFAULT_INPUT_VOLUME,
+       mic:            DEFAULT_INPUT_VOLUME,
+       recsrc:         SOUND_MASK_LINE,
+       mod_cnt:        0
+};
+
+struct sample_rate_reg_info {
+       u16 sample_rate;
+       u8  divisor;
+       u8  fs_44kHz;           /* if 0 48 khz, if 1 44.1 khz fsref */
+};
+
+/* To Store the default sample rate */
+static long audio_samplerate = AUDIO_RATE_DEFAULT;
+
+static const struct sample_rate_reg_info
+ reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
+       /* Div 1 */
+       {48000, 0, 0},
+       {44100, 0, 1},
+       /* Div 1.5 */
+       {32000, 1, 0},
+       {29400, 1, 1},
+       /* Div 2 */
+       {24000, 2, 0},
+       {22050, 2, 1},
+       /* Div 3 */
+       {16000, 3, 0},
+       {14700, 3, 1},
+       /* Div 4 */
+       {12000, 4, 0},
+       {11025, 4, 1},
+       /* Div 5 */
+       {9600, 5, 0},
+       {8820, 5, 1},
+       /* Div 5.5 */
+       {8727, 6, 0},
+       {8018, 6, 1},
+       /* Div 6 */
+       {8000, 7, 0},
+       {7350, 7, 1},
+};
+
+static struct omap_mcbsp_reg_cfg initial_config = {
+       .spcr2 = FREE | FRST | GRST | XRST | XINTM(3),
+       .spcr1 = RINTM(3) | RRST,
+       .rcr2  = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) |
+                RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(1),
+       .rcr1  = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16),
+       .xcr2  = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) |
+                XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(1) | XFIG,
+       .xcr1  = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16),
+       .srgr1 = FWID(15),
+       .srgr2 = GSYNC | CLKSP | FSGM | FPER(31),
+
+       /* platform specific initialization */
+#ifdef CONFIG_MACH_OMAP_H2
+       .pcr0  = CLKXM | CLKRM | FSXP | FSRP | CLKXP | CLKRP,
+#elif defined(CONFIG_MACH_OMAP_H3) || defined(CONFIG_MACH_OMAP_H4) || defined(CONFIG_MACH_OMAP_APOLLON)
+
+#ifndef TSC_MASTER
+       .pcr0  = FSXM | FSRM | CLKXM | CLKRM | CLKXP | CLKRP,
+#else
+       .pcr0  = CLKRM | SCLKME | FSXP | FSRP | CLKXP | CLKRP,
+#endif                         /* tsc Master defs */
+
+#endif                         /* platform specific inits */
+};
+
+/***************************** MODULES SPECIFIC FUNCTION PROTOTYPES ********************/
+
+static void omap_tsc2101_initialize(void *dummy);
+
+static void omap_tsc2101_shutdown(void *dummy);
+
+static int  omap_tsc2101_ioctl(struct inode *inode, struct file *file,
+                              uint cmd, ulong arg);
+
+static int  omap_tsc2101_probe(void);
+
+static void omap_tsc2101_remove(void);
+
+static int  omap_tsc2101_suspend(void);
+
+static int  omap_tsc2101_resume(void);
+
+static void tsc2101_configure(void);
+
+static int  mixer_open(struct inode *inode, struct file *file);
+
+static int  mixer_release(struct inode *inode, struct file *file);
+
+static int  mixer_ioctl(struct inode *inode, struct file *file, uint cmd,
+                       ulong arg);
+
+#ifdef TEST_KEYCLICK
+void tsc2101_testkeyclick(void);
+#endif
+
+#ifdef TONE_GEN
+void toneGen(void);
+#endif
+
+#ifdef TSC_DUMP_REGISTERS
+static void tsc2101_dumpRegisters(void);
+#endif
+
+#ifdef PROC_SUPPORT
+static int codec_start(char *buf, char **start, off_t offset, int count,
+                      int *eof, void *data);
+
+static int codec_stop(char *buf, char **start, off_t offset, int count,
+                     int *eof, void *data);
+
+static void tsc2101_start(void);
+#endif
+
+/******************** DATA STRUCTURES USING FUNCTION POINTERS **************************/
+
+/* File Op structure for mixer */
+static struct file_operations omap_mixer_fops = {
+       .open           = mixer_open,
+       .release        = mixer_release,
+       .ioctl          = mixer_ioctl,
+       .owner          = THIS_MODULE
+};
+
+/* To store characteristic info regarding the codec for the audio driver */
+static audio_state_t tsc2101_state = {
+       .output_stream  = &output_stream,
+       .input_stream   = &input_stream,
+/*     .need_tx_for_rx = 1, //Once the Full Duplex works  */
+       .need_tx_for_rx = 0,
+       .hw_init        = omap_tsc2101_initialize,
+       .hw_shutdown    = omap_tsc2101_shutdown,
+       .client_ioctl   = omap_tsc2101_ioctl,
+       .hw_probe       = omap_tsc2101_probe,
+       .hw_remove      = omap_tsc2101_remove,
+       .hw_suspend     = omap_tsc2101_suspend,
+       .hw_resume      = omap_tsc2101_resume,
+};
+
+/* This will be defined in the Audio.h */
+static struct file_operations *omap_audio_fops;
+
+/***************************** MODULES SPECIFIC FUNCTIONs *******************************/
+
+/*********************************************************************************
+ *
+ * Simplified write for tsc Audio
+ *
+ *********************************************************************************/
+static __inline__ void audio_tsc2101_write(u8 address, u16 data)
+{
+       omap_tsc2101_write(PAGE2_AUDIO_CODEC_REGISTERS, address, data);
+}
+
+/*********************************************************************************
+ *
+ * Simplified read for tsc  Audio
+ *
+ *********************************************************************************/
+static __inline__ u16 audio_tsc2101_read(u8 address)
+{
+       return (omap_tsc2101_read(PAGE2_AUDIO_CODEC_REGISTERS, address));
+}
+
+/*********************************************************************************
+ *
+ * tsc2101_update()
+ * Volume Adj etc
+ *
+ ********************************************************************************/
+static int tsc2101_update(int flag, int val)
+{
+       u16 volume;
+       u16 data;
+
+       FN_IN;
+       switch (flag) {
+       case SET_VOLUME:
+               if (val < 0 || val > 100) {
+                       printk(KERN_ERR "Trying a bad volume value(%d)!\n", val);
+                       return -EPERM;
+               }
+               /* Convert 0 -> 100 volume to 0x7F(min) -> y(max) volume range */
+               volume =
+                   ((val * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MAX;
+               /* invert the value for getting the proper range 0 min and 100 max */
+               volume = OUTPUT_VOLUME_MIN - volume;
+               data = audio_tsc2101_read(TSC2101_DAC_GAIN_CTRL);
+               data &=
+                   ~(DGC_DALVL(OUTPUT_VOLUME_MIN) |
+                     DGC_DARVL(OUTPUT_VOLUME_MIN));
+               data |= DGC_DALVL(volume) | DGC_DARVL(volume);
+               audio_tsc2101_write(TSC2101_DAC_GAIN_CTRL, data);
+               data = audio_tsc2101_read(TSC2101_DAC_GAIN_CTRL);
+
+               break;
+
+       case SET_LINE:
+               if (val < 0 || val > 100) {
+                       printk(KERN_ERR "Trying a bad volume value(%d)!\n", val);
+                       return -EPERM;
+               }
+               /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range */
+               /* NOTE: 0 is minimum volume and not mute */
+               volume = ((val * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
+               /* Handset Input not muted, AGC for Handset In off */
+               audio_tsc2101_write(TSC2101_HEADSET_GAIN_CTRL,
+       HGC_ADPGA_HED(volume));
+               break;
+
+       case SET_MIC:
+               if (val < 0 || val > 100) {
+                       printk(KERN_ERR "Trying a bad volume value(%d)!\n", val);
+                       return -EPERM;
+               }
+               /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range */
+               /* NOTE: 0 is minimum volume and not mute */
+               volume = ((val * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
+               /* Handset Input not muted, AGC for Handset In off */
+               audio_tsc2101_write(TSC2101_HANDSET_GAIN_CTRL,
+       HNGC_ADPGA_HND(volume));
+               break;
+
+       case SET_RECSRC:
+               /*
+                * If more than one recording device selected,
+                * disable the device that is currently in use.
+                */
+               if (hweight32(val) > 1)
+                       val &= ~tsc2101_local.recsrc;
+
+               data = audio_tsc2101_read(TSC2101_MIXER_PGA_CTRL);
+               data &= ~MPC_MICSEL(7); /* clear all MICSEL bits */
+
+               if (val == SOUND_MASK_MIC) {
+                       data |=  MPC_MICSEL(1);
+                       audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL, data);
+               }
+               else if (val == SOUND_MASK_LINE) {
+                       data |=  MPC_MICSEL(0);
+                       audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL, data);
+               }
+               else {
+                       printk(KERN_WARNING "omap1610-tsc2101: Wrong RECSRC"
+        " value specified\n");
+                       return -EINVAL;
+               }
+               tsc2101_local.recsrc = val;
+               break;
+       default:
+               printk(KERN_WARNING "omap1610-tsc2101: Wrong tsc2101_update "
+       "flag specified\n");
+               break;
+       }
+
+       FN_OUT(0);
+       return 0;
+}
+
+/*********************************************************************************
+ *
+ * mixer_open()
+ *
+ ********************************************************************************/
+static int mixer_open(struct inode *inode, struct file *file)
+{
+       /* Any mixer specific initialization */
+
+       /* Initalize the tsc2101 */
+       omap_tsc2101_enable();
+
+       return 0;
+}
+
+/*********************************************************************************
+ *
+ * mixer_release()
+ *
+ ********************************************************************************/
+static int mixer_release(struct inode *inode, struct file *file)
+{
+       /* Any mixer specific Un-initialization */
+       omap_tsc2101_disable();
+
+       return 0;
+}
+
+/*********************************************************************************
+ *
+ * mixer_ioctl()
+ *
+ ********************************************************************************/
+static int
+mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+       int val;
+       int gain;
+       int ret = 0;
+       int nr = _IOC_NR(cmd);
+
+       /*
+        * We only accept mixer (type 'M') ioctls.
+        */
+       FN_IN;
+       if (_IOC_TYPE(cmd) != 'M')
+               return -EINVAL;
+
+       DPRINTK(" 0x%08x\n", cmd);
+
+       if (cmd == SOUND_MIXER_INFO) {
+               struct mixer_info mi;
+
+               strncpy(mi.id, "TSC2101", sizeof(mi.id));
+               strncpy(mi.name, "TI TSC2101", sizeof(mi.name));
+               mi.modify_counter = tsc2101_local.mod_cnt;
+               FN_OUT(1);
+               return copy_to_user((void __user *)arg, &mi, sizeof(mi));
+       }
+
+       if (_IOC_DIR(cmd) & _IOC_WRITE) {
+               ret = get_user(val, (int __user *)arg);
+               if (ret)
+                       goto out;
+
+               /* Ignore separate left/right channel for now,
+                * even the codec does support it.
+                */
+               gain = val & 255;
+
+               switch (nr) {
+               case SOUND_MIXER_VOLUME:
+                       tsc2101_local.volume = val;
+                       tsc2101_local.mod_cnt++;
+                       ret = tsc2101_update(SET_VOLUME, gain);
+                       break;
+
+               case SOUND_MIXER_LINE:
+                       tsc2101_local.line = val;
+                       tsc2101_local.mod_cnt++;
+                       ret = tsc2101_update(SET_LINE, gain);
+                       break;
+
+               case SOUND_MIXER_MIC:
+                       tsc2101_local.mic = val;
+                       tsc2101_local.mod_cnt++;
+                       ret = tsc2101_update(SET_MIC, gain);
+                       break;
+
+               case SOUND_MIXER_RECSRC:
+                       if ((val & SOUND_MASK_LINE) ||
+                           (val & SOUND_MASK_MIC)) {
+                               if (tsc2101_local.recsrc != val) {
+                                       tsc2101_local.mod_cnt++;
+                                       tsc2101_update(SET_RECSRC, val);
+                               }
+                       }
+                       else {
+                               ret = -EINVAL;
+                       }
+                       break;
+
+               default:
+                       ret = -EINVAL;
+               }
+       }
+
+       if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {
+               ret = 0;
+
+               switch (nr) {
+               case SOUND_MIXER_VOLUME:
+                       val = tsc2101_local.volume;
+                       val = (tsc2101_local.volume << 8) |
+         tsc2101_local.volume;
+                       break;
+               case SOUND_MIXER_LINE:
+                       val = (tsc2101_local.line << 8) |
+         tsc2101_local.line;
+                       break;
+               case SOUND_MIXER_MIC:
+                       val = (tsc2101_local.mic << 8) |
+         tsc2101_local.mic;
+                       break;
+               case SOUND_MIXER_RECSRC:
+                       val = tsc2101_local.recsrc;
+                       break;
+               case SOUND_MIXER_RECMASK:
+                       val = REC_MASK;
+                       break;
+               case SOUND_MIXER_DEVMASK:
+                       val = DEV_MASK;
+                       break;
+               case SOUND_MIXER_CAPS:
+                       val = 0;
+                       break;
+               case SOUND_MIXER_STEREODEVS:
+                       val = SOUND_MASK_VOLUME;
+                       break;
+               default:
+                       val = 0;
+                       printk(KERN_WARNING "omap1610-tsc2101: unknown mixer "
+        "read ioctl flag specified\n");
+                       ret = -EINVAL;
+                       break;
+               }
+
+               if (ret == 0)
+                       ret = put_user(val, (int __user *)arg);
+       }
+      out:
+       FN_OUT(0);
+       return ret;
+
+}
+
+/*********************************************************************************
+ *
+ * omap_set_samplerate()
+ *
+ ********************************************************************************/
+static int omap_set_samplerate(long sample_rate)
+{
+       u8 count = 0;
+       u16 data = 0;
+       int clkgdv = 0;
+       /* wait for any frame to complete */
+       udelay(125);
+
+       /* Search for the right sample rate */
+       while ((reg_info[count].sample_rate != sample_rate) &&
+              (count < NUMBER_SAMPLE_RATES_SUPPORTED)) {
+               count++;
+       }
+       if (count == NUMBER_SAMPLE_RATES_SUPPORTED) {
+               printk(KERN_ERR "Invalid Sample Rate %d requested\n",
+                      (int)sample_rate);
+               return -EPERM;
+       }
+
+       /* Set AC1 */
+       data = audio_tsc2101_read(TSC2101_AUDIO_CTRL_1);
+       /*Clear prev settings */
+       data &= ~(AC1_DACFS(0x07) | AC1_ADCFS(0x07));
+       data |=
+           AC1_DACFS(reg_info[count].divisor) | AC1_ADCFS(reg_info[count].
+                                                          divisor);
+       audio_tsc2101_write(TSC2101_AUDIO_CTRL_1, data);
+
+       /* Set the AC3 */
+       data = audio_tsc2101_read(TSC2101_AUDIO_CTRL_3);
+       /*Clear prev settings */
+       data &= ~(AC3_REFFS | AC3_SLVMS);
+       data |= (reg_info[count].fs_44kHz) ? AC3_REFFS : 0;
+#ifdef TSC_MASTER
+       data |= AC3_SLVMS;
+#endif                         /* #ifdef TSC_MASTER */
+       audio_tsc2101_write(TSC2101_AUDIO_CTRL_3, data);
+
+       /* program the PLLs */
+       if (reg_info[count].fs_44kHz) {
+               /* 44.1 khz - 12 MHz Mclk */
+               audio_tsc2101_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL | PLL1_PVAL(1) | PLL1_I_VAL(7));    /* PVAL 1; I_VAL 7 */
+               audio_tsc2101_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x1490));    /* D_VAL 5264 */
+       } else {
+               /* 48 khz - 12 Mhz Mclk */
+               audio_tsc2101_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL | PLL1_PVAL(1) | PLL1_I_VAL(8));    /* PVAL 1; I_VAL 8 */
+               audio_tsc2101_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x780));     /* D_VAL 1920 */
+       }
+
+       audio_samplerate = sample_rate;
+
+       /* Set the sample rate */
+#ifndef TSC_MASTER
+       clkgdv =
+           DEFAULT_MCBSP_CLOCK / (sample_rate *
+                                  (DEFAULT_BITPERSAMPLE * 2 - 1));
+       if (clkgdv)
+               initial_config.srgr1 =
+                   (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+       else
+               return (1);
+
+       /* Stereo Mode */
+       initial_config.srgr2 =
+           (CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1));
+#else
+       initial_config.srgr1 =
+           (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+       initial_config.srgr2 =
+           ((GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)));
+
+#endif                         /* end of #ifdef TSC_MASTER */
+       omap_mcbsp_config(AUDIO_MCBSP, &initial_config);
+
+       return 0;
+}
+
+/*********************************************************************************
+ *
+ * omap_tsc2101_initialize() [hw_init() ]
+ *
+ ********************************************************************************/
+static void omap_tsc2101_initialize(void *dummy)
+{
+
+       DPRINTK("omap_tsc2101_initialize entry\n");
+
+       /* initialize with default sample rate */
+       audio_samplerate = AUDIO_RATE_DEFAULT;
+
+       omap_mcbsp_request(AUDIO_MCBSP);
+
+       /* if configured, then stop mcbsp */
+       omap_mcbsp_stop(AUDIO_MCBSP);
+
+       omap_tsc2101_enable();
+
+       omap_mcbsp_config(AUDIO_MCBSP, &initial_config);
+       omap_mcbsp_start(AUDIO_MCBSP);
+       tsc2101_configure();
+
+#ifdef TEST_KEYCLICK
+       tsc2101_testkeyclick();
+#endif
+
+#ifdef TONE_GEN
+       toneGen();
+#endif
+
+       DPRINTK("omap_tsc2101_initialize exit\n");
+}
+
+/*********************************************************************************
+ *
+ * omap_tsc2101_shutdown() [hw_shutdown() ]
+ *
+ ********************************************************************************/
+static void omap_tsc2101_shutdown(void *dummy)
+{
+       /*
+          Turn off codec after it is done.
+          Can't do it immediately, since it may still have
+          buffered data.
+
+          Wait 20ms (arbitrary value) and then turn it off.
+        */
+
+       FN_IN;
+       set_current_state(TASK_INTERRUPTIBLE);
+       schedule_timeout(2);
+
+       omap_mcbsp_stop(AUDIO_MCBSP);
+       omap_mcbsp_free(AUDIO_MCBSP);
+
+       audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL,
+                           ~(CPC_SP1PWDN | CPC_SP2PWDN | CPC_BASSBC));
+
+       omap_tsc2101_disable();
+
+       FN_OUT(0);
+}
+
+/*********************************************************************************
+ *
+ * tsc2101_configure
+ *
+ ********************************************************************************/
+static void tsc2101_configure(void)
+{
+       FN_IN;
+
+       audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL, 0x0000);
+
+       /*Mute Analog Sidetone */
+       /*Select MIC_INHED input for headset */
+       /*Cell Phone In not connected */
+       audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL,
+                           MPC_ASTMU | MPC_ASTG(0x40) | MPC_MICADC);
+
+       /* Set record source */
+       tsc2101_update(SET_RECSRC, tsc2101_local.recsrc);
+
+       /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */
+       /* 1dB AGC hysteresis */
+       /* MICes bias 2V */
+       audio_tsc2101_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
+
+       /* Set codec output volume */
+       audio_tsc2101_write(TSC2101_DAC_GAIN_CTRL, 0x0000);
+
+       /* DAC left and right routed to SPK2 */
+       /* SPK1/2 unmuted */
+       audio_tsc2101_write(TSC2101_AUDIO_CTRL_5,
+                           AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
+                           AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
+                           AC5_HDSCPTC);
+
+       /* OUT8P/N muted, CPOUT muted */
+
+       audio_tsc2101_write(TSC2101_AUDIO_CTRL_6,
+                           AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC |
+                           AC6_VGNDSCPTC);
+
+       /* Headset/Hook switch detect disabled */
+       audio_tsc2101_write(TSC2101_AUDIO_CTRL_7, 0x0000);
+
+       /* Left line input volume control */
+       tsc2101_update(SET_LINE, tsc2101_local.line);
+
+       /* mic input volume control */
+       tsc2101_update(SET_MIC, tsc2101_local.mic);
+
+       /* Left/Right headphone channel volume control */
+       /* Zero-cross detect on */
+       tsc2101_update(SET_VOLUME, tsc2101_local.volume);
+
+       /* clock configuration */
+       omap_set_samplerate(audio_samplerate);
+
+#ifdef TSC_DUMP_REGISTERS
+       tsc2101_dumpRegisters();
+#endif
+
+       FN_OUT(0);
+}
+
+#ifdef PROC_SUPPORT
+static void tsc2101_start(void)
+{
+       FN_IN;
+
+       audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL, 0x0000);
+
+       /*Mute Analog Sidetone */
+       /*Select MIC_INHED input for headset */
+       /*Cell Phone In not connected */
+       audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL,
+                           MPC_ASTMU | MPC_ASTG(0x40) | MPC_MICADC);
+
+       /* Set record source */
+       tsc2101_update(SET_RECSRC, tsc2101_local.recsrc);
+
+       /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */
+       /* 1dB AGC hysteresis */
+       /* MICes bias 2V */
+       audio_tsc2101_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
+
+       /* Set codec output volume */
+       audio_tsc2101_write(TSC2101_DAC_GAIN_CTRL, 0x0000);
+
+       /* DAC left and right routed to SPK2 */
+       /* SPK1/2 unmuted */
+       audio_tsc2101_write(TSC2101_AUDIO_CTRL_5,
+                           AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
+                           AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
+                           AC5_HDSCPTC);
+
+       /* OUT8P/N muted, CPOUT muted */
+
+       audio_tsc2101_write(TSC2101_AUDIO_CTRL_6,
+                           AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC |
+                           AC6_VGNDSCPTC);
+
+       /* Headset/Hook switch detect disabled */
+       audio_tsc2101_write(TSC2101_AUDIO_CTRL_7, 0x0000);
+
+       /* Left line input volume control */
+       tsc2101_update(SET_LINE, tsc2101_local.line);
+
+       /* mic input volume control */
+       tsc2101_update(SET_MIC, tsc2101_local.mic);
+
+       /* Left/Right headphone channel volume control */
+       /* Zero-cross detect on */
+       tsc2101_update(SET_VOLUME, tsc2101_local.volume);
+
+       FN_OUT(0);
+
+}
+#endif
+
+/******************************************************************************************
+ *
+ * All generic ioctl's are handled by audio_ioctl() [File: omap-audio.c]. This
+ * routine handles some platform specific ioctl's
+ *
+ ******************************************************************************************/
+static int
+omap_tsc2101_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+       long val;
+       int ret = 0;
+
+       DPRINTK(" 0x%08x\n", cmd);
+
+       /*
+        * These are platform dependent ioctls which are not handled by the
+        * generic omap-audio module.
+        */
+       switch (cmd) {
+       case SNDCTL_DSP_STEREO:
+               ret = get_user(val, (int __user *)arg);
+               if (ret)
+                       return ret;
+               /* the AIC23 is stereo only */
+               ret = (val == 0) ? -EINVAL : 1;
+               FN_OUT(1);
+               return put_user(ret, (int __user *)arg);
+
+       case SNDCTL_DSP_CHANNELS:
+       case SOUND_PCM_READ_CHANNELS:
+               /* the AIC23 is stereo only */
+               FN_OUT(2);
+               return put_user(2, (long __user *)arg);
+
+       case SNDCTL_DSP_SPEED:
+               ret = get_user(val, (long __user *)arg);
+               if (ret)
+                       break;
+               ret = omap_set_samplerate(val);
+               if (ret)
+                       break;
+               /* fall through */
+
+       case SOUND_PCM_READ_RATE:
+               FN_OUT(3);
+               return put_user(audio_samplerate, (long __user *)arg);
+
+       case SOUND_PCM_READ_BITS:
+       case SNDCTL_DSP_SETFMT:
+       case SNDCTL_DSP_GETFMTS:
+               /* we can do 16-bit only */
+               FN_OUT(4);
+               return put_user(AFMT_S16_LE, (long __user *)arg);
+
+       default:
+               /* Maybe this is meant for the mixer (As per OSS Docs) */
+               FN_OUT(5);
+               return mixer_ioctl(inode, file, cmd, arg);
+       }
+
+       FN_OUT(0);
+       return ret;
+}
+
+/*********************************************************************************
+ *
+ * module_probe for TSC2101
+ *
+ ********************************************************************************/
+static int omap_tsc2101_probe(void)
+{
+       FN_IN;
+
+       /* Get the fops from audio oss driver */
+       if (!(omap_audio_fops = audio_get_fops())) {
+               printk(KERN_ERR "Unable to Get the FOPs of Audio OSS driver\n");
+               audio_unregister_codec(&tsc2101_state);
+               return -EPERM;
+       }
+
+       /* register devices */
+       audio_dev_id = register_sound_dsp(omap_audio_fops, -1);
+       mixer_dev_id = register_sound_mixer(&omap_mixer_fops, -1);
+
+#ifdef PROC_SUPPORT
+       create_proc_read_entry(PROC_START_FILE, 0 /* default mode */ ,
+                              NULL /* parent dir */ ,
+                              codec_start, NULL /* client data */ );
+
+       create_proc_read_entry(PROC_STOP_FILE, 0 /* default mode */ ,
+                              NULL /* parent dir */ ,
+                              codec_stop, NULL /* client data */ );
+#endif
+
+       /* Announcement Time */
+       printk(KERN_INFO PLATFORM_NAME " " CODEC_NAME
+              " Audio support initialized\n");
+
+       FN_OUT(0);
+       return 0;
+}
+
+/*********************************************************************************
+ *
+ * Module Remove for TSC2101
+ *
+ ********************************************************************************/
+static void omap_tsc2101_remove(void)
+{
+       FN_IN;
+       /* Un-Register the codec with the audio driver */
+       unregister_sound_dsp(audio_dev_id);
+       unregister_sound_mixer(mixer_dev_id);
+
+#ifdef PROC_SUPPORT
+       remove_proc_entry(PROC_START_FILE, NULL);
+       remove_proc_entry(PROC_STOP_FILE, NULL);
+#endif
+       FN_OUT(0);
+
+}
+
+/*********************************************************************************
+ *
+ * Module Suspend for TSC2101
+ *
+ ********************************************************************************/
+static int omap_tsc2101_suspend(void)
+{
+
+       FN_OUT(0);
+       return 0;
+}
+
+/*********************************************************************************
+ *
+ * Module Resume for TSC2101
+ *
+ ********************************************************************************/
+static int omap_tsc2101_resume(void)
+{
+
+       FN_OUT(0);
+       return 0;
+}
+
+/*********************************************************************************
+ *
+ * module_init for TSC2101
+ *
+ ********************************************************************************/
+static int __init audio_tsc2101_init(void)
+{
+
+       int err = 0;
+       FN_IN;
+
+       if (machine_is_omap_osk() || machine_is_omap_innovator())
+               return -ENODEV;
+
+       mutex_init(&tsc2101_state.mutex);
+
+       /* register the codec with the audio driver */
+       if ((err = audio_register_codec(&tsc2101_state))) {
+               printk(KERN_ERR
+                      "Failed to register TSC driver with Audio OSS Driver\n");
+       }
+       FN_OUT(err);
+       return err;
+}
+
+/*********************************************************************************
+ *
+ * module_exit for TSC2101
+ *
+ ********************************************************************************/
+static void __exit audio_tsc2101_exit(void)
+{
+
+       FN_IN;
+       (void)audio_unregister_codec(&tsc2101_state);
+       FN_OUT(0);
+       return;
+}
+
+/**************************** DEBUG FUNCTIONS ***********************************/
+
+/*********************************************************************************
+ * TEST_KEYCLICK:
+ * This is a test to generate various keyclick sound on tsc.
+ * verifies if the tsc and the spi interfaces are operational.
+ *
+ ********************************************************************************/
+#ifdef TEST_KEYCLICK
+void tsc2101_testkeyclick(void)
+{
+       u8 freq = 0;
+       u16 old_reg_val, reg_val;
+       u32 uDummyVal = 0;
+       u32 uTryVal = 0;
+
+       old_reg_val = audio_tsc2101_read(TSC2101_AUDIO_CTRL_2);
+
+       /* Keyclick active, max amplitude and longest key click len(32 period) */
+       printk(KERN_INFO " TESTING KEYCLICK\n Listen carefully NOW....\n");
+       printk(KERN_INFO " OLD REG VAL=0x%x\n", old_reg_val);
+       /* try all frequencies */
+       for (; freq < 8; freq++) {
+               /* Keyclick active, max amplitude and longest key click len(32 period) */
+               reg_val = old_reg_val | AC2_KCLAC(0x7) | AC2_KCLLN(0xF);
+               uDummyVal = 0;
+               uTryVal = 0;
+               printk(KERN_INFO "\n\nTrying frequency %d reg val= 0x%x\n",
+                      freq, reg_val | AC2_KCLFRQ(freq) | AC2_KCLEN);
+               audio_tsc2101_write(TSC2101_AUDIO_CTRL_2,
+                                   reg_val | AC2_KCLFRQ(freq) | AC2_KCLEN);
+               printk("DONE. Wait 10 ms ...\n");
+               /* wait till the kclk bit is auto cleared! time out also to be considered. */
+               while (audio_tsc2101_read(TSC2101_AUDIO_CTRL_2) & AC2_KCLEN) {
+                       udelay(3);
+                       uTryVal++;
+                       if (uTryVal > 2000) {
+                               printk(KERN_ERR
+                                      "KEYCLICK TIMED OUT! freq val=%d, POSSIBLE ERROR!\n",
+                                      freq);
+                               printk(KERN_INFO
+                                      "uTryVal == %d: Read back new reg val= 0x%x\n",
+                                      uTryVal,
+                                      audio_tsc2101_read
+                                      (TSC2101_AUDIO_CTRL_2));
+                               /* clear */
+                               audio_tsc2101_write(TSC2101_AUDIO_CTRL_2, 0x00);
+                               break;
+                       }
+               }
+       }
+       /* put the old value back */
+       audio_tsc2101_write(TSC2101_AUDIO_CTRL_2, old_reg_val);
+       printk(KERN_INFO " KEYCLICK TEST COMPLETE\n");
+
+}                              /* End of tsc2101_testkeyclick */
+
+#endif                         /* TEST_KEYCLICK */
+
+/*********************************************************************************
+ * TONEGEN:
+ * This is a test to generate a rather unpleasant sound..
+ * verifies if the mcbsp is active (requires MCBSP_DIRECT_RW to be active on McBSP)
+ *
+ ********************************************************************************/
+#ifdef TONE_GEN
+/* Generates a shrill tone */
+u16 tone[] = {
+       0x0ce4, 0x0ce4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE,
+       0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C,
+       0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2,
+       0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C,
+       0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A,
+       0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676,
+       0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83,
+       0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E,
+       0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94,
+       0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03,
+       0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000,
+       0x0CE4, 0x0CE4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE,
+       0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C,
+       0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2,
+       0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C,
+       0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A,
+       0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676,
+       0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83,
+       0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E,
+       0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94,
+       0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03,
+       0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000,
+       0x0CE4, 0x0CE4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE,
+       0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C,
+       0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2,
+       0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C,
+       0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A,
+       0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676,
+       0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83,
+       0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E,
+       0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94,
+       0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03,
+       0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000
+};
+
+void toneGen(void)
+{
+       int count = 0;
+       int ret = 0;
+       printk(KERN_INFO "TONE GEN TEST :");
+
+       for (count = 0; count < 5000; count++) {
+               int bytes;
+               for (bytes = 0; bytes < sizeof(tone) / 2; bytes++) {
+                       ret = omap_mcbsp_pollwrite(AUDIO_MCBSP, tone[bytes]);
+                       if (ret == -1) {
+                               /* retry */
+                               bytes--;
+                       } else if (ret == -2) {
+                               printk(KERN_INFO "ERROR:bytes=%d\n", bytes);
+                               return;
+                       }
+               }
+       }
+       printk(KERN_INFO "SUCCESS\n");
+}
+
+#endif                         /* End of TONE_GEN */
+
+/*********************************************************************************
+ *
+ * TSC_DUMP_REGISTERS:
+ * This will dump the entire register set of Page 2 tsc2101. 
+ * Useful for major goof ups
+ *
+ ********************************************************************************/
+#ifdef TSC_DUMP_REGISTERS
+static void tsc2101_dumpRegisters(void)
+{
+       int i = 0;
+       u16 data = 0;
+       printk("TSC 2101 Register dump for Page 2 \n");
+       for (i = 0; i < 0x27; i++) {
+               data = audio_tsc2101_read(i);
+               printk(KERN_INFO "Register[%x]=0x%04x\n", i, data);
+
+       }
+}
+#endif                         /* End of #ifdef TSC_DUMP_REGISTERS */
+
+#ifdef PROC_SUPPORT
+static int codec_start(char *buf, char **start, off_t offset, int count,
+                      int *eof, void *data)
+{
+       omap_tsc2101_enable();
+       tsc2101_start();
+       printk("Codec initialization done.\n");
+       return 0;
+}
+static int codec_stop(char *buf, char **start, off_t offset, int count,
+                     int *eof, void *data)
+{
+
+       omap_tsc2101_disable();
+       audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL,
+                           ~(CPC_SP1PWDN | CPC_SP2PWDN | CPC_BASSBC));
+       printk("Codec shutdown.\n");
+       return 0;
+}
+#endif
+
+/*********************************************************************************
+ *
+ * Other misc management, registration etc
+ *
+ ********************************************************************************/
+module_init(audio_tsc2101_init);
+module_exit(audio_tsc2101_exit);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION
+    ("Glue audio driver for the TI OMAP1610/OMAP1710 TSC2101 codec.");
+MODULE_LICENSE("GPL");
diff --git a/sound/oss/omap-audio.c b/sound/oss/omap-audio.c
new file mode 100644 (file)
index 0000000..84f5445
--- /dev/null
@@ -0,0 +1,1162 @@
+/*
+ * linux/sound/oss/omap-audio.c
+ *
+ * Common audio handling for the OMAP processors
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
+ *
+ * This package 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.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ * 2004/08/12   Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms
+ *
+ * 2004-11-01   Nishanth Menon - modified to support 16xx and 17xx 
+ *                platform multi channel chaining.
+ *
+ * 2004-11-04   Nishanth Menon - Added support for power management
+ *
+ * 2004-12-17   Nishanth Menon - Provided proper module handling support
+ */
+
+/***************************** INCLUDES ************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/pm.h>
+#include <linux/errno.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <linux/sysrq.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include "omap-audio-dma-intfc.h"
+#include "omap-audio.h"
+
+/***************************** MACROS ************************************/
+
+#undef DEBUG
+//#define DEBUG
+#ifdef DEBUG
+#define DPRINTK  printk
+#define FN_IN printk("[omap_audio.c:[%s] start\n", __FUNCTION__)
+#define FN_OUT(n) printk("[omap_audio.c:[%s] end(%d)\n", __FUNCTION__ , n)
+#else
+#define DPRINTK( x... )
+#define FN_IN
+#define FN_OUT(x)
+#endif
+
+#define OMAP_AUDIO_NAME                "omap-audio"
+#define AUDIO_NBFRAGS_DEFAULT  8
+#define AUDIO_FRAGSIZE_DEFAULT 8192
+
+/* HACK ALERT!: These values will bave to be tuned as this is a trade off b/w
+ * Sampling Rate vs buffer size and delay we are prepared to do before giving up
+ */
+#define MAX_QUEUE_FULL_RETRIES 1000000
+#define QUEUE_WAIT_TIME        10
+
+#define AUDIO_ACTIVE(state)    ((state)->rd_ref || (state)->wr_ref)
+
+#define SPIN_ADDR              (dma_addr_t)0
+#define SPIN_SIZE              2048
+
+/***************************** MODULES SPECIFIC FUNCTION PROTOTYPES ********************/
+
+static int audio_write(struct file *file, const char __user *buffer,
+                      size_t count, loff_t * ppos);
+
+static int audio_read(struct file *file, char __user *buffer, size_t count,
+                     loff_t * ppos);
+
+static int audio_mmap(struct file *file, struct vm_area_struct *vma);
+
+static unsigned int audio_poll(struct file *file,
+                              struct poll_table_struct *wait);
+
+static loff_t audio_llseek(struct file *file, loff_t offset, int origin);
+
+static int audio_ioctl(struct inode *inode, struct file *file, uint cmd,
+                      ulong arg);
+
+static int audio_open(struct inode *inode, struct file *file);
+
+static int audio_release(struct inode *inode, struct file *file);
+
+static int audio_probe(struct platform_device *pdev);
+
+static int audio_remove(struct platform_device *pdev);
+
+static void audio_shutdown(struct platform_device *pdev);
+
+static int audio_suspend(struct platform_device *pdev, pm_message_t mesg);
+
+static int audio_resume(struct platform_device *pdev);
+
+static void audio_free(struct device *dev);
+
+/***************************** Data Structures **********************************/
+
+/*
+ * The function pointer set to be registered by the codec.
+ */
+static audio_state_t audio_state = { NULL };
+
+/* DMA Call back function */
+static dma_callback_t audio_dma_callback = NULL;
+
+/* File Ops structure */
+static struct file_operations omap_audio_fops = {
+       .open           = audio_open,
+       .release        = audio_release,
+       .write          = audio_write,
+       .read           = audio_read,
+       .mmap           = audio_mmap,
+       .poll           = audio_poll,
+       .ioctl          = audio_ioctl,
+       .llseek         = audio_llseek,
+       .owner          = THIS_MODULE
+};
+
+/* Driver information */
+static struct platform_driver omap_audio_driver = {
+       .probe          = audio_probe,
+       .remove         = audio_remove,
+       .suspend        = audio_suspend,
+       .shutdown       = audio_shutdown,
+       .resume         = audio_resume,
+       .driver         = {
+               .name   = OMAP_AUDIO_NAME,
+       },
+};
+
+/* Device Information */
+static struct platform_device omap_audio_device = {
+       .name = OMAP_AUDIO_NAME,
+       .dev = {
+               .driver_data = &audio_state,
+               .release = audio_free,
+               },
+       .id = 0,
+};
+
+/***************************** GLOBAL FUNCTIONs **********************************/
+
+/* Power Management Functions for Linux Device Model  */
+/* DEBUG PUPOSES ONLY! */
+#ifdef CONFIG_PM
+//#undef CONFIG_PM
+#endif
+
+#ifdef CONFIG_PM
+/*********************************************************************************
+ *
+ * audio_ldm_suspend(): Suspend operation
+ *
+ *********************************************************************************/
+static int audio_ldm_suspend(void *data)
+{
+       audio_state_t *state = data;
+
+       FN_IN;
+
+       /* 
+        * Reject the suspend request if we are already actively transmitting data 
+        * Rationale: We dont want to be suspended while in the middle of a call!
+        */
+       if (AUDIO_ACTIVE(state) && state->hw_init) {
+               printk(KERN_ERR "Audio device Active, Cannot Suspend");
+               return -EPERM;
+#if 0
+               /* NOTE:
+                * This Piece of code is commented out in hope
+                * That one day we would need to suspend the device while 
+                * audio operations are in progress and resume the operations
+                * once the resume is done.
+                * This is just a sample implementation of how it could be done.
+                * Currently NOT SUPPORTED
+                */
+               audio_stream_t *is = state->input_stream;
+               audio_stream_t *os = state->output_stream;
+               int stopstate;
+               if (is && is->buffers) {
+                       printk("IS Suspend\n");
+                       stopstate = is->stopped;
+                       audio_stop_dma(is);
+                       DMA_CLEAR(is);
+                       is->dma_spinref = 0;
+                       is->stopped = stopstate;
+               }
+               if (os && os->buffers) {
+                       printk("OS Suspend\n");
+                       stopstate = os->stopped;
+                       audio_stop_dma(os);
+                       DMA_CLEAR(os);
+                       os->dma_spinref = 0;
+                       os->stopped = stopstate;
+               }
+#endif
+       }
+
+       FN_OUT(0);
+       return 0;
+}
+
+/*********************************************************************************
+ *
+ * audio_ldm_resume(): Resume Operations
+ *
+ *********************************************************************************/
+static int audio_ldm_resume(void *data)
+{
+       audio_state_t *state = data;
+
+       FN_IN;
+       if (AUDIO_ACTIVE(state) && state->hw_init) {
+               /* Should never occur - since we never suspend with active state */
+               BUG();
+               return -EPERM;
+#if 0
+               /* NOTE:
+                * This Piece of code is commented out in hope
+                * That one day we would need to suspend the device while 
+                * audio operations are in progress and resume the operations
+                * once the resume is done.
+                * This is just a sample implementation of how it could be done.
+                * Currently NOT SUPPORTED
+                */
+               audio_stream_t *is = state->input_stream;
+               audio_stream_t *os = state->output_stream;
+               if (os && os->buffers) {
+                       printk("OS Resume\n");
+                       audio_reset(os);
+                       audio_process_dma(os);
+               }
+               if (is && is->buffers) {
+                       printk("IS Resume\n");
+                       audio_reset(is);
+                       audio_process_dma(is);
+               }
+#endif
+       }
+       FN_OUT(0);
+       return 0;
+}
+#endif                         /* End of #ifdef CONFIG_PM */
+
+/*********************************************************************************
+ *
+ * audio_free(): The Audio driver release function
+ * This is a dummy function required by the platform driver
+ *
+ *********************************************************************************/
+static void audio_free(struct device *dev)
+{
+       /* Nothing to Release! */
+}
+
+/*********************************************************************************
+ *
+ * audio_probe(): The Audio driver probe function
+ * WARNING!!!!  : It is expected that the codec would have registered with us by now
+ *
+ *********************************************************************************/
+static int audio_probe(struct platform_device *pdev)
+{
+       int ret;
+       FN_IN;
+       if (!audio_state.hw_probe) {
+               printk(KERN_ERR "Probe Function Not Registered\n");
+               return -ENODEV;
+       }
+       ret = audio_state.hw_probe();
+       FN_OUT(ret);
+       return ret;
+}
+
+/*********************************************************************************
+ *
+ * audio_remove() Function to handle removal operations
+ *
+ *********************************************************************************/
+static int audio_remove(struct platform_device *pdev)
+{
+       FN_IN;
+       if (audio_state.hw_remove) {
+               audio_state.hw_remove();
+       }
+       FN_OUT(0);
+       return 0;
+}
+
+/*********************************************************************************
+ *
+ * audio_shutdown(): Function to handle shutdown operations
+ *
+ *********************************************************************************/
+static void audio_shutdown(struct platform_device *pdev)
+{
+       FN_IN;
+       if (audio_state.hw_cleanup) {
+               audio_state.hw_cleanup();
+       }
+       FN_OUT(0);
+       return;
+}
+
+/*********************************************************************************
+ *
+ * audio_suspend(): Function to handle suspend operations 
+ *
+ *********************************************************************************/
+static int audio_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       int ret = 0;
+
+#ifdef CONFIG_PM
+       void *data = pdev->dev.driver_data;
+       FN_IN;
+       if (audio_state.hw_suspend) {
+               ret = audio_ldm_suspend(data);
+               if (ret == 0)
+                       ret = audio_state.hw_suspend();
+       }
+       if (ret) {
+               printk(KERN_INFO "Audio Suspend Failed \n");
+       } else {
+               printk(KERN_INFO "Audio Suspend Success \n");
+       }
+#endif                         /* CONFIG_PM */
+
+       FN_OUT(ret);
+       return ret;
+}
+
+/*********************************************************************************
+ *
+ * audio_resume(): Function to handle resume operations
+ *
+ *********************************************************************************/
+static int audio_resume(struct platform_device *pdev)
+{
+       int ret = 0;
+
+#ifdef CONFIG_PM
+       void *data = pdev->dev.driver_data;
+       FN_IN;
+       if (audio_state.hw_resume) {
+               ret = audio_ldm_resume(data);
+               if (ret == 0)
+                       ret = audio_state.hw_resume();
+       }
+       if (ret) {
+               printk(KERN_INFO " Audio Resume Failed \n");
+       } else {
+               printk(KERN_INFO " Audio Resume Success \n");
+       }
+#endif                         /* CONFIG_PM */
+
+       FN_OUT(ret);
+       return ret;
+}
+
+/*********************************************************************************
+ *
+ * audio_get_fops(): Return the fops required to get the function pointers of 
+ *                   OMAP Audio Driver
+ *
+ *********************************************************************************/
+struct file_operations *audio_get_fops(void)
+{
+       FN_IN;
+       FN_OUT(0);
+       return &omap_audio_fops;
+}
+
+/*********************************************************************************
+ *
+ * audio_register_codec(): Register a Codec fn points using this function
+ * WARNING!!!!!          : Codecs should ensure that they do so! no sanity checks
+ *                         during runtime is done due to obvious performance 
+ *                         penalties.
+ *
+ *********************************************************************************/
+int audio_register_codec(audio_state_t * codec_state)
+{
+       int ret;
+       FN_IN;
+
+       /* We dont handle multiple codecs now */
+       if (audio_state.hw_init) {
+               printk(KERN_ERR " Codec Already registered\n");
+               return -EPERM;
+       }
+
+       /* Grab the dma Callback */
+       audio_dma_callback = audio_get_dma_callback();
+       if (!audio_dma_callback) {
+               printk(KERN_ERR "Unable to get call back function\n");
+               return -EPERM;
+       }
+
+       /* Sanity checks */
+       if (!codec_state) {
+               printk(KERN_ERR "NULL ARGUMENT!\n");
+               return -EPERM;
+       }
+
+       if (!codec_state->hw_probe || !codec_state->hw_init
+           || !codec_state->hw_shutdown || !codec_state->client_ioctl) {
+               printk(KERN_ERR
+                      "Required Fn Entry point Missing probe=%p init=%p,down=%p,ioctl=%p!\n",
+                      codec_state->hw_probe, codec_state->hw_init,
+                      codec_state->hw_shutdown, codec_state->client_ioctl);
+               return -EPERM;
+       }
+
+       memcpy(&audio_state, codec_state, sizeof(audio_state_t));
+       mutex_init(&audio_state.mutex);
+
+       ret = platform_device_register(&omap_audio_device);
+       if (ret != 0) {
+               printk(KERN_ERR "Platform dev_register failed =%d\n", ret);
+               ret = -ENODEV;
+               goto register_out;
+       }
+
+       ret = platform_driver_register(&omap_audio_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Device Register failed =%d\n", ret);
+               ret = -ENODEV;
+               platform_device_unregister(&omap_audio_device);
+               goto register_out;
+       }
+
+      register_out:
+
+       FN_OUT(ret);
+       return ret;
+}
+
+/*********************************************************************************
+ *
+ * audio_unregister_codec(): Un-Register a Codec using this function
+ *
+ *********************************************************************************/
+int audio_unregister_codec(audio_state_t * codec_state)
+{
+       FN_IN;
+
+       /* We dont handle multiple codecs now */
+       if (!audio_state.hw_init) {
+               printk(KERN_ERR " No Codec registered\n");
+               return -EPERM;
+       }
+       /* Security check */
+       if (audio_state.hw_init != codec_state->hw_init) {
+               printk(KERN_ERR
+                      " Attempt to unregister codec which was not registered with us\n");
+               return -EPERM;
+       }
+
+       platform_driver_unregister(&omap_audio_driver);
+       platform_device_unregister(&omap_audio_device);
+
+       memset(&audio_state, 0, sizeof(audio_state_t));
+
+       FN_OUT(0);
+       return 0;
+}
+
+/***************************** MODULES SPECIFIC FUNCTION *************************/
+
+/*********************************************************************************
+ *
+ * audio_write(): Exposed to write() call
+ *
+ *********************************************************************************/
+static int
+audio_write(struct file *file, const char __user *buffer,
+               size_t count, loff_t * ppos)
+{
+       const char __user *buffer0 = buffer;
+       audio_state_t *state = file->private_data;
+       audio_stream_t *s = state->output_stream;
+       int chunksize, ret = 0;
+
+       DPRINTK("audio_write: count=%d\n", count);
+       if (*ppos != file->f_pos) {
+               printk("FPOS not ppos ppos=0x%x fpos =0x%x\n", (u32) * ppos,
+                      (u32) file->f_pos);
+               return -ESPIPE;
+       }
+       if (s->mapped) {
+               printk("s already mapped\n");
+               return -ENXIO;
+       }
+       if (!s->buffers && audio_setup_buf(s)) {
+               printk("NO MEMORY\n");
+               return -ENOMEM;
+       }
+
+       while (count > 0) {
+               audio_buf_t *b = &s->buffers[s->usr_head];
+
+               /* Wait for a buffer to become free */
+               if (file->f_flags & O_NONBLOCK) {
+                       ret = -EAGAIN;
+                       if (!s->wfc.done)
+                               break;
+               }
+               ret = -ERESTARTSYS;
+               if (wait_for_completion_interruptible(&s->wfc))
+                       break;
+
+               /* Feed the current buffer */
+               chunksize = s->fragsize - b->offset;
+               if (chunksize > count)
+                       chunksize = count;
+               DPRINTK("write %d to %d\n", chunksize, s->usr_head);
+               if (copy_from_user(b->data + b->offset, buffer, chunksize)) {
+                       printk(KERN_ERR "Audio: CopyFrom User failed \n");
+                       complete(&s->wfc);
+                       return -EFAULT;
+               }
+
+               buffer += chunksize;
+               count -= chunksize;
+               b->offset += chunksize;
+
+               if (b->offset < s->fragsize) {
+                       complete(&s->wfc);
+                       break;
+               }
+
+               /* Update pointers and send current fragment to DMA */
+               b->offset = 0;
+               if (++s->usr_head >= s->nbfrags)
+                       s->usr_head = 0;
+               /* Add the num of frags pending */
+               s->pending_frags++;
+               s->active = 1;
+
+               audio_process_dma(s);
+
+       }
+
+       if ((buffer - buffer0))
+               ret = buffer - buffer0;
+       DPRINTK("audio_write: return=%d\n", ret);
+       return ret;
+}
+
+/*********************************************************************************
+ *
+ * audio_read(): Exposed as read() function
+ *
+ *********************************************************************************/
+static int
+audio_read(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
+{
+       char __user *buffer0 = buffer;
+       audio_state_t *state = file->private_data;
+       audio_stream_t *s = state->input_stream;
+       int chunksize, ret = 0;
+       unsigned long flags;
+
+       DPRINTK("audio_read: count=%d\n", count);
+
+       if (*ppos != file->f_pos) {
+               printk("AudioRead - FPOS not ppos ppos=0x%x fpos =0x%x\n",
+                      (u32) * ppos, (u32) file->f_pos);
+               return -ESPIPE;
+       }
+       if (s->mapped) {
+               printk("AudioRead - s already mapped\n");
+               return -ENXIO;
+       }
+
+       if (!s->active) {
+               if (!s->buffers && audio_setup_buf(s)) {
+                       printk("AudioRead - No Memory\n");
+                       return -ENOMEM;
+               }
+               audio_prime_rx(state);
+       }
+
+       while (count > 0) {
+               audio_buf_t *b = &s->buffers[s->usr_head];
+
+               /* Wait for a buffer to become full */
+               if (file->f_flags & O_NONBLOCK) {
+                       ret = -EAGAIN;
+                       if (!s->wfc.done)
+                               break;
+               }
+               ret = -ERESTARTSYS;
+               if (wait_for_completion_interruptible(&s->wfc))
+                       break;
+
+               /* Grab data from the current buffer */
+               chunksize = s->fragsize - b->offset;
+               if (chunksize > count)
+                       chunksize = count;
+               DPRINTK("read %d from %d\n", chunksize, s->usr_head);
+               if (copy_to_user(buffer, b->data + b->offset, chunksize)) {
+                       complete(&s->wfc);
+                       return -EFAULT;
+               }
+               buffer += chunksize;
+               count -= chunksize;
+               b->offset += chunksize;
+               if (b->offset < s->fragsize) {
+                       complete(&s->wfc);
+                       break;
+               }
+
+               /* Update pointers and return current fragment to DMA */
+               local_irq_save(flags);
+               b->offset = 0;
+               if (++s->usr_head >= s->nbfrags)
+                       s->usr_head = 0;
+
+               s->pending_frags++;
+               local_irq_restore(flags);
+               audio_process_dma(s);
+
+       }
+
+       if ((buffer - buffer0))
+               ret = buffer - buffer0;
+       DPRINTK("audio_read: return=%d\n", ret);
+       return ret;
+}
+
+/*********************************************************************************
+ *
+ * audio_mmap(): Exposed as mmap Function
+ * !!WARNING: Still under development
+ *
+ *********************************************************************************/
+static int audio_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       audio_state_t *state = file->private_data;
+       audio_stream_t *s;
+       unsigned long size, vma_addr;
+       int i, ret;
+
+       FN_IN;
+       if (vma->vm_pgoff != 0)
+               return -EINVAL;
+
+       if (vma->vm_flags & VM_WRITE) {
+               if (!state->wr_ref)
+                       return -EINVAL;;
+               s = state->output_stream;
+       } else if (vma->vm_flags & VM_READ) {
+               if (!state->rd_ref)
+                       return -EINVAL;
+               s = state->input_stream;
+       } else
+               return -EINVAL;
+
+       if (s->mapped)
+               return -EINVAL;
+       size = vma->vm_end - vma->vm_start;
+       if (size != s->fragsize * s->nbfrags)
+               return -EINVAL;
+       if (!s->buffers && audio_setup_buf(s))
+               return -ENOMEM;
+       vma_addr = vma->vm_start;
+       for (i = 0; i < s->nbfrags; i++) {
+               audio_buf_t *buf = &s->buffers[i];
+               if (!buf->master)
+                       continue;
+               ret =
+                   remap_pfn_range(vma, vma_addr, buf->dma_addr >> PAGE_SHIFT,
+                                   buf->master, vma->vm_page_prot);
+               if (ret)
+                       return ret;
+               vma_addr += buf->master;
+       }
+       s->mapped = 1;
+
+       FN_OUT(0);
+       return 0;
+}
+
+/*********************************************************************************
+ *
+ * audio_poll(): Exposed as poll function
+ *
+ *********************************************************************************/
+static unsigned int
+audio_poll(struct file *file, struct poll_table_struct *wait)
+{
+       audio_state_t *state = file->private_data;
+       audio_stream_t *is = state->input_stream;
+       audio_stream_t *os = state->output_stream;
+       unsigned int mask = 0;
+
+       DPRINTK("audio_poll(): mode=%s%s\n",
+               (file->f_mode & FMODE_READ) ? "r" : "",
+               (file->f_mode & FMODE_WRITE) ? "w" : "");
+
+       if (file->f_mode & FMODE_READ) {
+               /* Start audio input if not already active */
+               if (!is->active) {
+                       if (!is->buffers && audio_setup_buf(is))
+                               return -ENOMEM;
+                       audio_prime_rx(state);
+               }
+               poll_wait(file, &is->wq, wait);
+       }
+
+       if (file->f_mode & FMODE_WRITE) {
+               if (!os->buffers && audio_setup_buf(os))
+                       return -ENOMEM;
+               poll_wait(file, &os->wq, wait);
+       }
+
+       if (file->f_mode & FMODE_READ)
+               if ((is->mapped && is->bytecount > 0) ||
+                   (!is->mapped && is->wfc.done > 0))
+                       mask |= POLLIN | POLLRDNORM;
+
+       if (file->f_mode & FMODE_WRITE)
+               if ((os->mapped && os->bytecount > 0) ||
+                   (!os->mapped && os->wfc.done > 0))
+                       mask |= POLLOUT | POLLWRNORM;
+
+       DPRINTK("audio_poll() returned mask of %s%s\n",
+               (mask & POLLIN) ? "r" : "", (mask & POLLOUT) ? "w" : "");
+
+       FN_OUT(mask);
+       return mask;
+}
+
+/*********************************************************************************
+ *
+ * audio_llseek(): Exposed as lseek() function.
+ *
+ *********************************************************************************/
+static loff_t audio_llseek(struct file *file, loff_t offset, int origin)
+{
+       FN_IN;
+       FN_OUT(0);
+       return -ESPIPE;
+}
+
+/*********************************************************************************
+ *
+ * audio_ioctl(): Handles generic ioctls. If there is a request for something this
+ * fn cannot handle, its then given to client specific ioctl routine, that will take
+ * up platform specific requests
+ *
+ *********************************************************************************/
+static int
+audio_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+       audio_state_t *state = file->private_data;
+       audio_stream_t *os = state->output_stream;
+       audio_stream_t *is = state->input_stream;
+       long val;
+
+       DPRINTK(__FILE__ " audio_ioctl 0x%08x\n", cmd);
+
+       /* dispatch based on command */
+       switch (cmd) {
+       case OSS_GETVERSION:
+               return put_user(SOUND_VERSION, (int __user *)arg);
+
+       case SNDCTL_DSP_GETBLKSIZE:
+               if (file->f_mode & FMODE_WRITE)
+                       return put_user(os->fragsize, (int __user *)arg);
+               else
+                       return put_user(is->fragsize, (int __user *)arg);
+
+       case SNDCTL_DSP_GETCAPS:
+               val = DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP;
+               if (is && os)
+                       val |= DSP_CAP_DUPLEX;
+               FN_OUT(1);
+               return put_user(val, (int __user *)arg);
+
+       case SNDCTL_DSP_SETFRAGMENT:
+               if (get_user(val, (long __user *)arg)) {
+                       FN_OUT(2);
+                       return -EFAULT;
+               }
+               if (file->f_mode & FMODE_READ) {
+                       int ret = audio_set_fragments(is, val);
+                       if (ret < 0) {
+                               FN_OUT(3);
+                               return ret;
+                       }
+                       ret = put_user(ret, (int __user *)arg);
+                       if (ret) {
+                               FN_OUT(4);
+                               return ret;
+                       }
+               }
+               if (file->f_mode & FMODE_WRITE) {
+                       int ret = audio_set_fragments(os, val);
+                       if (ret < 0) {
+                               FN_OUT(5);
+                               return ret;
+                       }
+                       ret = put_user(ret, (int __user *)arg);
+                       if (ret) {
+                               FN_OUT(6);
+                               return ret;
+                       }
+               }
+               FN_OUT(7);
+               return 0;
+
+       case SNDCTL_DSP_SYNC:
+               FN_OUT(8);
+               return audio_sync(file);
+
+       case SNDCTL_DSP_SETDUPLEX:
+               FN_OUT(9);
+               return 0;
+
+       case SNDCTL_DSP_POST:
+               FN_OUT(10);
+               return 0;
+
+       case SNDCTL_DSP_GETTRIGGER:
+               val = 0;
+               if (file->f_mode & FMODE_READ && is->active && !is->stopped)
+                       val |= PCM_ENABLE_INPUT;
+               if (file->f_mode & FMODE_WRITE && os->active && !os->stopped)
+                       val |= PCM_ENABLE_OUTPUT;
+               FN_OUT(11);
+               return put_user(val, (int __user *)arg);
+
+       case SNDCTL_DSP_SETTRIGGER:
+               if (get_user(val, (int __user *)arg)) {
+                       FN_OUT(12);
+                       return -EFAULT;
+               }
+               if (file->f_mode & FMODE_READ) {
+                       if (val & PCM_ENABLE_INPUT) {
+                               unsigned long flags;
+                               if (!is->active) {
+                                       if (!is->buffers && audio_setup_buf(is)) {
+                                               FN_OUT(13);
+                                               return -ENOMEM;
+                                       }
+                                       audio_prime_rx(state);
+                               }
+                               local_irq_save(flags);
+                               is->stopped = 0;
+                               local_irq_restore(flags);
+                               audio_process_dma(is);
+
+                       } else {
+                               audio_stop_dma(is);
+                       }
+               }
+               if (file->f_mode & FMODE_WRITE) {
+                       if (val & PCM_ENABLE_OUTPUT) {
+                               unsigned long flags;
+                               if (!os->buffers && audio_setup_buf(os)) {
+                                       FN_OUT(14);
+                                       return -ENOMEM;
+                               }
+                               local_irq_save(flags);
+                               if (os->mapped && !os->pending_frags) {
+                                       os->pending_frags = os->nbfrags;
+                                       init_completion(&os->wfc);
+                                       os->wfc.done = 0;
+                                       os->active = 1;
+                               }
+                               os->stopped = 0;
+                               local_irq_restore(flags);
+                               audio_process_dma(os);
+
+                       } else {
+                               audio_stop_dma(os);
+                       }
+               }
+               FN_OUT(15);
+               return 0;
+
+       case SNDCTL_DSP_GETOPTR:
+       case SNDCTL_DSP_GETIPTR:
+               {
+                       count_info inf = { 0, };
+                       audio_stream_t *s =
+                           (cmd == SNDCTL_DSP_GETOPTR) ? os : is;
+                       int bytecount, offset;
+                       unsigned long flags;
+
+                       if ((s == is && !(file->f_mode & FMODE_READ)) ||
+                           (s == os && !(file->f_mode & FMODE_WRITE))) {
+                               FN_OUT(16);
+                               return -EINVAL;
+                       }
+                       if (s->active) {
+                               local_irq_save(flags);
+                               offset = audio_get_dma_pos(s);
+                               inf.ptr = s->dma_tail * s->fragsize + offset;
+                               bytecount = s->bytecount + offset;
+                               s->bytecount = -offset;
+                               inf.blocks = s->fragcount;
+                               s->fragcount = 0;
+                               local_irq_restore(flags);
+                               if (bytecount < 0)
+                                       bytecount = 0;
+                               inf.bytes = bytecount;
+                       }
+                       FN_OUT(17);
+                       return copy_to_user((void __user *)arg, &inf, sizeof(inf));
+               }
+
+       case SNDCTL_DSP_GETOSPACE:
+       case SNDCTL_DSP_GETISPACE:
+               {
+                       audio_buf_info inf = { 0, };
+                       audio_stream_t *s =
+                           (cmd == SNDCTL_DSP_GETOSPACE) ? os : is;
+
+                       if ((s == is && !(file->f_mode & FMODE_READ)) ||
+                           (s == os && !(file->f_mode & FMODE_WRITE))) {
+                               FN_OUT(18);
+                               return -EINVAL;
+                       }
+                       if (!s->buffers && audio_setup_buf(s)) {
+                               FN_OUT(19);
+                               return -ENOMEM;
+                       }
+                       inf.bytes = s->wfc.done * s->fragsize;
+
+                       inf.fragments = inf.bytes / s->fragsize;
+                       inf.fragsize = s->fragsize;
+                       inf.fragstotal = s->nbfrags;
+                       FN_OUT(20);
+                       return copy_to_user((void __user *)arg, &inf, sizeof(inf));
+               }
+
+       case SNDCTL_DSP_NONBLOCK:
+               file->f_flags |= O_NONBLOCK;
+               FN_OUT(21);
+               return 0;
+
+       case SNDCTL_DSP_RESET:
+               if (file->f_mode & FMODE_READ) {
+                       audio_reset(is);
+                       if (state->need_tx_for_rx) {
+                               unsigned long flags;
+                               local_irq_save(flags);
+                               os->spin_idle = 0;
+                               local_irq_restore(flags);
+                       }
+               }
+               if (file->f_mode & FMODE_WRITE) {
+                       audio_reset(os);
+               }
+               FN_OUT(22);
+               return 0;
+
+       default:
+               /*
+                * Let the client of this module handle the
+                * non generic ioctls
+                */
+               FN_OUT(23);
+               return state->client_ioctl(inode, file, cmd, arg);
+       }
+
+       FN_OUT(0);
+       return 0;
+}
+
+/*********************************************************************************
+ *
+ * audio_open(): Exposed as open() function
+ *
+ *********************************************************************************/
+static int audio_open(struct inode *inode, struct file *file)
+{
+       audio_state_t *state = (&audio_state);
+       audio_stream_t *os = state->output_stream;
+       audio_stream_t *is = state->input_stream;
+       int err, need_tx_dma;
+       static unsigned char tsc2101_init_flag = 0;
+
+       FN_IN;
+
+       /* Lock the module */
+       if (!try_module_get(THIS_MODULE)) {
+               printk(KERN_CRIT "Failed to get module\n");
+               return -ESTALE;
+       }
+       /* Lock the codec module */
+       if (!try_module_get(state->owner)) {
+               printk(KERN_CRIT "Failed to get codec module\n");
+               module_put(THIS_MODULE);
+               return -ESTALE;
+       }
+
+       mutex_lock(&state->mutex);
+
+       /* access control */
+       err = -ENODEV;
+       if ((file->f_mode & FMODE_WRITE) && !os)
+               goto out;
+       if ((file->f_mode & FMODE_READ) && !is)
+               goto out;
+       err = -EBUSY;
+       if ((file->f_mode & FMODE_WRITE) && state->wr_ref)
+               goto out;
+       if ((file->f_mode & FMODE_READ) && state->rd_ref)
+               goto out;
+       err = -EINVAL;
+       if ((file->f_mode & FMODE_READ) && state->need_tx_for_rx && !os)
+               goto out;
+
+       /* request DMA channels */
+       need_tx_dma = ((file->f_mode & FMODE_WRITE) ||
+                      ((file->f_mode & FMODE_READ) && state->need_tx_for_rx));
+       if (state->wr_ref || (state->rd_ref && state->need_tx_for_rx))
+               need_tx_dma = 0;
+       if (need_tx_dma) {
+               DMA_REQUEST(err, os, audio_dma_callback);
+               if (err < 0)
+                       goto out;
+       }
+       if (file->f_mode & FMODE_READ) {
+               DMA_REQUEST(err, is, audio_dma_callback);
+               if (err < 0) {
+                       if (need_tx_dma)
+                               DMA_FREE(os);
+                       goto out;
+               }
+       }
+
+       /* now complete initialisation */
+       if (!AUDIO_ACTIVE(state)) {
+               if (state->hw_init && !tsc2101_init_flag) {
+                       state->hw_init(state->data);
+                       tsc2101_init_flag = 0;
+
+               }
+
+       }
+
+       if ((file->f_mode & FMODE_WRITE)) {
+               state->wr_ref = 1;
+               audio_reset(os);
+               os->fragsize = AUDIO_FRAGSIZE_DEFAULT;
+               os->nbfrags = AUDIO_NBFRAGS_DEFAULT;
+               os->mapped = 0;
+               init_waitqueue_head(&os->wq);
+       }
+
+       if (file->f_mode & FMODE_READ) {
+               state->rd_ref = 1;
+               audio_reset(is);
+               is->fragsize = AUDIO_FRAGSIZE_DEFAULT;
+               is->nbfrags = AUDIO_NBFRAGS_DEFAULT;
+               is->mapped = 0;
+               init_waitqueue_head(&is->wq);
+       }
+
+       file->private_data = state;
+       err = 0;
+
+      out:
+       mutex_unlock(&state->mutex);
+       if (err) {
+               module_put(state->owner);
+               module_put(THIS_MODULE);
+       }
+       FN_OUT(err);
+       return err;
+}
+
+/*********************************************************************************
+ *
+ * audio_release(): Exposed as release function()
+ *
+ *********************************************************************************/
+static int audio_release(struct inode *inode, struct file *file)
+{
+       audio_state_t *state = file->private_data;
+       audio_stream_t *os = state->output_stream;
+       audio_stream_t *is = state->input_stream;
+
+       FN_IN;
+
+       mutex_lock(&state->mutex);
+
+       if (file->f_mode & FMODE_READ) {
+               audio_discard_buf(is);
+               DMA_FREE(is);
+               is->dma_spinref = 0;
+               if (state->need_tx_for_rx) {
+                       os->spin_idle = 0;
+                       if (!state->wr_ref) {
+                               DMA_FREE(os);
+                               os->dma_spinref = 0;
+                       }
+               }
+               state->rd_ref = 0;
+       }
+
+       if (file->f_mode & FMODE_WRITE) {
+               audio_sync(file);
+               audio_discard_buf(os);
+               if (!state->need_tx_for_rx || !state->rd_ref) {
+                       DMA_FREE(os);
+                       os->dma_spinref = 0;
+               }
+               state->wr_ref = 0;
+       }
+
+       if (!AUDIO_ACTIVE(state)) {
+               if (state->hw_shutdown)
+                       state->hw_shutdown(state->data);
+       }
+
+       mutex_unlock(&state->mutex);
+
+       module_put(state->owner);
+       module_put(THIS_MODULE);
+
+       FN_OUT(0);
+       return 0;
+}
+
+EXPORT_SYMBOL(audio_register_codec);
+EXPORT_SYMBOL(audio_unregister_codec);
+EXPORT_SYMBOL(audio_get_fops);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("Common audio handling for OMAP processors");
+MODULE_LICENSE("GPL");
diff --git a/sound/oss/omap-audio.h b/sound/oss/omap-audio.h
new file mode 100644 (file)
index 0000000..c039dee
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * linux/sound/oss/omap-audio.h
+ *
+ * Common audio handling for the OMAP processors
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
+ *
+ * This package 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.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *  History
+ *  -------
+ *  2004/08/12 Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms
+ *
+ *  2004/04/04 Nishanth menon - Added hooks for power management
+ *
+ *  2005/12/10 Dirk Behme     - Added L/R Channel Interchange fix as proposed by Ajaya Babu
+ */
+
+#ifndef __OMAP_AUDIO_H
+#define __OMAP_AUDIO_H
+
+/* Requires dma.h */
+#include <asm/arch/dma.h>
+
+/*
+ * Buffer Management
+ */
+typedef struct {
+       int offset;             /* current offset */
+       char *data;             /* points to actual buffer */
+       dma_addr_t dma_addr;    /* physical buffer address */
+       int dma_ref;            /* DMA refcount */
+       int master;             /* owner for buffer allocation, contain size when true */
+} audio_buf_t;
+
+/*
+ * Structure describing the data stream related information
+ */
+typedef struct {
+       char *id;               /* identification string */
+       audio_buf_t *buffers;   /* pointer to audio buffer structures */
+       u_int usr_head;         /* user fragment index */
+       u_int dma_head;         /* DMA fragment index to go */
+       u_int dma_tail;         /* DMA fragment index to complete */
+       u_int fragsize;         /* fragment i.e. buffer size */
+       u_int nbfrags;          /* nbr of fragments i.e. buffers */
+       u_int pending_frags;    /* Fragments sent to DMA */
+       int dma_dev;            /* device identifier for DMA */
+
+#ifdef OMAP_DMA_CHAINING_SUPPORT
+       lch_chain *dma_chain;
+       dma_regs_t *dma_regs;   /* points to our DMA registers */
+#else
+       char started;           /* to store if the chain was started or not */
+       int dma_q_head;         /* DMA Channel Q Head */
+       int dma_q_tail;         /* DMA Channel Q Tail */
+       char dma_q_count;       /* DMA Channel Q Count */
+       char in_use;            /*  Is this is use? */
+       int *lch;               /*  Chain of channels this stream is linked to */
+#endif
+       int input_or_output;    /* Direction of this data stream */
+       int bytecount;          /* nbr of processed bytes */
+       int fragcount;          /* nbr of fragment transitions */
+       struct completion wfc;  /* wait for "nbfrags" fragment completion */
+       wait_queue_head_t wq;   /* for poll */
+       int dma_spinref;        /* DMA is spinning */
+       unsigned mapped:1;      /* mmap()'ed buffers */
+       unsigned active:1;      /* actually in progress */
+       unsigned stopped:1;     /* might be active but stopped */
+       unsigned spin_idle:1;   /* have DMA spin on zeros when idle */
+       unsigned linked:1;      /* dma channels linked */
+       int (*hw_start)(void);  /* interface to start HW interface, e.g. McBSP */
+       int (*hw_stop)(void);   /* interface to stop HW interface, e.g. McBSP */
+} audio_stream_t;
+
+/*
+ * State structure for one instance
+ */
+typedef struct {
+       struct module *owner;   /* Codec module ID */
+       audio_stream_t *output_stream;
+       audio_stream_t *input_stream;
+       unsigned rd_ref:1;      /* open reference for recording */
+       unsigned wr_ref:1;      /* open reference for playback */
+       unsigned need_tx_for_rx:1; /* if data must be sent while receiving */
+       void *data;
+       void (*hw_init) (void *);
+       void (*hw_shutdown) (void *);
+       int (*client_ioctl) (struct inode *, struct file *, uint, ulong);
+       int (*hw_probe) (void);
+       void (*hw_remove) (void);
+       void (*hw_cleanup) (void);
+       int (*hw_suspend) (void);
+       int (*hw_resume) (void);
+       struct pm_dev *pm_dev;
+       struct mutex mutex;     /* to protect against races in attach() */
+} audio_state_t;
+
+#ifdef AUDIO_PM
+void audio_ldm_suspend(void *data);
+
+void audio_ldm_resume(void *data);
+
+#endif
+
+/* Register a Codec using this function */
+extern int audio_register_codec(audio_state_t * codec_state);
+/* Un-Register a Codec using this function */
+extern int audio_unregister_codec(audio_state_t * codec_state);
+/* Function to provide fops of omap audio driver */
+extern struct file_operations *audio_get_fops(void);
+/* Function to initialize the device info for audio driver */
+extern int audio_dev_init(void);
+/* Function to un-initialize the device info for audio driver */
+void audio_dev_uninit(void);
+
+#endif                         /* End of #ifndef __OMAP_AUDIO_H */