]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge omap-drivers
authorTony Lindgren <tony@atomide.com>
Fri, 11 May 2007 00:29:50 +0000 (17:29 -0700)
committerTony Lindgren <tony@atomide.com>
Fri, 11 May 2007 00:29:50 +0000 (17:29 -0700)
Merge branches 'master' and 'omap-drivers'

Conflicts:

arch/arm/configs/omap_h2_1610_defconfig
arch/arm/configs/omap_osk_5912_defconfig
arch/arm/mach-omap1/board-h2.c
arch/arm/mach-omap1/board-palmte.c
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/board-2430sdp.c
arch/arm/mach-omap2/board-h4.c
arch/arm/mach-omap2/board-n800-audio.c
arch/arm/mach-omap2/board-n800-dsp.c
arch/arm/mach-omap2/board-n800-usb.c
arch/arm/mach-omap2/devices.c
arch/arm/mach-omap2/pm.c
arch/arm/plat-omap/Kconfig
arch/arm/plat-omap/Makefile
arch/arm/plat-omap/devices.c
drivers/Makefile
drivers/i2c/chips/Kconfig
drivers/i2c/chips/Makefile
drivers/i2c/chips/gpio_expander_omap.c
drivers/i2c/chips/menelaus.c
drivers/i2c/chips/tlv320aic23.c
drivers/i2c/chips/twl4030_core.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/video/Kconfig
include/asm-arm/arch-omap/dsp.h
include/asm-arm/arch-omap/eac.h
include/asm-arm/arch-omap/gpio.h
include/asm-arm/arch-omap/mmc.h
include/asm-arm/arch-omap/omap24xx.h
include/asm-arm/arch-omap/onenand.h
include/asm-arm/arch-omap/pm.h
include/asm-arm/hardware/tsc2101.h
net/ipv4/netfilter/Kconfig

240 files changed:
Documentation/arm/OMAP/README [new file with mode: 0644]
Documentation/arm/OMAP/gpio [new file with mode: 0644]
Makefile
arch/arm/boot/.gitignore
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/Makefile
arch/arm/mach-omap1/board-h2.c
arch/arm/mach-omap1/board-palmte.c
arch/arm/mach-omap1/devices.c
arch/arm/mach-omap1/mmu.c [new file with mode: 0644]
arch/arm/mach-omap1/mmu.h [new file with mode: 0644]
arch/arm/mach-omap1/pm.c
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/board-2430sdp-flash.c [new file with mode: 0644]
arch/arm/mach-omap2/board-2430sdp.c
arch/arm/mach-omap2/board-h4.c
arch/arm/mach-omap2/board-n800-audio.c
arch/arm/mach-omap2/board-n800-dsp.c
arch/arm/mach-omap2/board-n800-usb.c
arch/arm/mach-omap2/clock.c
arch/arm/mach-omap2/clock.h
arch/arm/mach-omap2/devices.c
arch/arm/mach-omap2/gpmc.c
arch/arm/mach-omap2/io.c
arch/arm/mach-omap2/mmu.c [new file with mode: 0644]
arch/arm/mach-omap2/mmu.h [new file with mode: 0644]
arch/arm/mach-omap2/pm.c
arch/arm/mach-omap2/prcm-regs.h
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_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/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/mmu.h [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/mmu.c [new file with mode: 0644]
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]
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/bluetooth/hci_h4p/Makefile [new file with mode: 0644]
drivers/bluetooth/hci_h4p/core.c [new file with mode: 0644]
drivers/bluetooth/hci_h4p/fw-csr.c [new file with mode: 0644]
drivers/bluetooth/hci_h4p/fw-ti.c [new file with mode: 0644]
drivers/bluetooth/hci_h4p/fw.c [new file with mode: 0644]
drivers/bluetooth/hci_h4p/hci_h4p.h [new file with mode: 0644]
drivers/bluetooth/hci_h4p/sysfs.c [new file with mode: 0644]
drivers/bluetooth/hci_h4p/uart.c [new file with mode: 0644]
drivers/char/Kconfig
drivers/char/Makefile
drivers/char/hw_random/omap-rng.c
drivers/char/omap-rtc.c [new file with mode: 0644]
drivers/char/omap-rtc.h [new file with mode: 0644]
drivers/i2c/chips/Kconfig
drivers/i2c/chips/Makefile
drivers/i2c/chips/menelaus.c
drivers/i2c/chips/tlv320aic23.c
drivers/i2c/chips/twl4030_core.c
drivers/i2c/chips/twl4030_gpio.c [new file with mode: 0644]
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/keyboard/tsc2301_kp.c [new file with mode: 0644]
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
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/tsc2046_ts.c [new file with mode: 0644]
drivers/input/touchscreen/tsc2102_ts.c [new file with mode: 0644]
drivers/input/touchscreen/tsc2301_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/radio/Kconfig
drivers/media/radio/Makefile
drivers/media/radio/radio-tea5761.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/host/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/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/backlight/Kconfig
drivers/video/backlight/Makefile
drivers/video/backlight/omap_bl.c [new file with mode: 0644]
include/asm-arm/.gitignore
include/asm-arm/arch-omap/dsp.h [new file with mode: 0644]
include/asm-arm/arch-omap/eac.h
include/asm-arm/arch-omap/gpio.h
include/asm-arm/arch-omap/gpmc.h
include/asm-arm/arch-omap/irqs.h
include/asm-arm/arch-omap/mmc.h
include/asm-arm/arch-omap/mmu.h [new file with mode: 0644]
include/asm-arm/arch-omap/omap-alsa.h
include/asm-arm/arch-omap/omap24xx.h
include/asm-arm/arch-omap/onenand.h
include/asm-arm/arch-omap/pm.h
include/asm-arm/arch-omap/sti.h [new file with mode: 0644]
include/asm-arm/hardware/tsc2101.h
include/asm-arm/mach/flash.h
include/asm-arm/pgtable.h
include/asm-arm/setup.h
include/linux/connector.h
include/linux/input.h
include/linux/spi/tsc2046.h [new file with mode: 0644]
include/linux/usb/musb.h [new file with mode: 0644]
kernel/printk.c
net/ipv4/netfilter/Kconfig
security/Kconfig
security/Makefile
security/lowmem.c [new file with mode: 0644]
sound/arm/Kconfig
sound/arm/Makefile
sound/arm/omap/Makefile [new file with mode: 0644]
sound/arm/omap/eac.c [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 dfe559c89fe63ef59c8eab589c7ded58190e5339..a84d0c982f45ba00c28dee855d671d7a2669f2da 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -16,6 +16,9 @@ NAME = Nocturnal Monster Puppy
 # 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 171a0853caf8caee50be7aa778867a2ae8f76870..fc9b99cfcdd0ada120c333f80aa6872c281db4cb 100644 (file)
@@ -1,2 +1,3 @@
 Image
 zImage
+uImage
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..87f6c96
--- /dev/null
@@ -0,0 +1,1535 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21-rc7-omap1
+# Mon Apr 23 08:46:31 2007
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+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_ZONE_DMA=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_SYSVIPC_SYSCTL=y
+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_BLK_DEV_INITRD=y
+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_NS9XXX 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_MMU_FWK=y
+CONFIG_OMAP_MBOX_FWK=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 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 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_NOKIA_N800=y
+CONFIG_MACH_OMAP2_TUSB6010=y
+# CONFIG_MACH_OMAP_H4 is not set
+# CONFIG_MACH_OMAP_APOLLON is not set
+# CONFIG_MACH_OMAP_2430SDP 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
+# CONFIG_OUTER_CACHE 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_ZONE_DMA_FLAG=1
+CONFIG_LEDS=y
+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
+# CONFIG_KEXEC 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_EMULATION 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_XFRM_MIGRATE 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_TARGET_TCPMSS 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_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_HCIH4P 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_DEBUG_DEVRES 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_BLKDEVS=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
+#
+# CONFIG_PNPACPI is not set
+
+#
+# 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_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_KEYBOARD_GPIO is not set
+CONFIG_KEYBOARD_TSC2301=y
+# 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_TSC2301=y
+# 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_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_OMAP24XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_TSC2101 is not set
+# CONFIG_SPI_TSC2102 is not set
+CONFIG_SPI_TSC2301=y
+CONFIG_SPI_TSC2301_AUDIO=y
+
+#
+# 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_ADM1029 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
+#
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 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_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_RADIO_TEA5761 is not set
+# CONFIG_USB_DSBR is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SVGALIB 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
+
+#
+# Frambuffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+CONFIG_FB_OMAP_LCDC_EXTERNAL=y
+# CONFIG_FB_OMAP_LCDC_HWA742 is not set
+CONFIG_FB_OMAP_LCDC_BLIZZARD=y
+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
+# 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
+
+#
+# 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
+CONFIG_SND_OMAP24XX_EAC=y
+
+#
+# USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+
+#
+# SoC audio support
+#
+# CONFIG_SND_SOC is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG 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=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DYNAMIC_MINORS=y
+CONFIG_USB_SUSPEND=y
+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
+# CONFIG_USB_GTCO 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_DM9601 is not set
+# 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_KC2190 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_BERRY_CHARGE 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_IOWARRIOR 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
+
+#
+# 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
+# CONFIG_CBUS_RETU_HEADSET is not set
+
+#
+# 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_DEBUG_SHIRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS 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_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_FAULT_INJECTION 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
+# CONFIG_SECURITY_LOWMEM 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_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
diff --git a/arch/arm/configs/omap_2430sdp_defconfig b/arch/arm/configs/omap_2430sdp_defconfig
new file mode 100644 (file)
index 0000000..19d49b0
--- /dev/null
@@ -0,0 +1,1348 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21-rc3-omap1
+# Mon Mar 19 22:43:37 2007
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+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_ZONE_DMA=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_SYSVIPC_SYSCTL=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_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_BLK_DEV_INITRD=y
+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_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=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_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_NS9XXX 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 is not set
+# CONFIG_OMAP_MUX_WARNINGS is not set
+# CONFIG_OMAP_STI is not set
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+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_NOKIA_N800 is not set
+# 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
+# CONFIG_OUTER_CACHE 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=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_ZONE_DMA_FLAG=1
+# 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
+# CONFIG_KEXEC 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
+
+#
+# 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_EMULATION 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_XFRM_MIGRATE is not set
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE 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 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_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_DEBUG_DEVRES 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_BLKDEVS=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=y
+CONFIG_MTD_ONENAND_VERIFY_WRITE=y
+# CONFIG_MTD_ONENAND_GENERIC is not set
+CONFIG_MTD_ONENAND_OMAP2=y
+# CONFIG_MTD_ONENAND_OTP is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# 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=16384
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=m
+# CONFIG_SCSI_TGT 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=m
+# 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=m
+# 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 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_KEYBOARD_GPIO 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=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=y
+CONFIG_HW_RANDOM_OMAP=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_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
+#
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 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
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SVGALIB 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
+
+#
+# Frambuffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX 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_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
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG 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=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+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=m
+CONFIG_USB_MUSB_SOC=y
+
+#
+# OMAP 243x high speed USB support
+#
+# 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=y
+# CONFIG_USB_TI_CPPI_DMA is not set
+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=m
+# 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 is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=m
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV 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
+# CONFIG_USB_GTCO 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 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_BERRY_CHARGE 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_IOWARRIOR is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=m
+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=m
+# CONFIG_USB_ZERO_HNPTEST is not set
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+# 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
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS 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_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 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=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
+
+#
+# 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=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+CONFIG_TIMER_STATS=y
+# 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 is not set
+CONFIG_DEBUG_MUTEXES=y
+# 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_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_FAULT_INJECTION 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=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_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# 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_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# 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_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=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..fd4d093624ec4601eef94f88f7d16b248408f110 100644 (file)
@@ -1,18 +1,24 @@
 #
 # 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.21-rc3-omap1
+# Wed Mar 14 18:03:53 2007
 #
 CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
 # CONFIG_GENERIC_TIME is not set
 CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
 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_ZONE_DMA=y
 CONFIG_VECTORS_BASE=0xffff0000
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
@@ -21,7 +27,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
 
 #
@@ -32,14 +37,16 @@ CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
 # 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_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_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
@@ -47,6 +54,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,10 +121,12 @@ 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
 # CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_NS9XXX is not set
 # CONFIG_ARCH_PNX4008 is not set
 # CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
@@ -137,20 +147,25 @@ 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_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+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 +189,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
 
 #
@@ -201,6 +216,7 @@ CONFIG_ARM_THUMB=y
 # CONFIG_CPU_DCACHE_DISABLE is not set
 # CONFIG_CPU_DCACHE_WRITETHROUGH is not set
 # CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+# CONFIG_OUTER_CACHE is not set
 
 #
 # Bus support
@@ -214,9 +230,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 +244,10 @@ 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_ZONE_DMA_FLAG=1
+CONFIG_LEDS=y
+# CONFIG_LEDS_TIMER is not set
+# CONFIG_LEDS_CPU is not set
 CONFIG_ALIGNMENT_TRAP=y
 
 #
@@ -236,24 +255,14 @@ 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
+# CONFIG_KEXEC 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
@@ -282,7 +291,7 @@ 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
+# CONFIG_APM_EMULATION is not set
 
 #
 # Networking
@@ -299,6 +308,7 @@ CONFIG_UNIX=y
 CONFIG_XFRM=y
 # CONFIG_XFRM_USER is not set
 # CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
@@ -382,6 +392,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_FW_LOADER is not set
+CONFIG_DEBUG_DRIVER=y
+# CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
 
 #
@@ -392,7 +404,88 @@ 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_BLKDEVS=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_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 is not set
 
 #
 # Parallel port support
@@ -402,6 +495,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -410,55 +504,20 @@ 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 +687,15 @@ 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_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,13 +708,63 @@ 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
 #
-# CONFIG_SPI is not set
-# CONFIG_SPI_MASTER is not set
+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
+#
+CONFIG_SPI_TSC2101=y
+# CONFIG_TSC2102 is not set
+# CONFIG_SPI_AT25 is not set
 
 #
 # Dallas's 1-wire bus
@@ -661,14 +777,56 @@ 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_ADM1029 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
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
 
 #
 # LED devices
@@ -692,20 +850,34 @@ CONFIG_HWMON=y
 # Digital Video Broadcasting Devices
 #
 # CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
 
 #
 # Graphics support
 #
-CONFIG_FIRMWARE_EDID=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB_DDC is not set
 # CONFIG_FB_CFB_FILLRECT is not set
 # CONFIG_FB_CFB_COPYAREA is not set
 # CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SVGALIB is not set
 # CONFIG_FB_MACMODES is not set
 # CONFIG_FB_BACKLIGHT is not set
 CONFIG_FB_MODE_HELPERS=y
 # CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frambuffer hardware drivers
+#
 # CONFIG_FB_S1D13XXX 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
 # CONFIG_FB_VIRTUAL is not set
 
 #
@@ -715,17 +887,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
@@ -734,24 +898,17 @@ 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
+# 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
+# CONFIG_HID_DEBUG is not set
 
 #
 # USB support
@@ -759,16 +916,144 @@ 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_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+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_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO 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
+# CONFIG_USB_GTCO 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_BERRY_CHARGE 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_IOWARRIOR 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 +1066,11 @@ CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_RTC_LIB=y
 # CONFIG_RTC_CLASS is not set
 
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
 #
 # File systems
 #
@@ -841,6 +1131,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 +1151,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 +1235,33 @@ 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_DEBUG_SHIRQ is not set
 CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS 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_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_FAULT_INJECTION is not set
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_LL is not set
 
 #
 # Security options
@@ -956,50 +1272,18 @@ 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_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=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..307277c
--- /dev/null
@@ -0,0 +1,1254 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21-rc3-omap1
+# Wed Mar 14 18:04:35 2007
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+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_ZONE_DMA=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_SYSVIPC_SYSCTL=y
+# 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_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+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=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_NS9XXX 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=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_STI is not set
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+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
+#
+# 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_NOKIA770 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
+
+#
+# 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
+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_CACHE_ROUND_ROBIN is not set
+# CONFIG_OUTER_CACHE 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_ZONE_DMA_FLAG=1
+CONFIG_LEDS=y
+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
+# CONFIG_KEXEC 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
+# CONFIG_PM_LEGACY is not set
+# CONFIG_PM_DEBUG is not set
+# CONFIG_PM_SYSFS_DEPRECATED is not set
+# CONFIG_APM_EMULATION 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_XFRM_MIGRATE 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=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_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=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_MCS_FIR is not set
+# CONFIG_OMAP_IR 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_DEBUG_DEVRES 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
+#
+# CONFIG_PNPACPI is not set
+
+#
+# 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_RAM_BLOCKSIZE=1024
+# 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=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_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLHC=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
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# 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_STOWAWAY is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_KEYBOARD_GPIO 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_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 is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_HW_RANDOM=m
+CONFIG_HW_RANDOM_OMAP=m
+# 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
+
+#
+# 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=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
+
+#
+# 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
+#
+CONFIG_TSC2101=y
+# CONFIG_TSC2102 is not set
+# CONFIG_SPI_AT25 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_ADM1029 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
+#
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L1=y
+CONFIG_VIDEO_V4L1_COMPAT=y
+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_CPIA is not set
+# CONFIG_VIDEO_CPIA2 is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+
+#
+# V4L USB devices
+#
+# CONFIG_VIDEO_PVRUSB2 is not set
+# CONFIG_VIDEO_EM28XX is not set
+# CONFIG_VIDEO_USBVISION is not set
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_QUICKCAM_MESSENGER is not set
+# CONFIG_USB_ET61X251 is not set
+# CONFIG_VIDEO_OVCAMCHIP is not set
+# CONFIG_USB_W9968CF 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_ZC0301 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_VIDEO_OMAP_CAMERA is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_TEA5761 is not set
+# CONFIG_USB_DSBR is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frambuffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX 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
+# 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
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=y
+# CONFIG_OBSOLETE_OSS is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_TVMIXER is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG 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=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS 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_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# Enable Host or Gadget support to see Inventra options
+#
+# 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_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
+# CONFIG_USB_GTCO 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_BERRY_CHARGE 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_IOWARRIOR 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_OMAP=y
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS 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_EXT4DEV_FS 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_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_ROMFS_FS=y
+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_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=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_DEBUG_SHIRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS 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_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=y
+# 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_FAULT_INJECTION 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 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_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
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..8ef2d68
--- /dev/null
@@ -0,0 +1,1168 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.20-omap1
+# Sat Feb 17 00:17:16 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=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_SYSFS_DEPRECATED=y
+# 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=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_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=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_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_DEBUG_DEVICES=y
+# 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=y
+# CONFIG_ARCH_OMAP2430 is not set
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_NOKIA_N800 is not set
+CONFIG_MACH_OMAP_H4=y
+# CONFIG_MACH_OMAP_2430SDP is not set
+# CONFIG_MACH_OMAP_H4_TUSB is not set
+# CONFIG_MACH_OMAP_H4_OTG is not set
+# CONFIG_MACH_OMAP2_H4_USB1 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 is not set
+CONFIG_HZ=100
+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 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
+
+#
+# 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_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=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
+# 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_BLKDEVS=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=m
+CONFIG_HW_RANDOM_OMAP=m
+# 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=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=y
+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 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
+
+#
+# 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 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_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 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
+
+#
+# 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=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=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_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=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_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
+#
+
+#
+# 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_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 391b6f4827f6a82db99753003a6e4510daea3f17..83776653906c0d6f6821e027b1df11292ae882f2 100644 (file)
@@ -10,6 +10,12 @@ obj-$(CONFIG_OMAP_MPU_TIMER)         += time.o
 # Power Management
 obj-$(CONFIG_PM) += pm.o sleep.o
 
+# DSP
+obj-$(CONFIG_OMAP_MMU_FWK)     += mmu_mach.o
+obj-$(CONFIG_OMAP_MBOX_FWK)    += mailbox_mach.o
+mailbox_mach-objs              := mailbox.o
+mmu_mach-objs                  := mmu.o
+
 led-y := leds.o
 
 # Specific board support
index 07940545bbf1251bf14996a46b5ae408a79e732c..d2214ad30a3b5e6b2632776dfbd24e5a39e1cb44 100644 (file)
@@ -142,8 +142,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
@@ -200,7 +198,6 @@ static struct platform_device h2_nand_device = {
        .num_resources  = 1,
        .resource       = &h2_nand_resource,
 };
-#endif
 
 static struct resource h2_smc91x_resources[] = {
        [0] = {
@@ -422,7 +419,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,
@@ -506,12 +503,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 c23e8b6b0a3481474dd9a658c8b3687ac10a442e..c0bc1e54ee1864f9c171711fee6bc13939bf4d20 100644 (file)
@@ -10,6 +10,8 @@
  * Maintainters : http://palmtelinux.sf.net
  *                palmtelinux-developpers@lists.sf.net
  *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
@@ -24,8 +26,8 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/tsc2102.h>
 #include <linux/interrupt.h>
+#include <linux/apm-emulation.h>
 
-#include <asm/apm.h>
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -43,6 +45,7 @@
 #include <asm/arch/common.h>
 #include <asm/arch/mcbsp.h>
 #include <asm/arch/omap-alsa.h>
+#include <asm/arch/gpio-switch.h>
 
 static void __init omap_palmte_init_irq(void)
 {
@@ -51,11 +54,11 @@ static void __init omap_palmte_init_irq(void)
        omap_gpio_init();
 }
 
-static int palmte_keymap[] = {
-       KEY(0, 0, KEY_F1),
-       KEY(0, 1, KEY_F2),
-       KEY(0, 2, KEY_F3),
-       KEY(0, 3, KEY_F4),
+static const int palmte_keymap[] = {
+       KEY(0, 0, KEY_F1),              /* Calendar */
+       KEY(0, 1, KEY_F2),              /* Contacts */
+       KEY(0, 2, KEY_F3),              /* Tasks List */
+       KEY(0, 3, KEY_F4),              /* Note Pad */
        KEY(0, 4, KEY_POWER),
        KEY(1, 0, KEY_LEFT),
        KEY(1, 1, KEY_DOWN),
@@ -68,7 +71,7 @@ static int palmte_keymap[] = {
 static struct omap_kp_platform_data palmte_kp_data = {
        .rows   = 8,
        .cols   = 8,
-       .keymap = palmte_keymap,
+       .keymap = (int *) palmte_keymap,
        .rep    = 1,
        .delay  = 12,
 };
@@ -180,7 +183,7 @@ static struct platform_device palmte_irda_device = {
        .resource       = palmte_irda_resources,
 };
 
-static struct platform_device *devices[] __initdata = {
+static struct platform_device *palmte_devices[] __initdata = {
        &palmte_rom_device,
        &palmte_kp_device,
        &palmte_lcd_device,
@@ -273,7 +276,7 @@ static void palmte_get_power_status(struct apm_power_info *info, int *battery)
                info->time = 0;
        } else {
                while (hi > lo + 1) {
-                       mid = (hi + lo) >> 2;
+                       mid = (hi + lo) >> 1;
                        if (batt <= palmte_battery_sample[mid])
                                lo = mid;
                        else
@@ -339,74 +342,64 @@ static struct spi_board_info palmte_spi_info[] __initdata = {
        },
 };
 
-/* Periodically check for changes on important input pins */
-struct timer_list palmte_pin_timer;
-int prev_power, prev_headphones;
-
-static void palmte_pin_handler(unsigned long data) {
-       int power, headphones;
-
-       power = !omap_get_gpio_datain(PALMTE_DC_GPIO);
-       headphones = omap_get_gpio_datain(PALMTE_HEADPHONES_GPIO);
-
-       if (power && !prev_power)
-               printk(KERN_INFO "PM: cable connected\n");
-       else if (!power && prev_power)
-               printk(KERN_INFO "PM: cable disconnected\n");
-
-       if (headphones && !prev_headphones) {
+static void palmte_headphones_detect(void *data, int state) {
+       if (state) {
                /* Headphones connected, disable speaker */
                omap_set_gpio_dataout(PALMTE_SPEAKER_GPIO, 0);
                printk(KERN_INFO "PM: speaker off\n");
-       } else if (!headphones && prev_headphones) {
+       } else {
                /* Headphones unplugged, re-enable speaker */
                omap_set_gpio_dataout(PALMTE_SPEAKER_GPIO, 1);
                printk(KERN_INFO "PM: speaker on\n");
        }
-
-       prev_power = power;
-       prev_headphones = headphones;
-       mod_timer(&palmte_pin_timer, jiffies + msecs_to_jiffies(500));
 }
 
-static void __init palmte_gpio_setup(void)
+static struct omap_gpio_switch palmte_switches[] __initdata = {
+       /* Speaker-enable pin is an output */
+       {
+               .name   = "speaker-enable",
+               .gpio   = PALMTE_SPEAKER_GPIO,
+               .type   = OMAP_GPIO_SWITCH_TYPE_ACTIVITY,
+               .flags  = OMAP_GPIO_SWITCH_FLAG_OUTPUT |
+                       OMAP_GPIO_SWITCH_FLAG_INVERTED,
+       },
+       /* Indicates whether power is from DC-IN or battery */
+       {
+               .name   = "dc-in",
+               .gpio   = PALMTE_DC_GPIO,
+               .type   = OMAP_GPIO_SWITCH_TYPE_CONNECTION,
+               .flags  = OMAP_GPIO_SWITCH_FLAG_INVERTED,
+       },
+       /* Indicates whether a USB host is on the other end of the cable */
+       {
+               .name   = "usb",
+               .gpio   = PALMTE_USBDETECT_GPIO,
+               .type   = OMAP_GPIO_SWITCH_TYPE_CONNECTION,
+       },
+       /* High when headphones jack is plugged in */
+       {
+               .name   = "headphones",
+               .gpio   = PALMTE_HEADPHONES_GPIO,
+               .type   = OMAP_GPIO_SWITCH_TYPE_CONNECTION,
+               .notify = palmte_headphones_detect,
+       },
+};
+
+static void __init palmte_misc_gpio_setup(void)
 {
-       /* Set TSC2102 PINTDAV pin as input */
+       /* Set TSC2102 PINTDAV pin as input (used by TSC2102 driver) */
        if (omap_request_gpio(PALMTE_PINTDAV_GPIO)) {
                printk(KERN_ERR "Could not reserve PINTDAV GPIO!\n");
                return;
        }
        omap_set_gpio_direction(PALMTE_PINTDAV_GPIO, 1);
 
-       /* Monitor cable-connected signals */
-       if (omap_request_gpio(PALMTE_DC_GPIO) ||
-                       omap_request_gpio(PALMTE_USB_OR_DC_GPIO) ||
-                       omap_request_gpio(PALMTE_USBDETECT_GPIO)) {
+       /* Set USB-or-DC-IN pin as input (unused) */
+       if (omap_request_gpio(PALMTE_USB_OR_DC_GPIO)) {
                printk(KERN_ERR "Could not reserve cable signal GPIO!\n");
                return;
        }
-       omap_set_gpio_direction(PALMTE_DC_GPIO, 1);
        omap_set_gpio_direction(PALMTE_USB_OR_DC_GPIO, 1);
-       omap_set_gpio_direction(PALMTE_USBDETECT_GPIO, 1);
-
-       /* Set speaker-enable pin as output */
-       if (omap_request_gpio(PALMTE_SPEAKER_GPIO)) {
-               printk(KERN_ERR "Could not reserve speaker GPIO!\n");
-               return;
-       }
-       omap_set_gpio_direction(PALMTE_SPEAKER_GPIO, 0);
-
-       /* Monitor the headphones-connected signal */
-       if (omap_request_gpio(PALMTE_HEADPHONES_GPIO)) {
-               printk(KERN_ERR "Could not reserve headphones signal GPIO!\n");
-               return;
-       }
-       omap_set_gpio_direction(PALMTE_HEADPHONES_GPIO, 1);
-
-       prev_power = omap_get_gpio_datain(PALMTE_DC_GPIO);
-       prev_headphones = !omap_get_gpio_datain(PALMTE_HEADPHONES_GPIO);
-       setup_timer(&palmte_pin_timer, palmte_pin_handler, 0);
-       palmte_pin_handler(0);
 }
 
 static void __init omap_palmte_init(void)
@@ -414,12 +407,15 @@ static void __init omap_palmte_init(void)
        omap_board_config = palmte_config;
        omap_board_config_size = ARRAY_SIZE(palmte_config);
 
-       platform_add_devices(devices, ARRAY_SIZE(devices));
+       platform_add_devices(palmte_devices, ARRAY_SIZE(palmte_devices));
 
        spi_register_board_info(palmte_spi_info, ARRAY_SIZE(palmte_spi_info));
 
+       omap_register_gpio_switches(palmte_switches,
+                       ARRAY_SIZE(palmte_switches));
+
+       palmte_misc_gpio_setup();
        omap_serial_init();
-       palmte_gpio_setup();
 }
 
 static void __init omap_palmte_map_io(void)
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
 
diff --git a/arch/arm/mach-omap1/mmu.c b/arch/arm/mach-omap1/mmu.c
new file mode 100644 (file)
index 0000000..e1e29e0
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * linux/arch/arm/mach-omap2/mmu.c
+ *
+ * Support for non-MPU OMAP1 MMUs.
+ *
+ * Copyright (C) 2002-2005 Nokia Corporation
+ *
+ * Written by Toshihiro Kobayashi <toshihiro.kobayashi@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 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/types.h>
+#include <linux/init.h>
+#include <linux/rwsem.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include "mmu.h"
+#include <asm/tlbflush.h>
+
+static void *dspvect_page;
+#define DSP_INIT_PAGE  0xfff000
+
+#define MMUFAULT_MASK (OMAP_MMU_FAULT_ST_PERM |\
+                      OMAP_MMU_FAULT_ST_TLB_MISS |\
+                      OMAP_MMU_FAULT_ST_TRANS)
+
+static unsigned int get_cam_l_va_mask(u16 pgsz)
+{
+       switch (pgsz) {
+       case OMAP_MMU_CAM_PAGESIZE_1MB:
+               return OMAP_MMU_CAM_L_VA_TAG_L1_MASK |
+                      OMAP_MMU_CAM_L_VA_TAG_L2_MASK_1MB;
+       case OMAP_MMU_CAM_PAGESIZE_64KB:
+               return OMAP_MMU_CAM_L_VA_TAG_L1_MASK |
+                      OMAP_MMU_CAM_L_VA_TAG_L2_MASK_64KB;
+       case OMAP_MMU_CAM_PAGESIZE_4KB:
+               return OMAP_MMU_CAM_L_VA_TAG_L1_MASK |
+                      OMAP_MMU_CAM_L_VA_TAG_L2_MASK_4KB;
+       case OMAP_MMU_CAM_PAGESIZE_1KB:
+               return OMAP_MMU_CAM_L_VA_TAG_L1_MASK |
+                      OMAP_MMU_CAM_L_VA_TAG_L2_MASK_1KB;
+       }
+       return 0;
+}
+
+#define get_cam_va_mask(pgsz) \
+       ((u32)OMAP_MMU_CAM_H_VA_TAG_H_MASK << 22 | \
+        (u32)get_cam_l_va_mask(pgsz) << 6)
+
+static int intmem_usecount;
+
+/* for safety */
+void dsp_mem_usecount_clear(void)
+{
+       if (intmem_usecount != 0) {
+               printk(KERN_WARNING
+                      "MMU: 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();
+       }
+}
+EXPORT_SYMBOL_GPL(dsp_mem_usecount_clear);
+
+static int omap1_mmu_mem_enable(struct omap_mmu *mmu, void *addr)
+{
+       int ret = 0;
+
+       if (omap_mmu_internal_memory(mmu, addr)) {
+               if (intmem_usecount++ == 0)
+                       ret = omap_dsp_request_mem();
+       } else
+               ret = -EIO;
+
+       return ret;
+}
+
+static int omap1_mmu_mem_disable(struct omap_mmu *mmu, void *addr)
+{
+       int ret = 0;
+
+       if (omap_mmu_internal_memory(mmu, addr)) {
+               if (--intmem_usecount == 0)
+                       omap_dsp_release_mem();
+       } else
+               ret = -EIO;
+
+       return ret;
+}
+
+static inline void
+omap1_mmu_read_tlb(struct omap_mmu *mmu, struct cam_ram_regset *cr)
+{
+       /* read a TLB entry */
+       omap_mmu_write_reg(mmu, OMAP_MMU_LD_TLB_RD, OMAP_MMU_LD_TLB);
+
+       cr->cam_h = omap_mmu_read_reg(mmu, OMAP_MMU_READ_CAM_H);
+       cr->cam_l = omap_mmu_read_reg(mmu, OMAP_MMU_READ_CAM_L);
+       cr->ram_h = omap_mmu_read_reg(mmu, OMAP_MMU_READ_RAM_H);
+       cr->ram_l = omap_mmu_read_reg(mmu, OMAP_MMU_READ_RAM_L);
+}
+
+static inline void
+omap1_mmu_load_tlb(struct omap_mmu *mmu, struct cam_ram_regset *cr)
+{
+       /* Set the CAM and RAM entries */
+       omap_mmu_write_reg(mmu, cr->cam_h, OMAP_MMU_CAM_H);
+       omap_mmu_write_reg(mmu, cr->cam_l, OMAP_MMU_CAM_L);
+       omap_mmu_write_reg(mmu, cr->ram_h, OMAP_MMU_RAM_H);
+       omap_mmu_write_reg(mmu, cr->ram_l, OMAP_MMU_RAM_L);
+}
+
+static ssize_t omap1_mmu_show(struct omap_mmu *mmu, char *buf,
+                             struct omap_mmu_tlb_lock *tlb_lock)
+{
+       int i, len;
+
+       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 */
+
+       for (i = 0; i < mmu->nr_tlb_entries; i++) {
+               struct omap_mmu_tlb_entry ent;
+               struct cam_ram_regset cr;
+               struct omap_mmu_tlb_lock entry_lock;
+               char *pgsz_str, *ap_str;
+
+               /* read a TLB entry */
+               entry_lock.base   = tlb_lock->base;
+               entry_lock.victim = i;
+               omap_mmu_read_tlb(mmu, &entry_lock, &cr);
+
+               ent.pgsz  = cr.cam_l & OMAP_MMU_CAM_PAGESIZE_MASK;
+               ent.prsvd = cr.cam_l & OMAP_MMU_CAM_P;
+               ent.valid = cr.cam_l & OMAP_MMU_CAM_V;
+               ent.ap    = cr.ram_l & OMAP_MMU_RAM_L_AP_MASK;
+               ent.va = (u32)(cr.cam_h & OMAP_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 & OMAP_MMU_RAM_L_RAM_LSB_MASK);
+
+               pgsz_str = (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_1MB)  ? " 1MB":
+                          (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_64KB) ? "64KB":
+                          (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_4KB)  ? " 4KB":
+                          (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_1KB)  ? " 1KB":
+                                                                    " ???";
+               ap_str = (ent.ap == OMAP_MMU_RAM_L_AP_RO) ? "RO":
+                        (ent.ap == OMAP_MMU_RAM_L_AP_FA) ? "FA":
+                        (ent.ap == OMAP_MMU_RAM_L_AP_NA) ? "NA":
+                                                          "??";
+
+               if (i == tlb_lock->base)
+                       len += sprintf(buf + len, "lock base = %d\n",
+                                      tlb_lock->base);
+               if (i == tlb_lock->victim)
+                       len += sprintf(buf + len, "victim    = %d\n",
+                                      tlb_lock->victim);
+               len += sprintf(buf + len,
+                              /* 00: P V  4KB 0x300000 0x10171800 FA */
+                              "%02d: %c %c %s 0x%06lx 0x%08lx %s\n",
+                              i,
+                              ent.prsvd ? 'P' : ' ',
+                              ent.valid ? 'V' : ' ',
+                              pgsz_str, ent.va, ent.pa, ap_str);
+       }
+
+       return len;
+}
+
+static int exmap_setup_preserved_entries(struct omap_mmu *mmu)
+{
+       int n = 0;
+
+       exmap_setup_preserved_mem_page(mmu, dspvect_page, DSP_INIT_PAGE, n++);
+
+       return n;
+}
+
+static void exmap_clear_preserved_entries(struct omap_mmu *mmu)
+{
+       exmap_clear_mem_page(mmu, DSP_INIT_PAGE);
+}
+
+static int omap1_mmu_startup(struct omap_mmu *mmu)
+{
+       dspvect_page = (void *)__get_dma_pages(GFP_KERNEL, 0);
+       if (dspvect_page == NULL) {
+               printk(KERN_ERR "MMU: failed to allocate memory "
+                               "for dsp vector table\n");
+               return -ENOMEM;
+       }
+
+       mmu->nr_exmap_preserved = exmap_setup_preserved_entries(mmu);
+
+       return 0;
+}
+
+static void omap1_mmu_shutdown(struct omap_mmu *mmu)
+{
+       exmap_clear_preserved_entries(mmu);
+
+       if (dspvect_page != NULL) {
+               unsigned long virt;
+
+               down_read(&mmu->exmap_sem);
+
+               virt = (unsigned long)omap_mmu_to_virt(mmu, DSP_INIT_PAGE);
+               flush_tlb_kernel_range(virt, virt + PAGE_SIZE);
+               free_page((unsigned long)dspvect_page);
+               dspvect_page = NULL;
+
+               up_read(&mmu->exmap_sem);
+       }
+}
+
+static inline unsigned long omap1_mmu_cam_va(struct cam_ram_regset *cr)
+{
+       unsigned int page_size = cr->cam_l & OMAP_MMU_CAM_PAGESIZE_MASK;
+
+       return (u32)(cr->cam_h & OMAP_MMU_CAM_H_VA_TAG_H_MASK)  << 22 |
+              (u32)(cr->cam_l & get_cam_l_va_mask(page_size)) << 6;
+}
+
+static struct cam_ram_regset *
+omap1_mmu_cam_ram_alloc(struct omap_mmu_tlb_entry *entry)
+{
+       struct cam_ram_regset *cr;
+
+       if (entry->va & ~(get_cam_va_mask(entry->pgsz))) {
+               printk(KERN_ERR "MMU: mapping vadr (0x%06lx) is not on an "
+                      "aligned boundary\n", entry->va);
+               return ERR_PTR(-EINVAL);
+       }
+
+       cr = kmalloc(sizeof(struct cam_ram_regset), GFP_KERNEL);
+
+       cr->cam_h = entry->va >> 22;
+       cr->cam_l = (entry->va >> 6 & get_cam_l_va_mask(entry->pgsz)) |
+                  entry->prsvd | entry->pgsz;
+       cr->ram_h = entry->pa >> 16;
+       cr->ram_l = (entry->pa & OMAP_MMU_RAM_L_RAM_LSB_MASK) | entry->ap;
+
+       return cr;
+}
+
+static inline int omap1_mmu_cam_ram_valid(struct cam_ram_regset *cr)
+{
+       return cr->cam_l & OMAP_MMU_CAM_V;
+}
+
+static void omap1_mmu_interrupt(struct omap_mmu *mmu)
+{
+       unsigned long status;
+       unsigned long adh, adl;
+       unsigned long dp;
+       unsigned long va;
+
+       status = omap_mmu_read_reg(mmu, OMAP_MMU_FAULT_ST);
+       adh = omap_mmu_read_reg(mmu, OMAP_MMU_FAULT_AD_H);
+       adl = omap_mmu_read_reg(mmu, OMAP_MMU_FAULT_AD_L);
+       dp = adh & OMAP_MMU_FAULT_AD_H_DP;
+       va = (((adh & OMAP_MMU_FAULT_AD_H_ADR_MASK) << 16) | adl);
+
+       /* if the fault is masked, nothing to do */
+       if ((status & MMUFAULT_MASK) == 0) {
+               pr_debug( "MMU interrupt, but ignoring.\n");
+               /*
+                * note: in OMAP1710,
+                * when CACHE + DMA domain gets out of idle in DSP,
+                * MMU interrupt occurs but MMU_FAULT_ST is not set.
+                * in this case, we just ignore the interrupt.
+                */
+               if (status) {
+                       pr_debug( "%s%s%s%s\n",
+                                 (status & OMAP_MMU_FAULT_ST_PREF)?
+                                 "  (prefetch err)" : "",
+                                 (status & OMAP_MMU_FAULT_ST_PERM)?
+                                 "  (permission fault)" : "",
+                                 (status & OMAP_MMU_FAULT_ST_TLB_MISS)?
+                                 "  (TLB miss)" : "",
+                                 (status & OMAP_MMU_FAULT_ST_TRANS) ?
+                                 "  (translation fault)": "");
+                       pr_debug( "fault address = %#08lx\n", va);
+               }
+               enable_irq(mmu->irq);
+               return;
+       }
+
+       pr_info("%s%s%s%s\n",
+               (status & OMAP_MMU_FAULT_ST_PREF)?
+               (MMUFAULT_MASK & OMAP_MMU_FAULT_ST_PREF)?
+               "  prefetch err":
+               "  (prefetch err)":
+               "",
+               (status & OMAP_MMU_FAULT_ST_PERM)?
+               (MMUFAULT_MASK & OMAP_MMU_FAULT_ST_PERM)?
+               "  permission fault":
+               "  (permission fault)":
+               "",
+               (status & OMAP_MMU_FAULT_ST_TLB_MISS)?
+               (MMUFAULT_MASK & OMAP_MMU_FAULT_ST_TLB_MISS)?
+               "  TLB miss":
+               "  (TLB miss)":
+               "",
+               (status & OMAP_MMU_FAULT_ST_TRANS)?
+               (MMUFAULT_MASK & OMAP_MMU_FAULT_ST_TRANS)?
+               "  translation fault":
+               "  (translation fault)":
+               "");
+       pr_info("fault address = %#08lx\n", va);
+
+       mmu->fault_address = va;
+       schedule_work(&mmu->irq_work);
+}
+
+struct omap_mmu_ops omap1_mmu_ops = {
+       .startup        = omap1_mmu_startup,
+       .shutdown       = omap1_mmu_shutdown,
+       .mem_enable     = omap1_mmu_mem_enable,
+       .mem_disable    = omap1_mmu_mem_disable,
+       .read_tlb       = omap1_mmu_read_tlb,
+       .load_tlb       = omap1_mmu_load_tlb,
+       .show           = omap1_mmu_show,
+       .cam_va         = omap1_mmu_cam_va,
+       .cam_ram_alloc  = omap1_mmu_cam_ram_alloc,
+       .cam_ram_valid  = omap1_mmu_cam_ram_valid,
+       .interrupt      = omap1_mmu_interrupt,
+};
+EXPORT_SYMBOL_GPL(omap1_mmu_ops);
diff --git a/arch/arm/mach-omap1/mmu.h b/arch/arm/mach-omap1/mmu.h
new file mode 100644 (file)
index 0000000..d86d966
--- /dev/null
@@ -0,0 +1,130 @@
+#ifndef __MACH_OMAP1_MMU_H
+#define __MACH_OMAP1_MMU_H
+
+#include <asm/arch/mmu.h>
+#include <asm/io.h>
+
+#define MMU_LOCK_BASE_MASK             (0x3f << 10)
+#define MMU_LOCK_VICTIM_MASK           (0x3f << 4)
+
+#define OMAP_MMU_BASE                  (0xfffed200)
+#define OMAP_MMU_PREFETCH              (OMAP_MMU_BASE + 0x00)
+#define OMAP_MMU_WALKING_ST            (OMAP_MMU_BASE + 0x04)
+#define OMAP_MMU_CNTL                  (OMAP_MMU_BASE + 0x08)
+#define OMAP_MMU_FAULT_AD_H            (OMAP_MMU_BASE + 0x0c)
+#define OMAP_MMU_FAULT_AD_L            (OMAP_MMU_BASE + 0x10)
+#define OMAP_MMU_FAULT_ST              (OMAP_MMU_BASE + 0x14)
+#define OMAP_MMU_IT_ACK                        (OMAP_MMU_BASE + 0x18)
+#define OMAP_MMU_TTB_H                 (OMAP_MMU_BASE + 0x1c)
+#define OMAP_MMU_TTB_L                 (OMAP_MMU_BASE + 0x20)
+#define OMAP_MMU_LOCK                  (OMAP_MMU_BASE + 0x24)
+#define OMAP_MMU_LD_TLB                        (OMAP_MMU_BASE + 0x28)
+#define OMAP_MMU_CAM_H                 (OMAP_MMU_BASE + 0x2c)
+#define OMAP_MMU_CAM_L                 (OMAP_MMU_BASE + 0x30)
+#define OMAP_MMU_RAM_H                 (OMAP_MMU_BASE + 0x34)
+#define OMAP_MMU_RAM_L                 (OMAP_MMU_BASE + 0x38)
+#define OMAP_MMU_GFLUSH                        (OMAP_MMU_BASE + 0x3c)
+#define OMAP_MMU_FLUSH_ENTRY           (OMAP_MMU_BASE + 0x40)
+#define OMAP_MMU_READ_CAM_H            (OMAP_MMU_BASE + 0x44)
+#define OMAP_MMU_READ_CAM_L            (OMAP_MMU_BASE + 0x48)
+#define OMAP_MMU_READ_RAM_H            (OMAP_MMU_BASE + 0x4c)
+#define OMAP_MMU_READ_RAM_L            (OMAP_MMU_BASE + 0x50)
+
+#define OMAP_MMU_CNTL_BURST_16MNGT_EN  0x0020
+#define OMAP_MMU_CNTL_WTL_EN           0x0004
+#define OMAP_MMU_CNTL_MMU_EN           0x0002
+#define OMAP_MMU_CNTL_RESET_SW         0x0001
+
+#define OMAP_MMU_FAULT_AD_H_DP         0x0100
+#define OMAP_MMU_FAULT_AD_H_ADR_MASK   0x00ff
+
+#define OMAP_MMU_FAULT_ST_PREF         0x0008
+#define OMAP_MMU_FAULT_ST_PERM         0x0004
+#define OMAP_MMU_FAULT_ST_TLB_MISS     0x0002
+#define OMAP_MMU_FAULT_ST_TRANS                0x0001
+
+#define OMAP_MMU_IT_ACK_IT_ACK         0x0001
+
+#define OMAP_MMU_CAM_H_VA_TAG_H_MASK           0x0003
+
+#define OMAP_MMU_CAM_L_VA_TAG_L1_MASK          0xc000
+#define OMAP_MMU_CAM_L_VA_TAG_L2_MASK_1MB      0x0000
+#define OMAP_MMU_CAM_L_VA_TAG_L2_MASK_64KB     0x3c00
+#define OMAP_MMU_CAM_L_VA_TAG_L2_MASK_4KB      0x3fc0
+#define OMAP_MMU_CAM_L_VA_TAG_L2_MASK_1KB      0x3ff0
+#define OMAP_MMU_CAM_L_P                       0x0008
+#define OMAP_MMU_CAM_L_V                       0x0004
+#define OMAP_MMU_CAM_L_PAGESIZE_MASK           0x0003
+#define OMAP_MMU_CAM_L_PAGESIZE_1MB            0x0000
+#define OMAP_MMU_CAM_L_PAGESIZE_64KB           0x0001
+#define OMAP_MMU_CAM_L_PAGESIZE_4KB            0x0002
+#define OMAP_MMU_CAM_L_PAGESIZE_1KB            0x0003
+
+#define OMAP_MMU_CAM_P                 OMAP_MMU_CAM_L_P
+#define OMAP_MMU_CAM_V                 OMAP_MMU_CAM_L_V
+#define OMAP_MMU_CAM_PAGESIZE_MASK     OMAP_MMU_CAM_L_PAGESIZE_MASK
+#define OMAP_MMU_CAM_PAGESIZE_1MB      OMAP_MMU_CAM_L_PAGESIZE_1MB
+#define OMAP_MMU_CAM_PAGESIZE_64KB     OMAP_MMU_CAM_L_PAGESIZE_64KB
+#define OMAP_MMU_CAM_PAGESIZE_4KB      OMAP_MMU_CAM_L_PAGESIZE_4KB
+#define OMAP_MMU_CAM_PAGESIZE_1KB      OMAP_MMU_CAM_L_PAGESIZE_1KB
+#define OMAP_MMU_CAM_PAGESIZE_16MB     -1 /* unused in omap1 */
+
+#define OMAP_MMU_RAM_L_RAM_LSB_MASK    0xfc00
+#define OMAP_MMU_RAM_L_AP_MASK         0x0300
+#define OMAP_MMU_RAM_L_AP_NA           0x0000
+#define OMAP_MMU_RAM_L_AP_RO           0x0200
+#define OMAP_MMU_RAM_L_AP_FA           0x0300
+
+#define OMAP_MMU_LD_TLB_RD             0x0002
+
+#define INIT_TLB_ENTRY(ent,v,p,ps)                     \
+do {                                                   \
+       (ent)->va       = (v);                          \
+       (ent)->pa       = (p);                          \
+       (ent)->pgsz     = (ps);                         \
+       (ent)->prsvd    = 0;                            \
+       (ent)->ap       = OMAP_MMU_RAM_L_AP_FA;         \
+       (ent)->tlb      = 1;                            \
+} while (0)
+
+#define INIT_TLB_ENTRY_4KB_PRESERVED(ent,v,p)          \
+do {                                                   \
+       (ent)->va       = (v);                          \
+       (ent)->pa       = (p);                          \
+       (ent)->pgsz     = OMAP_MMU_CAM_PAGESIZE_4KB;    \
+       (ent)->prsvd    = OMAP_MMU_CAM_P;               \
+       (ent)->ap       = OMAP_MMU_RAM_L_AP_FA;         \
+} while (0)
+
+extern struct omap_mmu_ops omap1_mmu_ops;
+
+struct omap_mmu_tlb_entry {
+       unsigned long va;
+       unsigned long pa;
+       unsigned int pgsz, prsvd, valid;
+
+       u16 ap;
+       unsigned int tlb;
+};
+
+static inline unsigned short
+omap_mmu_read_reg(struct omap_mmu *mmu, unsigned long reg)
+{
+       return __raw_readw(mmu->base + reg);
+}
+
+static inline void omap_mmu_write_reg(struct omap_mmu *mmu,
+                              unsigned short val, unsigned long reg)
+{
+       __raw_writew(val, mmu->base + reg);
+}
+
+int omap_dsp_request_mem(void);
+void omap_dsp_release_mem(void);
+
+static inline void omap_mmu_itack(struct omap_mmu *mmu)
+{
+       omap_mmu_write_reg(mmu, OMAP_MMU_IT_ACK_IT_ACK, OMAP_MMU_IT_ACK);
+}
+
+#endif /* __MACH_OMAP1_MMU_H */
index 39c8045b14536a837068a79e75548786c29968c4..130bafa0a9fcd0154465297f309aa104c6af38af 100644 (file)
@@ -98,7 +98,6 @@ static struct subsys_attribute sleep_while_idle_attr = {
        .store  = omap_pm_sleep_while_idle_store,
 };
 
-extern struct kset power_subsys;
 static void (*omap_sram_idle)(void) = NULL;
 static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL;
 
index 752dd6e75826776757472f166ef45220257ccf91..60bfa75930f58f63857d2dbbfaaae4fc7b735b34 100644 (file)
@@ -22,10 +22,33 @@ config MACH_OMAP_GENERIC
        bool "Generic OMAP board"
        depends on ARCH_OMAP2 && ARCH_OMAP24XX
 
+config MACH_NOKIA_N800
+       bool "Nokia N800"
+       depends on ARCH_OMAP24XX
+
+config MACH_OMAP2_TUSB6010
+       bool
+       depends on ARCH_OMAP2 && ARCH_OMAP2420
+       default y if MACH_NOKIA_N800
+
 config MACH_OMAP_H4
        bool "OMAP 2420 H4 board"
        depends on ARCH_OMAP2 && ARCH_OMAP24XX
        select OMAP_DEBUG_DEVICES
+       select GPIOEXPANDER_OMAP
+
+config MACH_OMAP_H4_TUSB
+       bool "TUSB 6010 EVM board"
+       depends on MACH_OMAP_H4
+       select MACH_OMAP2_TUSB6010
+       help
+         Set this if you've got a TUSB6010 high speed USB board.
+         You may need to consult the schematics for your revisions
+         of the Menelaus and TUSB boards, and make changes to be
+         sure this is set up properly for your board stack.
+
+         Be sure to select OTG mode operation, not host-only or
+         peripheral-only.
 
 config MACH_OMAP_H4_OTG
        bool "Use USB OTG connector, not device connector (S1.10)"
@@ -56,11 +79,3 @@ config MACH_OMAP_2430SDP
        bool "OMAP 2430 SDP board"
        depends on ARCH_OMAP2 && ARCH_OMAP24XX
 
-config MACH_NOKIA_N800
-       bool "Nokia N800"
-       depends on ARCH_OMAP24XX
-
-config MACH_OMAP2_TUSB6010
-       bool
-       depends on ARCH_OMAP2 && ARCH_OMAP2420
-       default y if MACH_NOKIA_N800
\ No newline at end of file
index 7b794b7a85765b36bf846c79d6d19c71c354d867..a777ae003d793aaf0603f43d80b855bff1d6deef 100644 (file)
@@ -11,10 +11,17 @@ obj-$(CONFIG_OMAP_MPU_TIMER)                += timer-gp.o
 # Power Management
 obj-$(CONFIG_PM) += pm.o sleep.o
 
+# DSP
+obj-$(CONFIG_OMAP_MMU_FWK)     += mmu_mach.o
+obj-$(CONFIG_OMAP_MBOX_FWK)    += mailbox_mach.o
+mailbox_mach-objs              := mailbox.o
+mmu_mach-objs                  := mmu.o
+
 # Specific board support
 obj-$(CONFIG_MACH_OMAP_GENERIC)                += board-generic.o
 obj-$(CONFIG_MACH_OMAP_H4)             += board-h4.o
-obj-$(CONFIG_MACH_OMAP_2430SDP)                += board-2430sdp.o
+obj-$(CONFIG_MACH_OMAP_2430SDP)                += board-2430sdp.o \
+                                          board-2430sdp-flash.o
 obj-$(CONFIG_MACH_OMAP_APOLLON)                += board-apollon.o \
                                           board-apollon-keys.o
 obj-$(CONFIG_MACH_NOKIA_N800)          += board-n800.o board-n800-flash.o \
@@ -22,3 +29,6 @@ obj-$(CONFIG_MACH_NOKIA_N800)         += board-n800.o board-n800-flash.o \
                                           board-n800-audio.o board-n800-usb.o \
                                           board-n800-dsp.o board-n800-pm.o
 
+# TUSB 6010 chips
+obj-$(CONFIG_MACH_OMAP2_TUSB6010)      += usb-tusb6010.o
+
diff --git a/arch/arm/mach-omap2/board-2430sdp-flash.c b/arch/arm/mach-omap2/board-2430sdp-flash.c
new file mode 100644 (file)
index 0000000..1e8492a
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * linux/arch/arm/mach-omap2/board-2430sdp-flash.c
+ *
+ * Copyright (C) 2007 MontaVista Software, Inc. <source@mvista.com>
+ * Author: Kevin Hilman
+ *
+ * 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/platform_device.h>
+#include <asm/mach/flash.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/onenand_regs.h>
+
+#include <asm/io.h>
+#include <asm/arch/onenand.h>
+#include <asm/arch/board.h>
+#include <asm/arch/gpmc.h>
+
+#define ONENAND_MAP 0x20000000
+#define GPMC_OFF_CONFIG1_0 0x60
+
+static struct mtd_partition onenand_partitions[] = {
+       {
+               .name           = "(OneNAND)X-Loader",
+               .offset         = 0,
+               .size           = 4*(64*2048),  /* 0-3 blks reserved.
+                                                  Mandated by ROM code */
+               .mask_flags     = MTD_WRITEABLE /* force read-only */
+       },
+       {
+               .name           = "(OneNAND)U-Boot",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           =  2*(64*2048),
+               .mask_flags     = MTD_WRITEABLE /* force read-only */
+       },
+       {
+               .name           = "(OneNAND)U-Boot Environment",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 1*(64*2048),
+       },
+       {
+               .name           = "(OneNAND)Kernel",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 4*(64*2048),
+       },
+       {
+               .name           = "(OneNAND)File System",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct omap_onenand_platform_data sdp_onenand_data = {
+       .parts          = onenand_partitions,
+       .nr_parts       = ARRAY_SIZE(onenand_partitions),
+       .dma_channel    = -1,   /* disable DMA in OMAP OneNAND driver */
+};
+
+static struct platform_device sdp_onenand_device = {
+       .name           = "omap2-onenand",
+       .id             = -1,
+       .dev = {
+               .platform_data = &sdp_onenand_data,
+       },
+};
+
+void __init sdp2430_flash_init(void)
+{
+       unsigned long gpmc_base_add, gpmc_cs_base_add;
+       unsigned char cs=0;
+
+       gpmc_base_add = OMAP243X_GPMC_VIRT;
+       while (cs < GPMC_CS_NUM) {
+               int ret = 0;
+
+               /* Each GPMC set for a single CS is at offset 0x30 */
+               gpmc_cs_base_add =
+                       (gpmc_base_add + GPMC_OFF_CONFIG1_0 + (cs*0x30));
+
+               /* xloader/Uboot would have programmed the oneNAND
+                * base address for us This is a ugly hack. The proper
+                * way of doing this is to pass the setup of u-boot up
+                * to kernel using kernel params - something on the
+                * lines of machineID. Check if oneNAND is
+                * configured */
+               ret = __raw_readl(gpmc_cs_base_add + GPMC_CS_CONFIG7);
+               if ((ret & 0x3F) == (ONENAND_MAP >> 24)) {
+                       /* Found it!! */
+                       break;
+               }
+               cs++;
+       }
+       if (cs >= GPMC_CS_NUM) {
+               printk("OneNAND: Unable to find oneNAND configuration in GPMC "
+                      " - not registering.\n");
+               return;
+       }
+
+       sdp_onenand_data.cs = cs;
+
+       if (platform_device_register(&sdp_onenand_device) < 0) {
+               printk(KERN_ERR "Unable to register OneNAND device\n");
+               return;
+       }
+}
index 7e76fbf19b5d934dcfa76fc938f89eb157e6dd72..ebd26304f755e558123f996de82c044a7f5a8c4e 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc2046.h>
 
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/arch/board.h>
 #include <asm/arch/common.h>
 #include <asm/arch/gpmc.h>
+#include <asm/arch/mcspi.h>
 #include "prcm-regs.h"
 
 #include <asm/io.h>
 
-
 #define        SDP2430_FLASH_CS        0
 #define        SDP2430_SMC91X_CS       5
 
+/* TSC2046 (touchscreen) */
+#define TS_GPIO                 24
+
 static struct mtd_partition sdp2430_partitions[] = {
        /* bootloader (U-Boot, etc) in first sector */
        {
@@ -120,6 +125,31 @@ static struct platform_device *sdp2430_devices[] __initdata = {
        &sdp2430_flash_device,
 };
 
+static struct tsc2046_platform_data tsc2046_config = {
+       .dav_gpio       = TS_GPIO,
+       .gpio_debounce  = 0xa,
+};
+
+static struct omap2_mcspi_device_config tsc2046_mcspi_config = {
+       .turbo_mode     = 0,
+       .single_channel = 0,  /* 0: slave, 1: master */
+};
+
+static struct spi_board_info sdp2430_spi_board_info[] __initdata = {
+       [0] = {
+               /*
+                * TSC2046 operates at a max freqency of 2MHz, so
+                * operate slightly below at 1.5MHz
+                */
+               .modalias        = "tsc2046",
+               .bus_num         = 1,
+               .chip_select     = 0,
+               .max_speed_hz    = 1500000,
+               .controller_data = &tsc2046_mcspi_config,
+               .platform_data   = &tsc2046_config,
+       },
+};
+
 static inline void __init sdp2430_init_smc91x(void)
 {
        int eth_cs;
@@ -193,12 +223,91 @@ static struct omap_board_config_kernel sdp2430_config[] = {
        {OMAP_TAG_UART, &sdp2430_uart_config},
 };
 
+#if    defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
+
+#define OMAP2_I2C_BASE1                0x48070000
+#define OMAP2_I2C_BASE2                0x48072000
+#define OMAP2_I2C_INT1         56
+#define OMAP2_I2C_INT2         57
+
+static u32 omap2_i2c1_clkrate  = 400;
+static u32 omap2_i2c2_clkrate  = 2600;
+
+static struct resource i2c_resources1[] = {
+       {
+               .start  = OMAP2_I2C_BASE1,
+               .end    = OMAP2_I2C_BASE1 + 0x3f,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = OMAP2_I2C_INT1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource i2c_resources2[] = {
+       {
+               .start  = OMAP2_I2C_BASE2,
+               .end    = OMAP2_I2C_BASE2 + 0x3f,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = OMAP2_I2C_INT2,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device omap_i2c_device1 = {
+       .name           = "i2c_omap",
+       .id             = 1,
+       .num_resources  = ARRAY_SIZE(i2c_resources1),
+       .resource       = i2c_resources1,
+       .dev            = {
+               .platform_data  = &omap2_i2c1_clkrate,
+       },
+};
+
+static struct platform_device omap_i2c_device2 = {
+       .name           = "i2c_omap",
+       .id             = 2,
+       .num_resources  = ARRAY_SIZE(i2c_resources2),
+       .resource       = i2c_resources2,
+       .dev            = {
+               .platform_data  = &omap2_i2c2_clkrate,
+       },
+};
+
+static void omap_init_i2c(void)
+{
+       (void) platform_device_register(&omap_i2c_device2);
+       (void) platform_device_register(&omap_i2c_device1);
+}
+
+#else
+
+static void omap_init_i2c(void) {}
+
+#endif
+
+static int __init omap2430_i2c_init(void)
+{
+       omap_init_i2c();
+       return 0;
+}
+
+extern void __init sdp2430_flash_init(void);
+
 static void __init omap_2430sdp_init(void)
 {
        platform_add_devices(sdp2430_devices, ARRAY_SIZE(sdp2430_devices));
        omap_board_config = sdp2430_config;
        omap_board_config_size = ARRAY_SIZE(sdp2430_config);
        omap_serial_init();
+
+       sdp2430_flash_init();
+
+       spi_register_board_info(sdp2430_spi_board_info,
+                               ARRAY_SIZE(sdp2430_spi_board_info));
 }
 
 static void __init omap_2430sdp_map_io(void)
@@ -206,6 +315,8 @@ static void __init omap_2430sdp_map_io(void)
        omap2_map_common_io();
 }
 
+arch_initcall(omap2430_i2c_init);
+
 MACHINE_START(OMAP_2430SDP, "OMAP2430 sdp2430 board")
        /* Maintainer: Syed Khasim - Texas Instruments Inc */
        .phys_io        = 0x48000000,
index 100aea47fa300b7c59c833e0c508eb9fef91a4f3..aa5b65708e7a8fa0ac889073da597860c690e75a 100644 (file)
@@ -265,7 +265,7 @@ static struct platform_device *h4_devices[] __initdata = {
 /* 2420 Sysboot setup (2430 is different) */
 static u32 get_sysboot_value(void)
 {
-       return (omap_readl(OMAP242X_CONTROL_STATUS) & 0xFFF);
+       return (omap_readl(OMAP24XX_CONTROL_STATUS) & 0xFFF);
 }
 
 /* FIXME: This function should be moved to some other file, gpmc.c? */
@@ -476,9 +476,10 @@ static void __init tusb_evm_setup(void)
                 */
                omap_cfg_reg(J15_24XX_GPIO99);
                irq = 99;
-               omap_cfg_reg(AA10_242X_DMAREQ0);
-               omap_cfg_reg(AA6_242X_DMAREQ1);
                dmachan = (1 << 1) | (1 << 0);
+#if !(defined(CONFIG_MTD_OMAP_NOR) || defined(CONFIG_MTD_OMAP_NOR_MODULE))
+               dmachan |= (1 << 5) | (1 << 4) (1 << 3) | (1 << 2);
+#endif
                break;
        }
 
index 9033de58319750ef930ccce93a4dfa9e4fdf051b..2fac0aa9b4cff1aa47b14885ce83396892b8d988 100644 (file)
@@ -127,7 +127,7 @@ static int n800_audio_register_controls(void *pdata, struct snd_card *card)
 
 static struct eac_codec n800_eac_codec = {
        .mclk_src = EAC_MCLK_EXT_2x12288000,
-       .codec_mode = EAC_CODEC_I2S,
+       .codec_mode = EAC_CODEC_I2S_MASTER,
        .codec_conf.i2s.polarity_changed_mode = 0,
        .codec_conf.i2s.sync_delay_enable = 0,
        .default_rate = 48000,
index cb570243dc592ea6b95400fd2188165fb960e8b0..b6da02f8f75864fed2a1f18bb8533e234a7480b0 100644 (file)
@@ -48,7 +48,7 @@ static struct dsp_kfunc_device n800_audio_device = {
 /*
  * dsp peripheral device: TIMER
  */
-static int dsp_timer_probe(struct dsp_kfunc_device *kdev)
+static int dsp_timer_probe(struct dsp_kfunc_device *kdev, int stage)
 {
        char clockname[20];
 
@@ -78,7 +78,7 @@ static int dsp_timer_probe(struct dsp_kfunc_device *kdev)
        return PTR_ERR(kdev->ick);
 }
 
-static int dsp_timer_remove(struct dsp_kfunc_device *kdev)
+static int dsp_timer_remove(struct dsp_kfunc_device *kdev, int stage)
 {
        clk_put(kdev->ick);
        clk_put(kdev->fck);
@@ -90,7 +90,7 @@ static int dsp_timer_enable(struct dsp_kfunc_device *kdev, int stage)
 {
        pr_debug("%s enabled(%d)\n", kdev->name, stage);
 
-       mutex_lock(&kdev->lock);
+       spin_lock(&kdev->lock);
 
        if (kdev->enabled)
                goto out;
@@ -99,7 +99,7 @@ static int dsp_timer_enable(struct dsp_kfunc_device *kdev, int stage)
        clk_enable(kdev->fck);
        clk_enable(kdev->ick);
  out:
-       mutex_unlock(&kdev->lock);
+       spin_unlock(&kdev->lock);
 
        return 0;
 }
@@ -108,7 +108,7 @@ static int dsp_timer_disable(struct dsp_kfunc_device *kdev, int stage)
 {
        pr_debug("%s disabled(%d)\n", kdev->name, stage);
 
-       mutex_lock(&kdev->lock);
+       spin_lock(&kdev->lock);
 
        if (kdev->enabled == 0)
                goto out;
@@ -117,7 +117,7 @@ static int dsp_timer_disable(struct dsp_kfunc_device *kdev, int stage)
        clk_disable(kdev->ick);
        clk_disable(kdev->fck);
  out:
-       mutex_unlock(&kdev->lock);
+       spin_unlock(&kdev->lock);
 
        return 0;
 }
index 122ba5beff55b14ae64c9033684e2aab672a0667..bfd606b5bbf342dba9512c33f0d5cec2e9095a19 100644 (file)
  */
 
 #include <linux/types.h>
-#include <linux/errno.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
 #include <linux/usb/musb.h>
 #include <asm/arch/gpmc.h>
 #include <asm/arch/gpio.h>
+#include <asm/arch/pm.h>
 
 #define TUSB_ASYNC_CS          1
 #define TUSB_SYNC_CS           4
@@ -23,6 +25,7 @@
 #define GPIO_TUSB_ENABLE       0
 
 static int tusb_set_power(int state);
+static int tusb_set_clock(struct clk *osc_ck, int state);
 
 #if    defined(CONFIG_USB_MUSB_OTG)
 #      define BOARD_MODE       MUSB_OTG
@@ -36,7 +39,9 @@ static struct musb_hdrc_platform_data tusb_data = {
        .mode           = BOARD_MODE,
        .multipoint     = 1,
        .set_power      = tusb_set_power,
+       .set_clock      = tusb_set_clock,
        .min_power      = 25,   /* x2 = 50 mA drawn from VBUS as peripheral */
+       .clock          = "osc_ck",
 };
 
 /*
@@ -71,6 +76,29 @@ static int tusb_set_power(int state)
        return retval;
 }
 
+static int             osc_ck_on;
+
+static int tusb_set_clock(struct clk *osc_ck, int state)
+{
+       if (state) {
+               if (osc_ck_on > 0)
+                       return -ENODEV;
+
+               omap2_block_sleep();
+               clk_enable(osc_ck);
+               osc_ck_on = 1;
+       } else {
+               if (osc_ck_on == 0)
+                       return -ENODEV;
+
+               clk_disable(osc_ck);
+               osc_ck_on = 0;
+               omap2_allow_sleep();
+       }
+
+       return 0;
+}
+
 void __init n800_usb_init(void)
 {
        int ret = 0;
index 03065074f8084373852a8e1faff97b2b363656ee..d60d1717f1ff504cc92910b7c3b856fc0f94ec66 100644 (file)
@@ -97,7 +97,7 @@ static void omap2_clk_fixed_enable(struct clk *clk)
 {
        u32 cval, i=0;
 
-       if (clk->enable_bit == 0xff)                    /* Parent will do it */
+       if (clk->enable_bit == PARENT_CONTROLS_CLOCK)   /* Parent will do it */
                return;
 
        cval = CM_CLKEN_PLL;
@@ -205,8 +205,8 @@ static void omap2_clk_fixed_disable(struct clk *clk)
 {
        u32 cval;
 
-       if(clk->enable_bit == 0xff)             /* let parent off do it */
-               return;
+       if (clk->enable_bit == PARENT_CONTROLS_CLOCK)
+               return;         /* let parent off do it */
 
        cval = CM_CLKEN_PLL;
        cval &= ~(0x3 << clk->enable_bit);
@@ -651,7 +651,7 @@ static u32 omap2_get_clksel(u32 *div_sel, u32 *field_mask,
                break;
        case CM_SYSCLKOUT_SEL1:
                div_addr = (u32)&PRCM_CLKOUT_CTRL;
-               if ((div_off == 3) || (div_off = 11))
+               if ((div_off == 3) || (div_off == 11))
                        mask= 0x3;
                break;
        case CM_CORE_SEL1:
index 162978fd535943e7fdffcbdaec41866586955d1e..ba26e16fd5765e9b663c1f2b0cb747806c7cb4d4 100644 (file)
@@ -29,6 +29,8 @@ static void omap2_sys_clk_recalc(struct clk * clk);
 static u32 omap2_clksel_to_divisor(u32 div_sel, u32 field_val);
 static u32 omap2_clksel_get_divisor(struct clk *clk);
 
+/* REVISIT: should use a clock flag for this, not a magic number */
+#define PARENT_CONTROLS_CLOCK  0xff
 
 #define RATE_IN_242X   (1 << 0)
 #define RATE_IN_243X   (1 << 1)
@@ -174,7 +176,7 @@ struct prcm_config {
 #define RII_CLKSEL_DSP                 (3 << 0)        /* c5x - 200MHz */
 #define RII_CLKSEL_DSP_IF              (2 << 5)        /* c5x - 100MHz */
 #define RII_SYNC_DSP                   (0 << 7)        /* Bypass sync */
-#define RII_CLKSEL_IVA                 (6 << 8)        /* iva1 - 200MHz */
+#define RII_CLKSEL_IVA                 (3 << 8)        /* iva1 - 200MHz */
 #define RII_SYNC_IVA                   (0 << 13)       /* Bypass sync */
 #define RII_CM_CLKSEL_DSP_VAL          RII_SYNC_IVA | RII_CLKSEL_IVA | \
                                        RII_SYNC_DSP | RII_CLKSEL_DSP_IF | \
@@ -182,6 +184,27 @@ struct prcm_config {
 #define RII_CLKSEL_GFX                 (2 << 0)        /* 50MHz */
 #define RII_CM_CLKSEL_GFX_VAL          RII_CLKSEL_GFX
 
+/* 2420-PRCM I 660MHz core */
+#define RI_CLKSEL_L3                   (4 << 0)        /* 165MHz */
+#define RI_CLKSEL_L4                   (2 << 5)        /* 82.5MHz */
+#define RI_CLKSEL_USB                  (4 << 25)       /* 41.25MHz */
+#define RI_CM_CLKSEL1_CORE_VAL         RI_CLKSEL_USB | \
+                                       RXX_CLKSEL_SSI | RXX_CLKSEL_VLYNQ | \
+                                       RX_CLKSEL_DSS2 | RX_CLKSEL_DSS1 | \
+                                       RI_CLKSEL_L4 | RI_CLKSEL_L3
+#define RI_CLKSEL_MPU                  (2 << 0)        /* 330MHz */
+#define RI_CM_CLKSEL_MPU_VAL           RI_CLKSEL_MPU
+#define RI_CLKSEL_DSP                  (3 << 0)        /* c5x - 220MHz */
+#define RI_CLKSEL_DSP_IF               (2 << 5)        /* c5x - 110MHz */
+#define RI_SYNC_DSP                    (1 << 7)        /* Activate sync */
+#define RI_CLKSEL_IVA                  (4 << 8)        /* iva1 - 165MHz */
+#define RI_SYNC_IVA                    (0 << 13)       /* Bypass sync */
+#define RI_CM_CLKSEL_DSP_VAL           RI_SYNC_IVA | RI_CLKSEL_IVA | \
+                                       RI_SYNC_DSP | RI_CLKSEL_DSP_IF | \
+                                       RI_CLKSEL_DSP
+#define RI_CLKSEL_GFX                  (1 << 0)        /* 165MHz */
+#define RI_CM_CLKSEL_GFX_VAL           RI_CLKSEL_GFX
+
 /* 2420-PRCM VII (boot) */
 #define RVII_CLKSEL_L3                 (1 << 0)
 #define RVII_CLKSEL_L4                 (1 << 5)
@@ -300,6 +323,13 @@ struct prcm_config {
  * boot (boot)
  */
 
+/* PRCM I target DPLL = 2*330MHz = 660MHz */
+#define MI_DPLL_MULT_12                        (55 << 12)
+#define MI_DPLL_DIV_12                 (1 << 8)
+#define MI_CM_CLKSEL1_PLL_12_VAL       MX_48M_SRC | MX_54M_SRC | \
+                                       MI_DPLL_DIV_12 | MI_DPLL_MULT_12 | \
+                                       MX_APLLS_CLIKIN_12
+
 /*
  * 2420 Equivalent - mode registers
  * PRCM II , target DPLL = 2*300MHz = 600MHz
@@ -352,6 +382,7 @@ struct prcm_config {
  * By having the boot loader boot up in the fastest L4 speed available likely
  * will result in something which you can switch between.
  */
+#define V24XX_SDRC_RFR_CTRL_165MHz     (0x00044c00 | 1)
 #define V24XX_SDRC_RFR_CTRL_133MHz     (0x0003de00 | 1)
 #define V24XX_SDRC_RFR_CTRL_100MHz     (0x0002da01 | 1)
 #define V24XX_SDRC_RFR_CTRL_110MHz     (0x0002da01 | 1) /* Need to calc */
@@ -394,6 +425,13 @@ struct prcm_config {
  * Note: This table needs to be sorted, fastest to slowest.
  *-------------------------------------------------------------------------*/
 static struct prcm_config rate_table[] = {
+       /* PRCM I - FAST */
+       {S12M, S660M, S330M, RI_CM_CLKSEL_MPU_VAL,              /* 330MHz ARM */
+               RI_CM_CLKSEL_DSP_VAL, RI_CM_CLKSEL_GFX_VAL,
+               RI_CM_CLKSEL1_CORE_VAL, MI_CM_CLKSEL1_PLL_12_VAL,
+               MX_CLKSEL2_PLL_2x_VAL, 0, V24XX_SDRC_RFR_CTRL_165MHz,
+               RATE_IN_242X},
+
        /* PRCM II - FAST */
        {S12M, S600M, S300M, RII_CM_CLKSEL_MPU_VAL,             /* 300MHz ARM */
                RII_CM_CLKSEL_DSP_VAL, RII_CM_CLKSEL_GFX_VAL,
@@ -628,7 +666,7 @@ static struct clk func_54m_ck = {
                                RATE_FIXED | CM_PLL_SEL1 | RATE_PROPAGATES,
        .src_offset     = 5,
        .enable_reg     = (void __iomem *)&CM_CLKEN_PLL,
-       .enable_bit     = 0xff,
+       .enable_bit     = PARENT_CONTROLS_CLOCK,
        .recalc         = &omap2_propagate_rate,
 };
 
@@ -655,7 +693,7 @@ static struct clk func_96m_ck = {
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                RATE_FIXED | RATE_PROPAGATES,
        .enable_reg     = (void __iomem *)&CM_CLKEN_PLL,
-       .enable_bit     = 0xff,
+       .enable_bit     = PARENT_CONTROLS_CLOCK,
        .recalc         = &omap2_propagate_rate,
 };
 
@@ -667,7 +705,7 @@ static struct clk func_48m_ck = {
                                RATE_FIXED | CM_PLL_SEL1 | RATE_PROPAGATES,
        .src_offset     = 3,
        .enable_reg     = (void __iomem *)&CM_CLKEN_PLL,
-       .enable_bit     = 0xff,
+       .enable_bit     = PARENT_CONTROLS_CLOCK,
        .recalc         = &omap2_propagate_rate,
 };
 
@@ -679,7 +717,7 @@ static struct clk func_12m_ck = {
                                RATE_FIXED | RATE_PROPAGATES,
        .recalc         = &omap2_propagate_rate,
        .enable_reg     = (void __iomem *)&CM_CLKEN_PLL,
-       .enable_bit     = 0xff,
+       .enable_bit     = PARENT_CONTROLS_CLOCK,
 };
 
 /* Secure timer, only available in secure mode */
@@ -796,7 +834,7 @@ static struct clk dsp_ick = {
        .parent         = &dsp_fck,
        .flags          = CLOCK_IN_OMAP242X | RATE_CKCTL | CM_DSP_SEL1 |
                                DELAYED_APP | CONFIG_PARTICIPANT,
-       .rate_offset = 5,
+       .rate_offset    = 5,
        .enable_reg     = (void __iomem *)&CM_ICLKEN_DSP,
        .enable_bit     = 1,            /* for ipi */
        .recalc         = &omap2_clksel_recalc,
@@ -807,7 +845,7 @@ static struct clk iva1_ifck = {
        .parent         = &core_ck,
        .flags          = CLOCK_IN_OMAP242X | CM_DSP_SEL1 | RATE_CKCTL |
                        CONFIG_PARTICIPANT | RATE_PROPAGATES | DELAYED_APP,
-       .rate_offset= 8,
+       .rate_offset    = 8,
        .enable_reg     = (void __iomem *)&CM_FCLKEN_DSP,
        .enable_bit     = 10,
        .recalc         = &omap2_clksel_recalc,
@@ -861,7 +899,7 @@ static struct clk usb_l4_ick = {    /* FS-USB interface clock */
                                CONFIG_PARTICIPANT,
        .enable_reg     = (void __iomem *)&CM_ICLKEN2_CORE,
        .enable_bit     = 0,
-       .rate_offset = 25,
+       .rate_offset    = 25,
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -880,7 +918,7 @@ static struct clk ssi_ssr_sst_fck = {
                                RATE_CKCTL | CM_CORE_SEL1 | DELAYED_APP,
        .enable_reg     = (void __iomem *)&CM_FCLKEN2_CORE,     /* bit 1 */
        .enable_bit     = 1,
-       .rate_offset = 20,
+       .rate_offset    = 20,
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -902,7 +940,7 @@ static struct clk gfx_3d_fck = {
                                RATE_CKCTL | CM_GFX_SEL1,
        .enable_reg     = (void __iomem *)&CM_FCLKEN_GFX,
        .enable_bit     = 2,
-       .rate_offset= 0,
+       .rate_offset    = 0,
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -913,7 +951,7 @@ static struct clk gfx_2d_fck = {
                                RATE_CKCTL | CM_GFX_SEL1,
        .enable_reg     = (void __iomem *)&CM_FCLKEN_GFX,
        .enable_bit     = 1,
-       .rate_offset= 0,
+       .rate_offset    = 0,
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -1282,8 +1320,8 @@ static struct clk mcbsp1_ick = {
        .name           = "mcbsp1_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_bit     = 15,
        .enable_reg     = (void __iomem *)&CM_ICLKEN1_CORE,      /* bit16 */
+       .enable_bit     = 15,
        .recalc         = &omap2_followparent_recalc,
 };
 
@@ -1291,8 +1329,8 @@ static struct clk mcbsp1_fck = {
        .name           = "mcbsp1_fck",
        .parent         = &func_96m_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_bit     = 15,
        .enable_reg     = (void __iomem *)&CM_FCLKEN1_CORE,
+       .enable_bit     = 15,
        .recalc         = &omap2_followparent_recalc,
 };
 
@@ -1300,8 +1338,8 @@ static struct clk mcbsp2_ick = {
        .name           = "mcbsp2_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_bit     = 16,
        .enable_reg     = (void __iomem *)&CM_ICLKEN1_CORE,
+       .enable_bit     = 16,
        .recalc         = &omap2_followparent_recalc,
 };
 
@@ -1309,8 +1347,8 @@ static struct clk mcbsp2_fck = {
        .name           = "mcbsp2_fck",
        .parent         = &func_96m_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_bit     = 16,
        .enable_reg     = (void __iomem *)&CM_FCLKEN1_CORE,
+       .enable_bit     = 16,
        .recalc         = &omap2_followparent_recalc,
 };
 
@@ -1725,7 +1763,8 @@ static struct clk i2c2_fck = {
 };
 
 static struct clk i2chs2_fck = {
-       .name           = "i2chs2_fck",
+       .name           = "i2chs_fck",
+       .id             = 2,
        .parent         = &func_96m_ck,
        .flags          = CLOCK_IN_OMAP243X,
        .enable_reg     = (void __iomem *)&CM_FCLKEN2_CORE,
@@ -1754,7 +1793,8 @@ static struct clk i2c1_fck = {
 };
 
 static struct clk i2chs1_fck = {
-       .name           = "i2chs1_fck",
+       .name           = "i2chs_fck",
+       .id             = 1,
        .parent         = &func_96m_ck,
        .flags          = CLOCK_IN_OMAP243X,
        .enable_reg     = (void __iomem *)&CM_FCLKEN2_CORE,
index 767140c7db07382155b932dd2823d6992c154e97..f1eb871130cd977805d528f281cf9d07af066c2c 100644 (file)
 #include <asm/arch/gpio.h>
 #include <asm/arch/eac.h>
 
+#if    !defined(CONFIG_ARCH_OMAP243X)
 #if    defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
 
 #define OMAP2_I2C_BASE2                0x48072000
 #define OMAP2_I2C_INT2         57
 
+static u32 omap2_i2c2_clkrate  = 100;
 static struct resource i2c_resources2[] = {
        {
                .start          = OMAP2_I2C_BASE2,
@@ -47,6 +49,9 @@ static struct platform_device omap_i2c_device2 = {
        .id             = 2,
        .num_resources  = ARRAY_SIZE(i2c_resources2),
        .resource       = i2c_resources2,
+       .dev            = {
+               .platform_data  = &omap2_i2c2_clkrate,
+       },
 };
 
 /* See also arch/arm/plat-omap/devices.c for first I2C on 24xx */
@@ -56,10 +61,9 @@ static void omap_init_i2c(void)
        if (machine_is_omap_h4())
                return;
 
-       if (!cpu_is_omap2430()) {
-               omap_cfg_reg(J15_24XX_I2C2_SCL);
-               omap_cfg_reg(H19_24XX_I2C2_SDA);
-       }
+       omap_cfg_reg(J15_24XX_I2C2_SCL);
+       omap_cfg_reg(H19_24XX_I2C2_SDA);
+
        (void) platform_device_register(&omap_i2c_device2);
 }
 
@@ -67,6 +71,7 @@ static void omap_init_i2c(void)
 
 static void omap_init_i2c(void) {}
 
+#endif
 #endif
 
 #if defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
@@ -241,7 +246,9 @@ static int __init omap2_init_devices(void)
        /* please keep these calls, and their implementations above,
         * in alphabetical order so they're easier to sort through.
         */
-       omap_init_i2c();
+       if (!cpu_is_omap2430()) {
+               omap_init_i2c();
+       }
        omap_init_mbox();
        omap_init_mcspi();
        omap_init_sti();
index b6b47f2a4ae307e85d050fc25f1b264087f94b25..7384cce3990894037d97b8707320809f8085d3d6 100644 (file)
@@ -51,7 +51,6 @@
 #define GPMC_CS0               0x60
 #define GPMC_CS_SIZE           0x30
 
-#define GPMC_CS_NUM            8
 #define GPMC_MEM_START         0x00000000
 #define GPMC_MEM_END           0x3FFFFFFF
 #define BOOT_ROM_SPACE         0x100000        /* 1MB */
index 2769171147bcfbe1edb51ad51d60742ba2548fb0..4f648c370f20309aada764eb91976b4cefb8c0b9 100644 (file)
@@ -4,7 +4,7 @@
  * OMAP2 I/O mapping code
  *
  * Copyright (C) 2005 Nokia Corporation
- * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ * Author: Juha Yrjola<juha.yrjola@nokia.com>
  * Updated map desc to add 2430 support : <x0khasim@ti.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -42,6 +42,12 @@ static struct map_desc omap2_io_desc[] __initdata = {
                .length         = L3_24XX_SIZE,
                .type           = MT_DEVICE
        },
+       {
+               .virtual        = L4_24XX_VIRT,
+               .pfn            = __phys_to_pfn(L4_24XX_PHYS),
+               .length         = L4_24XX_SIZE,
+               .type           = MT_DEVICE
+       },
 #ifdef CONFIG_ARCH_OMAP2430
        {
                .virtual        = L4_WK_243X_VIRT,
@@ -74,18 +80,20 @@ static struct map_desc omap2_io_desc[] __initdata = {
                .length         = DSP_MEM_24XX_SIZE,
                .type           = MT_DEVICE
        },
+#ifdef CONFIG_ARCH_OMAP2420
        {
                .virtual        = DSP_IPI_24XX_VIRT,
                .pfn            = __phys_to_pfn(DSP_IPI_24XX_PHYS),
                .length         = DSP_IPI_24XX_SIZE,
                .type           = MT_DEVICE
        },
+#endif
        {
                .virtual        = DSP_MMU_24XX_VIRT,
                .pfn            = __phys_to_pfn(DSP_MMU_24XX_PHYS),
                .length         = DSP_MMU_24XX_SIZE,
                .type           = MT_DEVICE
-       }
+       },
 };
 
 void __init omap2_map_common_io(void)
diff --git a/arch/arm/mach-omap2/mmu.c b/arch/arm/mach-omap2/mmu.c
new file mode 100644 (file)
index 0000000..2a52907
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * linux/arch/arm/mach-omap2/mmu.c
+ *
+ * Support for non-MPU OMAP2 MMUs.
+ *
+ * Copyright (C) 2002-2007 Nokia Corporation
+ *
+ * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *        and Paul Mundt <paul.mundt@nokia.com>
+ *
+ * TWL support: Hiroshi DOYU <Hiroshi.DOYU@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/types.h>
+#include <linux/init.h>
+#include <linux/rwsem.h>
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include "mmu.h"
+#include <asm/arch/mmu.h>
+#include <asm/tlbflush.h>
+#include <asm/io.h>
+#include <asm/sizes.h>
+
+static void *dspvect_page;
+#define DSP_INIT_PAGE  0xfff000
+
+static inline void
+omap2_mmu_read_tlb(struct omap_mmu *mmu, struct cam_ram_regset *cr)
+{
+       cr->cam = omap_mmu_read_reg(mmu, MMU_READ_CAM);
+       cr->ram = omap_mmu_read_reg(mmu, MMU_READ_RAM);
+}
+
+static inline void
+omap2_mmu_load_tlb(struct omap_mmu *mmu, struct cam_ram_regset *cr)
+{
+       /* Set the CAM and RAM entries */
+       omap_mmu_write_reg(mmu, cr->cam | OMAP_MMU_CAM_V, MMU_CAM);
+       omap_mmu_write_reg(mmu, cr->ram, MMU_RAM);
+}
+
+static void exmap_setup_iomap_page(struct omap_mmu *mmu, unsigned long phys,
+                                  unsigned long dsp_io_adr, int index)
+{
+       unsigned long dspadr;
+       void *virt;
+       struct omap_mmu_tlb_entry tlb_ent;
+
+       dspadr = (IOMAP_VAL << 18) + (dsp_io_adr << 1);
+       virt = omap_mmu_to_virt(mmu, dspadr);
+       exmap_set_armmmu((unsigned long)virt, phys, PAGE_SIZE);
+       INIT_EXMAP_TBL_ENTRY_4KB_PRESERVED(mmu->exmap_tbl + index, NULL, virt);
+       INIT_TLB_ENTRY_4KB_ES32_PRESERVED(&tlb_ent, dspadr, phys);
+       omap_mmu_load_pte_entry(mmu, &tlb_ent);
+}
+
+static void exmap_clear_iomap_page(struct omap_mmu *mmu,
+                                  unsigned long dsp_io_adr)
+{
+       unsigned long dspadr;
+       void *virt;
+
+       dspadr = (IOMAP_VAL << 18) + (dsp_io_adr << 1);
+       virt = omap_mmu_to_virt(mmu, dspadr);
+       exmap_clear_armmmu((unsigned long)virt, PAGE_SIZE);
+       /* DSP MMU is shutting down. not handled here. */
+}
+
+#define OMAP24XX_MAILBOX_BASE  (L4_24XX_BASE + 0x94000)
+#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)
+#define OMAP24XX_STI_BASE      (L4_24XX_BASE + 0x68000)
+#define OMAP24XX_STI_CH_BASE   (L4_24XX_BASE + 0x0c000000)
+
+static int exmap_setup_preserved_entries(struct omap_mmu *mmu)
+{
+       int i, n = 0;
+
+       exmap_setup_preserved_mem_page(mmu, dspvect_page, DSP_INIT_PAGE, n++);
+
+       exmap_setup_iomap_page(mmu, OMAP24XX_PRCM_BASE, 0x7000, n++);
+       exmap_setup_iomap_page(mmu, OMAP24XX_MAILBOX_BASE, 0x11000, n++);
+
+       if (cpu_is_omap2420()) {
+               exmap_setup_iomap_page(mmu, OMAP2420_GPT5_BASE, 0xe000, n++);
+               exmap_setup_iomap_page(mmu, OMAP2420_GPT6_BASE, 0xe800, n++);
+               exmap_setup_iomap_page(mmu, OMAP2420_GPT7_BASE, 0xf000, n++);
+               exmap_setup_iomap_page(mmu, OMAP2420_GPT8_BASE, 0xf800, n++);
+               exmap_setup_iomap_page(mmu, OMAP24XX_EAC_BASE,  0x10000, n++);
+               exmap_setup_iomap_page(mmu, OMAP24XX_STI_BASE, 0xc800, n++);
+               for (i = 0; i < 5; i++)
+                       exmap_setup_preserved_mem_page(mmu,
+                               __va(OMAP24XX_STI_CH_BASE + i*SZ_4K),
+                               0xfb0000 + i*SZ_4K, n++);
+       }
+
+       return n;
+}
+
+static void exmap_clear_preserved_entries(struct omap_mmu *mmu)
+{
+       int i;
+
+       exmap_clear_iomap_page(mmu, 0x7000);    /* PRCM registers */
+       exmap_clear_iomap_page(mmu, 0x11000);   /* MAILBOX registers */
+
+       if (cpu_is_omap2420()) {
+               exmap_clear_iomap_page(mmu, 0xe000);    /* GPT5 */
+               exmap_clear_iomap_page(mmu, 0xe800);    /* GPT6 */
+               exmap_clear_iomap_page(mmu, 0xf000);    /* GPT7 */
+               exmap_clear_iomap_page(mmu, 0xf800);    /* GPT8 */
+               exmap_clear_iomap_page(mmu, 0x10000);   /* EAC */
+               exmap_clear_iomap_page(mmu, 0xc800);    /* STI */
+               for (i = 0; i < 5; i++)                 /* STI CH */
+                       exmap_clear_mem_page(mmu, 0xfb0000 + i*SZ_4K);
+       }
+
+       exmap_clear_mem_page(mmu, DSP_INIT_PAGE);
+}
+
+#define MMU_IRQ_MASK \
+       (OMAP_MMU_IRQ_MULTIHITFAULT | \
+        OMAP_MMU_IRQ_TABLEWALKFAULT | \
+        OMAP_MMU_IRQ_EMUMISS | \
+        OMAP_MMU_IRQ_TRANSLATIONFAULT)
+
+static int omap2_mmu_startup(struct omap_mmu *mmu)
+{
+       dspvect_page = (void *)__get_dma_pages(GFP_KERNEL, 0);
+       if (dspvect_page == NULL) {
+               printk(KERN_ERR "MMU: failed to allocate memory "
+                               "for dsp vector table\n");
+               return -ENOMEM;
+       }
+
+       mmu->nr_exmap_preserved = exmap_setup_preserved_entries(mmu);
+
+       omap_mmu_write_reg(mmu, MMU_IRQ_MASK, MMU_IRQENABLE);
+
+       return 0;
+}
+
+static void omap2_mmu_shutdown(struct omap_mmu *mmu)
+{
+       exmap_clear_preserved_entries(mmu);
+
+       if (dspvect_page != NULL) {
+               unsigned long virt;
+
+               down_read(&mmu->exmap_sem);
+
+               virt = (unsigned long)omap_mmu_to_virt(mmu, DSP_INIT_PAGE);
+               flush_tlb_kernel_range(virt, virt + PAGE_SIZE);
+               free_page((unsigned long)dspvect_page);
+               dspvect_page = NULL;
+
+               up_read(&mmu->exmap_sem);
+       }
+}
+
+static ssize_t omap2_mmu_show(struct omap_mmu *mmu, char *buf,
+                             struct omap_mmu_tlb_lock *tlb_lock)
+{
+       int i, len;
+
+       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 */
+
+       for (i = 0; i < mmu->nr_tlb_entries; i++) {
+               struct omap_mmu_tlb_entry ent;
+               struct cam_ram_regset cr;
+               struct omap_mmu_tlb_lock entry_lock;
+               char *pgsz_str, *elsz_str;
+
+               /* read a TLB entry */
+               entry_lock.base   = tlb_lock->base;
+               entry_lock.victim = i;
+               omap_mmu_read_tlb(mmu, &entry_lock, &cr);
+
+               ent.pgsz   = cr.cam & OMAP_MMU_CAM_PAGESIZE_MASK;
+               ent.prsvd  = cr.cam & OMAP_MMU_CAM_P;
+               ent.valid  = cr.cam & OMAP_MMU_CAM_V;
+               ent.va     = cr.cam & OMAP_MMU_CAM_VATAG_MASK;
+               ent.endian = cr.ram & OMAP_MMU_RAM_ENDIANNESS;
+               ent.elsz   = cr.ram & OMAP_MMU_RAM_ELEMENTSIZE_MASK;
+               ent.pa     = cr.ram & OMAP_MMU_RAM_PADDR_MASK;
+               ent.mixed  = cr.ram & OMAP_MMU_RAM_MIXED;
+
+               pgsz_str = (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_16MB) ? "64MB":
+                          (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_1MB)  ? " 1MB":
+                          (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_64KB) ? "64KB":
+                          (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_4KB)  ? " 4KB":
+                                                                    " ???";
+               elsz_str = (ent.elsz == OMAP_MMU_RAM_ELEMENTSIZE_8)  ? " 8":
+                          (ent.elsz == OMAP_MMU_RAM_ELEMENTSIZE_16) ? "16":
+                          (ent.elsz == OMAP_MMU_RAM_ELEMENTSIZE_32) ? "32":
+                                                                     "??";
+
+               if (i == tlb_lock->base)
+                       len += sprintf(buf + len, "lock base = %d\n",
+                                      tlb_lock->base);
+               if (i == tlb_lock->victim)
+                       len += sprintf(buf + len, "victim    = %d\n",
+                                      tlb_lock->victim);
+
+               len += sprintf(buf + len,
+                              /* 00: P V  4KB 0x300000 0x10171800 B 16 M */
+                              "%02d: %c %c %s 0x%06lx 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' : ' ');
+       }
+
+       return len;
+}
+
+#define get_cam_va_mask(pgsz) \
+       (((pgsz) == OMAP_MMU_CAM_PAGESIZE_16MB) ? 0xff000000 : \
+        ((pgsz) == OMAP_MMU_CAM_PAGESIZE_1MB)  ? 0xfff00000 : \
+        ((pgsz) == OMAP_MMU_CAM_PAGESIZE_64KB) ? 0xffff0000 : \
+        ((pgsz) == OMAP_MMU_CAM_PAGESIZE_4KB)  ? 0xfffff000 : 0)
+
+static inline unsigned long omap2_mmu_cam_va(struct cam_ram_regset *cr)
+{
+       unsigned int page_size = cr->cam & OMAP_MMU_CAM_PAGESIZE_MASK;
+       unsigned int mask = get_cam_va_mask(cr->cam & page_size);
+
+       return cr->cam & mask;
+}
+
+static struct cam_ram_regset *
+omap2_mmu_cam_ram_alloc(struct omap_mmu_tlb_entry *entry)
+{
+       struct cam_ram_regset *cr;
+
+       if (entry->va & ~(get_cam_va_mask(entry->pgsz))) {
+               printk(KERN_ERR "MMU: mapping vadr (0x%06lx) is not on an "
+                      "aligned boundary\n", entry->va);
+               return ERR_PTR(-EINVAL);
+       }
+
+       cr = kmalloc(sizeof(struct cam_ram_regset), GFP_KERNEL);
+
+       cr->cam = (entry->va & OMAP_MMU_CAM_VATAG_MASK) |
+                 entry->prsvd | entry->pgsz;
+       cr->ram = entry->pa | entry->endian | entry->elsz;
+
+       return cr;
+}
+
+static inline int omap2_mmu_cam_ram_valid(struct cam_ram_regset *cr)
+{
+       return cr->cam & OMAP_MMU_CAM_V;
+}
+
+static void omap2_mmu_interrupt(struct omap_mmu *mmu)
+{
+       unsigned long status, va;
+
+       status = MMU_IRQ_MASK & omap_mmu_read_reg(mmu, MMU_IRQSTATUS);
+       va = omap_mmu_read_reg(mmu, MMU_FAULT_AD);
+
+       pr_info("%s\n", (status & OMAP_MMU_IRQ_MULTIHITFAULT)           ? "multi hit":"");
+       pr_info("%s\n", (status & OMAP_MMU_IRQ_TABLEWALKFAULT)          ? "table walk fault":"");
+       pr_info("%s\n", (status & OMAP_MMU_IRQ_EMUMISS)                 ? "EMU miss":"");
+       pr_info("%s\n", (status & OMAP_MMU_IRQ_TRANSLATIONFAULT)        ? "translation fault":"");
+       pr_info("%s\n", (status & OMAP_MMU_IRQ_TLBMISS)                 ? "TLB miss":"");
+       pr_info("fault address = %#08lx\n", va);
+
+       omap_mmu_disable(mmu);
+       omap_mmu_write_reg(mmu, status, MMU_IRQSTATUS);
+
+       mmu->fault_address = va;
+       schedule_work(&mmu->irq_work);
+}
+
+static pgprot_t omap2_mmu_pte_get_attr(struct omap_mmu_tlb_entry *entry)
+{
+       u32 attr;
+
+       attr = entry->mixed << 5;
+       attr |= entry->endian;
+       attr |= entry->elsz >> 3;
+       attr <<= ((entry->pgsz & OMAP_MMU_CAM_PAGESIZE_4KB) ? 0:6);
+
+       return attr;
+}
+
+struct omap_mmu_ops omap2_mmu_ops = {
+       .startup        = omap2_mmu_startup,
+       .shutdown       = omap2_mmu_shutdown,
+       .read_tlb       = omap2_mmu_read_tlb,
+       .load_tlb       = omap2_mmu_load_tlb,
+       .show           = omap2_mmu_show,
+       .cam_va         = omap2_mmu_cam_va,
+       .cam_ram_alloc  = omap2_mmu_cam_ram_alloc,
+       .cam_ram_valid  = omap2_mmu_cam_ram_valid,
+       .interrupt      = omap2_mmu_interrupt,
+       .pte_get_attr   = omap2_mmu_pte_get_attr,
+};
+EXPORT_SYMBOL_GPL(omap2_mmu_ops);
+
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-omap2/mmu.h b/arch/arm/mach-omap2/mmu.h
new file mode 100644 (file)
index 0000000..cbc82af
--- /dev/null
@@ -0,0 +1,101 @@
+#ifndef __MACH_OMAP2_MMU_H
+#define __MACH_OMAP2_MMU_H
+
+#include "prcm-regs.h"
+#include <asm/arch/mmu.h>
+#include <asm/io.h>
+
+#define MMU_LOCK_BASE_MASK             (0x1f << 10)
+#define MMU_LOCK_VICTIM_MASK           (0x1f << 4)
+
+#define OMAP_MMU_IRQ_MULTIHITFAULT     0x00000010
+#define OMAP_MMU_IRQ_TABLEWALKFAULT    0x00000008
+#define OMAP_MMU_IRQ_EMUMISS           0x00000004
+#define OMAP_MMU_IRQ_TRANSLATIONFAULT  0x00000002
+#define OMAP_MMU_IRQ_TLBMISS           0x00000001
+
+#define OMAP_MMU_CAM_VATAG_MASK                0xfffff000
+#define OMAP_MMU_CAM_P                 0x00000008
+#define OMAP_MMU_CAM_V                 0x00000004
+#define OMAP_MMU_CAM_PAGESIZE_MASK     0x00000003
+#define OMAP_MMU_CAM_PAGESIZE_1MB      0x00000000
+#define OMAP_MMU_CAM_PAGESIZE_64KB     0x00000001
+#define OMAP_MMU_CAM_PAGESIZE_4KB      0x00000002
+#define OMAP_MMU_CAM_PAGESIZE_16MB     0x00000003
+
+#define OMAP_MMU_RAM_PADDR_MASK                0xfffff000
+#define OMAP_MMU_RAM_ENDIANNESS                0x00000200
+#define OMAP_MMU_RAM_ENDIANNESS_BIG    0x00000200
+#define OMAP_MMU_RAM_ENDIANNESS_LITTLE 0x00000000
+#define OMAP_MMU_RAM_ELEMENTSIZE_MASK  0x00000180
+#define OMAP_MMU_RAM_ELEMENTSIZE_8     0x00000000
+#define OMAP_MMU_RAM_ELEMENTSIZE_16    0x00000080
+#define OMAP_MMU_RAM_ELEMENTSIZE_32    0x00000100
+#define OMAP_MMU_RAM_ELEMENTSIZE_NONE  0x00000180
+#define OMAP_MMU_RAM_MIXED             0x00000040
+
+#define IOMAP_VAL      0x3f
+
+#define omap_dsp_request_mem() do { } while (0)
+#define omap_dsp_release_mem() do { } while (0)
+
+#define INIT_TLB_ENTRY(ent,v,p,ps)                             \
+do {                                                           \
+       (ent)->va       = (v);                                  \
+       (ent)->pa       = (p);                                  \
+       (ent)->pgsz     = (ps);                                 \
+       (ent)->prsvd    = 0;                                    \
+       (ent)->endian   = OMAP_MMU_RAM_ENDIANNESS_LITTLE;       \
+       (ent)->elsz     = OMAP_MMU_RAM_ELEMENTSIZE_16;          \
+       (ent)->mixed    = 0;                                    \
+       (ent)->tlb      = 1;                                    \
+} while (0)
+
+#define INIT_TLB_ENTRY_4KB_PRESERVED(ent,v,p) \
+do {                                                           \
+       (ent)->va       = (v);                                  \
+       (ent)->pa       = (p);                                  \
+       (ent)->pgsz     = OMAP_MMU_CAM_PAGESIZE_4KB;            \
+       (ent)->prsvd    = OMAP_MMU_CAM_P;                       \
+       (ent)->endian   = OMAP_MMU_RAM_ENDIANNESS_LITTLE;       \
+       (ent)->elsz     = OMAP_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     = OMAP_MMU_CAM_PAGESIZE_4KB;            \
+       (ent)->prsvd    = OMAP_MMU_CAM_P;                       \
+       (ent)->endian   = OMAP_MMU_RAM_ENDIANNESS_LITTLE;       \
+       (ent)->elsz     = OMAP_MMU_RAM_ELEMENTSIZE_32;          \
+       (ent)->mixed    = 0;                                    \
+} while (0)
+
+extern struct omap_mmu_ops omap2_mmu_ops;
+
+struct omap_mmu_tlb_entry {
+       unsigned long va;
+       unsigned long pa;
+       unsigned int pgsz, prsvd, valid;
+
+       u32 endian, elsz, mixed;
+       unsigned int tlb;
+};
+
+static inline unsigned long
+omap_mmu_read_reg(struct omap_mmu *mmu, unsigned long reg)
+{
+       return __raw_readl(mmu->base + reg);
+}
+
+static inline void omap_mmu_write_reg(struct omap_mmu *mmu,
+                              unsigned long val, unsigned long reg)
+{
+       __raw_writel(val, mmu->base + reg);
+}
+static inline void omap_mmu_itack(struct omap_mmu *mmu)
+{
+}
+#endif /* __MACH_OMAP2_MMU_H */
index 8c39a464e2534ca170445fcfca681b74da4a18bd..4a8e99be69876a1b321f33a357b2a6c01e71a5ba 100644 (file)
@@ -44,6 +44,7 @@
 #include <asm/arch/mux.h>
 #include <asm/arch/dma.h>
 #include <asm/arch/board.h>
+#include <asm/arch/gpio.h>
 
 #define PRCM_REVISION          0x000
 #define PRCM_SYSCONFIG         0x010
@@ -406,12 +407,12 @@ static inline void serial_console_fclk_mask(u32 *f1, u32 *f2) {}
 
 static unsigned short enable_dyn_sleep = 0; /* disabled till drivers are fixed */
 
-static ssize_t omap_pm_sleep_while_idle_show(struct subsystem * subsys, char *buf)
+static ssize_t omap_pm_sleep_while_idle_show(struct kset * subsys, char *buf)
 {
        return sprintf(buf, "%hu\n", enable_dyn_sleep);
 }
 
-static ssize_t omap_pm_sleep_while_idle_store(struct subsystem * subsys,
+static ssize_t omap_pm_sleep_while_idle_store(struct kset * subsys,
                                              const char * buf,
                                              size_t n)
 {
index 5e1c4b53ee9de1af966f138f77758b132c46bd8d..941ef6321ab94bbe10608a81317d2a18d45fd9b6 100644 (file)
 #define GPIO3_SYSCONFIG                __REG32((GPIOX_BASE(3) + 0x10))
 #define GPIO4_SYSCONFIG                __REG32((GPIOX_BASE(4) + 0x10))
 
-#if defined(CONFIG_ARCH_OMAP243X)
+#if defined(CONFIG_ARCH_OMAP2430)
 #define GPIO5_SYSCONFIG                __REG32((OMAP24XX_GPIO5_BASE + 0x10))
 #endif
 
 #define GPIO4_DEBOUNCENABLE    GPIO4_REG32(0x050)
 #define GPIO4_DEBOUNCINGTIME   GPIO4_REG32(0x054)
 
-#if defined(CONFIG_ARCH_OMAP243X)
+#if defined(CONFIG_ARCH_OMAP2430)
 /* GPIO 5 */
 #define GPIO5_REG32(offset)    __REG32((OMAP24XX_GPIO5_BASE + (offset)))
 #define GPIO5_IRQENABLE1       GPIO5_REG32(0x01C)
index c1f7e5a819a3fdac417a4100902ed68fa4786090..69639c48963474c96f9bb37a11d4e23e6306944e 100644 (file)
@@ -42,6 +42,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
@@ -68,6 +101,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
@@ -76,6 +120,22 @@ config OMAP_MCBSP
          Say Y here if you want support for the OMAP Multichannel
          Buffered Serial Port.
 
+config OMAP_MMU_FWK
+       tristate "MMU framework support"
+       depends on ARCH_OMAP
+       default n
+       help
+         Say Y here if you want to use OMAP MMU framework support for
+         DSP, IVA1.0 and Camera in OMAP1/2.
+
+config OMAP_MBOX_FWK
+       tristate "Mailbox framework support"
+       depends on ARCH_OMAP
+       default n
+       help
+         Say Y here if you want to use OMAP Mailbox framework support for
+         DSP and IVA1.0 in OMAP1/2.
+
 choice
         prompt "System timer"
        default OMAP_MPU_TIMER
@@ -90,6 +150,8 @@ config OMAP_MPU_TIMER
 config OMAP_32K_TIMER
        bool "Use 32KHz timer"
        depends on ARCH_OMAP16XX || ARCH_OMAP24XX
+       select GENERIC_TIME
+       select GENERIC_CLOCKEVENTS
        help
          Select this option if you want to enable the OMAP 32KHz timer.
          This timer saves power compared to the OMAP_MPU_TIMER, and has
@@ -139,6 +201,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 d55ca99ae03459f0b631976bb1441272276bd600..282ea007013aea051debf1e6c859f80aec461e8c 100644 (file)
@@ -14,12 +14,25 @@ obj-$(CONFIG_OMAP_32K_TIMER)        += timer32k.o
 # OCPI interconnect support for 1710, 1610 and 5912
 obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
 
+obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
+
+# STI support
+obj-$(CONFIG_OMAP_STI) += sti/
 
 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
 
+# OMAP MMU framework
+obj-$(CONFIG_OMAP_MMU_FWK) += mmu.o
+
+# OMAP mailbox framework
+obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox.o
+
 # DSP subsystem
 obj-y += dsp/
 obj-$(CONFIG_OMAP_DSP) += mailbox.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 0a603242f36712e1060542f6c14c97efd3100a76..cbcc8fe30efadcd75606361792c8a02d82ffa4a5 100644 (file)
@@ -396,3 +396,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 dd8708ad0a71833339c5e3abc23cf4711604275c..1e106d18b184c37f85cd2b2dbd2e2de87008eee2 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;
@@ -171,8 +191,10 @@ console_initcall(omap_add_serial_console);
 
 #if defined(CONFIG_ARCH_OMAP16XX)
 #define TIMER_32K_SYNCHRONIZED         0xfffbc410
-#elif defined(CONFIG_ARCH_OMAP24XX)
+#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
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 c5dab1d6417e113aeae93658b45a5d5730cdebb1..f8a341bdb9d624fc2cea026a2dbad3af9f87d4a6 100644 (file)
@@ -74,7 +74,7 @@ int dsp_kfunc_device_register(struct dsp_kfunc_device *kdev)
 {
        static DEFINE_MUTEX(dsp_pdata_lock);
 
-       mutex_init(&kdev->lock);
+       spin_lock_init(&kdev->lock);
 
        mutex_lock(&dsp_pdata_lock);
        list_add_tail(&kdev->entry, &dsp_pdata.kdev_list);
@@ -89,6 +89,7 @@ static inline void omap_init_dsp(void) { }
 #endif /* CONFIG_OMAP_DSP */
 
 /*-------------------------------------------------------------------------*/
+#if    !defined(CONFIG_ARCH_OMAP243X)
 #if    defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
 
 #define        OMAP1_I2C_BASE          0xfffb3800
@@ -97,6 +98,8 @@ static inline void omap_init_dsp(void) { }
 #define OMAP1_I2C_INT          INT_I2C
 #define OMAP2_I2C_INT1         56
 
+static u32 omap2_i2c1_clkrate  = 100;
+
 static struct resource i2c_resources1[] = {
        {
                .start          = 0,
@@ -116,12 +119,15 @@ static struct platform_device omap_i2c_device1 = {
        .id             = 1,
        .num_resources  = ARRAY_SIZE(i2c_resources1),
        .resource       = i2c_resources1,
+       .dev            = {
+               .platform_data  = &omap2_i2c1_clkrate,
+       },
 };
 
 /* See also arch/arm/mach-omap2/devices.c for second I2C on 24xx */
 static void omap_init_i2c(void)
 {
-       if (cpu_is_omap24xx()) {
+       if (cpu_is_omap242x()) {
                i2c_resources1[0].start = OMAP2_I2C_BASE1;
                i2c_resources1[0].end = OMAP2_I2C_BASE1 + OMAP_I2C_SIZE;
                i2c_resources1[1].start = OMAP2_I2C_INT1;
@@ -136,8 +142,10 @@ static void omap_init_i2c(void)
         * it can include clocking and address info, maybe more.
         */
        if (cpu_is_omap24xx()) {
-               omap_cfg_reg(M19_24XX_I2C1_SCL);
-               omap_cfg_reg(L15_24XX_I2C1_SDA);
+               if (machine_is_omap_h4()) {
+                       omap_cfg_reg(M19_24XX_I2C1_SCL);
+                       omap_cfg_reg(L15_24XX_I2C1_SDA);
+               }
        } else {
                omap_cfg_reg(I2C_SCL);
                omap_cfg_reg(I2C_SDA);
@@ -149,12 +157,16 @@ static void omap_init_i2c(void)
 #else
 static inline void omap_init_i2c(void) {}
 #endif
-
+#endif
 /*-------------------------------------------------------------------------*/
 #if    defined(CONFIG_KEYBOARD_OMAP) || defined(CONFIG_KEYBOARD_OMAP_MODULE)
 
 static void omap_init_kp(void)
 {
+       /* REVISIT: 2430 keypad is on TWL4030 */
+       if (cpu_is_omap2430())
+               return;
+
        if (machine_is_omap_h2() || machine_is_omap_h3()) {
                omap_cfg_reg(F18_1610_KBC0);
                omap_cfg_reg(D20_1610_KBC1);
@@ -252,6 +264,7 @@ static struct omap_mmc_conf mmc2_conf;
 
 static u64 mmc2_dmamask = 0xffffffff;
 
+
 static struct resource mmc2_resources[] = {
        {
                .start          = OMAP_MMC2_BASE,
@@ -281,6 +294,10 @@ static void __init omap_init_mmc(void)
        const struct omap_mmc_config    *mmc_conf;
        const struct omap_mmc_conf      *mmc;
 
+       /* REVISIT: 2430 has HS MMC */
+       if (cpu_is_omap2430())
+               return;
+
        /* NOTE:  assumes MMC was never (wrongly) enabled */
        mmc_conf = omap_get_config(OMAP_TAG_MMC, struct omap_mmc_config);
        if (!mmc_conf)
@@ -410,7 +427,14 @@ static inline void omap_init_uwire(void) {}
 #if    defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE)
 
 #ifdef CONFIG_ARCH_OMAP24XX
+
+#ifdef CONFIG_ARCH_OMAP2430
+/* WDT2 */
+#define        OMAP_WDT_BASE           0x49016000
+#else
 #define        OMAP_WDT_BASE           0x48022000
+#endif
+
 #else
 #define        OMAP_WDT_BASE           0xfffeb000
 #endif
@@ -493,21 +517,18 @@ static inline void omap_init_rng(void) {}
  */
 static int __init omap_init_devices(void)
 {
-/*
- * Need to enable relevant once for 2430 SDP
- */
-#ifndef CONFIG_MACH_OMAP_2430SDP
        /* please keep these calls, and their implementations above,
         * in alphabetical order so they're easier to sort through.
         */
        omap_init_dsp();
-       omap_init_i2c();
        omap_init_kp();
        omap_init_mmc();
        omap_init_uwire();
        omap_init_wdt();
        omap_init_rng();
-#endif
+       if (!cpu_is_omap2430()) {
+               omap_init_i2c();
+       }
        return 0;
 }
 arch_initcall(omap_init_devices);
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..a5512db
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * 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 __PLAT_OMAP_DSP_DSP_H
+#define __PLAT_OMAP_DSP_DSP_H
+
+#include "hardware_dsp.h"
+#include "dsp_common.h"
+#include <asm/arch/mmu.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, ...);
+#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);
+
+extern struct omap_mmu dsp_mmu;
+
+#define dsp_mem_enable(addr)   omap_mmu_mem_enable(&dsp_mmu, (addr))
+#define dsp_mem_disable(addr)  omap_mmu_mem_disable(&dsp_mmu, (addr))
+
+#endif /* __PLAT_OMAP_DSP_DSP_H */
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..f3a91d0
--- /dev/null
@@ -0,0 +1,628 @@
+/*
+ * 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 int 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,
+};
+
+#define list_for_each_entry_safe_natural(p,n,h,m) \
+                       list_for_each_entry_safe(p,n,h,m)
+#define __BUILD_KFUNC(fn, dir)                                                 \
+static int __dsp_kfunc_##fn##_devices(struct omap_dsp *dsp, int type, int stage)\
+{                                                                              \
+       struct dsp_kfunc_device *p, *tmp;                                       \
+       int ret, fail = 0;                                                      \
+                                                                               \
+       list_for_each_entry_safe_##dir(p, tmp, dsp->kdev_list, entry) {         \
+               if (type && (p->type != type))                                  \
+                       continue;                                               \
+               if (p->fn == NULL)                                              \
+                       continue;                                               \
+               ret = p->fn(p, stage);                                          \
+               if (ret) {                                                      \
+                       printk(KERN_ERR "%s %s failed\n", #fn, p->name);        \
+                       fail++;                                                 \
+               }                                                               \
+       }                                                                       \
+       return fail;                                                            \
+}
+#define BUILD_KFUNC(fn, dir)                                           \
+__BUILD_KFUNC(fn, dir)                                                 \
+static inline int dsp_kfunc_##fn##_devices(struct omap_dsp *dsp)       \
+{                                                                      \
+       return __dsp_kfunc_##fn##_devices(dsp, 0, 0);                   \
+}
+#define BUILD_KFUNC_CTL(fn, dir)                                                       \
+__BUILD_KFUNC(fn, dir)                                                                 \
+static inline int dsp_kfunc_##fn##_devices(struct omap_dsp *dsp, int type, int stage)  \
+{                                                                                      \
+       return __dsp_kfunc_##fn##_devices(dsp, type, stage);                            \
+}
+
+BUILD_KFUNC(probe, natural)
+BUILD_KFUNC(remove, reverse)
+BUILD_KFUNC_CTL(enable, natural)
+BUILD_KFUNC_CTL(disable, reverse)
+
+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.
+        */
+       dsp_mem_enable(ipbuf_sys_ad);
+       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:
+       dsp_mem_disable(ipbuf_sys_ad);
+       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;
+       }
+
+       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:
+       return ret;
+}
+
+int dsp_mbcmd_send_and_wait_exarg(struct mbcmd *mb, struct mb_exarg *arg,
+                                 wait_queue_head_t *q)
+{
+       int ret;
+
+       DEFINE_WAIT(wait);
+       prepare_to_wait(q, &wait, TASK_INTERRUPTIBLE);
+       ret = dsp_mbcmd_send_exarg(mb, arg);
+       if (ret < 0)
+               goto out;
+       schedule_timeout(DSP_TIMEOUT);
+ out:
+       finish_wait(q, &wait);
+       return ret;
+}
+
+/*
+ * mbcmd receiver
+ */
+static int mbcmd_receiver(void* msg)
+{
+       struct mbcmd *mb = (struct mbcmd *)&msg;
+
+       if (cmdinfo[mb->cmd_h] == NULL) {
+               printk(KERN_ERR
+                      "invalid message (%08x) for mbcmd_receiver().\n",
+                      (mbox_msg_t)msg);
+               return -1;
+       }
+
+       (*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));
+       return 0;
+}
+
+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 (IS_ERR(omap_dsp->mbox)) {
+               printk(KERN_ERR "failed to get mailbox handler for DSP.\n");
+               return -ENODEV;
+       }
+
+       omap_dsp->mbox->rxq->callback = mbcmd_receiver;
+       omap_dsp->mbox->txq->callback = mbcmd_sender_prepare;
+
+       return 0;
+}
+
+static void dsp_mbox_exit(void)
+{
+       omap_dsp->mbox->txq->callback = NULL;
+       omap_dsp->mbox->rxq->callback = NULL;
+
+       omap_mbox_put(omap_dsp->mbox);
+
+       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_enable();
+       ret = dsp_mem_late_init();
+       if (ret)
+               return ret;
+       ret = dsp_mbox_init();
+       if (ret)
+               goto fail_mbox;
+#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)
+               goto fail_kfunc;
+       omap_dsp->enabled = 1;
+
+       return 0;
+
+ fail_kfunc:
+       dsp_mbox_exit();
+ fail_mbox:
+       dsp_clk_disable();
+
+       return ret;
+}
+
+extern int  dsp_ctl_core_init(void);
+extern void dsp_ctl_core_exit(void);
+extern int 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 fail_kfunc;
+       }
+
+       ret = dsp_ctl_core_init();
+       if (ret)
+               goto fail_ctl_core;
+       ret = dsp_mem_init();
+       if (ret)
+               goto fail_mem;
+       ret = dsp_ctl_init();
+       if (unlikely(ret))
+               goto fail_ctl_init;
+       mblog_init();
+       ret = dsp_taskmod_init();
+       if (ret)
+               goto fail_taskmod;
+
+       return 0;
+
+ fail_taskmod:
+       mblog_exit();
+       dsp_ctl_exit();
+ fail_ctl_init:
+       dsp_mem_exit();
+ fail_mem:
+       dsp_ctl_core_exit();
+ fail_ctl_core:
+       dsp_kfunc_remove_devices(info);
+ fail_kfunc:
+       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;
+}
+
+#if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP1)
+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..79c1fdf
--- /dev/null
@@ -0,0 +1,1069 @@
+/*
+ * 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 <asm/arch/dsp.h>
+#include "hardware_dsp.h"
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.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 */
+       ret = dsp_setvar(VARID_ICRMASK, dsp_cpustat_get_icrmask());
+       if (ret < 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) {
+               pr_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;
+}
+
+int __init dsp_ctl_init(void)
+{
+       int ret;
+
+       ret = device_create_file(omap_dsp->dev, &dev_attr_ifver);
+       if (unlikely(ret))
+               return ret;
+       ret = device_create_file(omap_dsp->dev, &dev_attr_cpustat);
+       if (unlikely(ret))
+               goto fail_create_cpustat;
+       ret = device_create_file(omap_dsp->dev, &dev_attr_icrmask);
+       if (unlikely(ret))
+               goto fail_create_icrmask;
+
+       return 0;
+
+fail_create_icrmask:
+       device_remove_file(omap_dsp->dev, &dev_attr_cpustat);
+fail_create_cpustat:
+       device_remove_file(omap_dsp->dev, &dev_attr_ifver);
+
+       return 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..d17a5c8
--- /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++) {
+               device_create(dsp_ctl_class, NULL,
+                                   MKDEV(OMAP_DSP_CTL_MAJOR,
+                                         dev_list[i].minor),
+                                   dev_list[i].devname);
+       }
+
+       return 0;
+}
+
+void dsp_ctl_core_exit(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(dev_list); i++) {
+               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..fb35749
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * 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 __PLAT_OMAP_DSP_MBCMD_H
+#define __PLAT_OMAP_DSP_MBCMD_H
+/*
+ * 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
+
+#endif /* __PLAT_OMAP_DSP_MBCMD_H */
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..eab57b5
--- /dev/null
@@ -0,0 +1,472 @@
+/*
+ * 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/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/dsp.h>
+#include <asm/arch/mailbox.h>
+#include <asm/arch/mmu.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.h"
+
+#if defined(CONFIG_ARCH_OMAP1)
+#include "../../mach-omap1/mmu.h"
+#elif defined(CONFIG_ARCH_OMAP2)
+#include "../../mach-omap2/mmu.h"
+#endif
+
+#include "mmu.h"
+
+static struct mem_sync_struct mem_sync;
+
+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;
+}
+
+
+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(&dsp_mmu.exmap_sem);
+               if (exmap_valid(&dsp_mmu, vadr, len))
+                       ret = MEM_TYPE_EXTERN;
+               else
+                       ret = MEM_TYPE_NONE;
+               up_read(&dsp_mmu.exmap_sem);
+               return ret;
+       }
+}
+
+int dsp_address_validate(void *p, size_t len, char *fmt, ...)
+{
+       char s[64];
+       va_list args;
+
+       if (dsp_mem_type(p, len) > 0)
+               return 0;
+
+       if (fmt == NULL)
+               goto out;
+
+       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 external memory\n"
+              "space where no actual memory is mapped)\n", s, p, len);
+ out:
+       return -1;
+}
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+
+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;
+}
+
+/*
+ * 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)
+               return;
+
+       /* 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;
+
+       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;
+       }
+       omapfb_update_window_async(registered_fb[0], &win, fbupd_cb, NULL);
+}
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+static int omapfb_notifier_cb(struct notifier_block *omapfb_nb,
+                             unsigned long event, void *fbi)
+{
+       pr_info("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, status;
+
+       pr_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) {
+               pr_info("omapdsp: frame buffer not registered.\n");
+               return -EINVAL;
+       }
+       if (num_registered_fb != 1) {
+               pr_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_4K-1);
+       fbsz = (fbsz_sys + padr_sys - padr + SZ_4K-1) & ~(SZ_4K-1);
+
+       /* line up dspadr offset with padr */
+       dspadr_actual =
+               (fbsz > SZ_1M) ?  lineup_offset(*dspadr, padr, SZ_1M-1) :
+               (fbsz > SZ_64K) ? lineup_offset(*dspadr, padr, SZ_64K-1) :
+               /* (fbsz > SZ_4KB) ? */ *dspadr;
+       if (dspadr_actual != *dspadr)
+               pr_debug(
+                       "omapdsp: actual dspadr for FBEXPORT = %08x\n",
+                       dspadr_actual);
+       *dspadr = dspadr_actual;
+
+       cnt = omap_mmu_exmap(&dsp_mmu, 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);
+       }
+
+       /* increase the DMA priority */
+       set_emiff_dma_prio(15);
+
+#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");
+               omap_mmu_exunmap(&dsp_mmu, (unsigned long)dspadr);
+               return -ENOMEM;
+       }
+
+       status = omapfb_register_client(omapfb_nb, omapfb_notifier_cb, NULL);
+       if (status)
+               pr_info("omapfb_register_client(): failure(%d)\n", status);
+#endif
+
+       return cnt;
+}
+#else
+void mbox_fbctl_upd(void) { }
+#endif
+
+/* dsp/mem fops: backward compatibility */
+static ssize_t dsp_mem_read(struct file *file, char __user *buf, size_t count,
+                           loff_t *ppos)
+{
+       return __omap_mmu_mem_read(&dsp_mmu, (char __user *)buf, *ppos, count);
+}
+
+static ssize_t dsp_mem_write(struct file *file, const char __user *buf,
+                            size_t count, loff_t *ppos)
+{
+       return __omap_mmu_mem_write(&dsp_mmu,
+                                   (char __user *)buf, *ppos, count);
+}
+
+static int dsp_mem_ioctl(struct inode *inode, struct file *file,
+                        unsigned int cmd, unsigned long arg)
+{
+       struct omap_dsp_mapinfo mapinfo;
+       __u32 size;
+
+       switch (cmd) {
+       case MEM_IOCTL_MMUINIT:
+               if (dsp_mmu.exmap_tbl)
+                       omap_mmu_unregister(&dsp_mmu);
+               dsp_mem_ipi_init();
+               return omap_mmu_register(&dsp_mmu);
+
+       case MEM_IOCTL_EXMAP:
+               if (copy_from_user(&mapinfo, (void __user *)arg,
+                                  sizeof(mapinfo)))
+                       return -EFAULT;
+               return omap_mmu_exmap(&dsp_mmu, mapinfo.dspadr,
+                                     0, mapinfo.size, EXMAP_TYPE_MEM);
+
+       case MEM_IOCTL_EXUNMAP:
+               return omap_mmu_exunmap(&dsp_mmu, (unsigned long)arg);
+
+       case MEM_IOCTL_EXMAP_FLUSH:
+               omap_mmu_exmap_flush(&dsp_mmu);
+               return 0;
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+       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;
+       }
+#endif
+       case MEM_IOCTL_MMUITACK:
+               return dsp_mmu_itack();
+
+       case MEM_IOCTL_KMEM_RESERVE:
+
+               if (copy_from_user(&size, (void __user *)arg,
+                                  sizeof(__u32)))
+                       return -EFAULT;
+               return omap_mmu_kmem_reserve(&dsp_mmu, size);
+
+
+       case MEM_IOCTL_KMEM_RELEASE:
+               omap_mmu_kmem_release();
+               return 0;
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+
+struct file_operations dsp_mem_fops = {
+       .owner   = THIS_MODULE,
+       .read    = dsp_mem_read,
+       .write   = dsp_mem_write,
+       .ioctl   = dsp_mem_ioctl,
+};
+
+void dsp_mem_start(void)
+{
+       dsp_register_mem_cb(intmem_enable, intmem_disable);
+}
+
+void dsp_mem_stop(void)
+{
+       memset(&mem_sync, 0, sizeof(struct mem_sync_struct));
+       dsp_unregister_mem_cb();
+}
+
+static void dsp_mmu_irq_work(struct work_struct *work)
+{
+       struct omap_mmu *mmu = container_of(work, struct omap_mmu, irq_work);
+
+       if (dsp_cfgstat_get_stat() == CFGSTAT_READY) {
+               dsp_err_set(ERRCODE_MMU, mmu->fault_address);
+               return;
+       }
+       omap_mmu_itack(mmu);
+       pr_info("Resetting DSP...\n");
+       dsp_cpustat_request(CPUSTAT_RESET);
+       omap_mmu_enable(mmu, 0);
+}
+
+/*
+ * later half of dsp memory initialization
+ */
+int dsp_mem_late_init(void)
+{
+       int ret;
+
+       dsp_mem_ipi_init();
+
+       INIT_WORK(&dsp_mmu.irq_work, dsp_mmu_irq_work);
+       ret = omap_mmu_register(&dsp_mmu);
+       if (ret) {
+               dsp_reset_idle_boot_base();
+               goto out;
+       }
+       omap_dsp->mmu = &dsp_mmu;
+ out:
+       return ret;
+}
+
+int __init dsp_mem_init(void)
+{
+#ifdef CONFIG_ARCH_OMAP2
+       dsp_mmu.clk    = dsp_fck_handle;
+       dsp_mmu.memclk = dsp_ick_handle;
+#elif defined(CONFIG_ARCH_OMAP1)
+       dsp_mmu.clk    = dsp_ck_handle;
+       dsp_mmu.memclk = api_ck_handle;
+#endif
+       return 0;
+}
+
+void dsp_mem_exit(void)
+{
+       dsp_reset_idle_boot_base();
+       omap_mmu_unregister(&dsp_mmu);
+}
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..d2276f9
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * 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/arch/mailbox.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;
+       DEFINE_WAIT(wait);
+
+       if (count < 4)
+               return 0;
+
+       prepare_to_wait(&err_wait_q, &wait, TASK_INTERRUPTIBLE);
+       if (errcnt == 0)
+               schedule();
+       finish_wait(&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;
+}
+
+void dsp_err_notify(void)
+{
+       /* new error code should be assigned */
+       dsp_err_set(DSP_ERR_WDT, 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);
+       }
+       omap_dsp->mbox->err_notify = dsp_err_notify;
+       errcnt = 0;
+}
+
+void dsp_err_stop(void)
+{
+       wake_up_interruptible(&err_wait_q);
+       omap_dsp->mbox->err_notify = NULL;
+}
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..c0dc26c
--- /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 __PLAT_OMAP_DSP_FIFO_H
+#define __PLAT_OMAP_DSP_FIFO_H
+
+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;
+}
+
+#endif /* __PLAT_OMAP_DSP_FIFO_H */
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..aba8e74
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * 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;
+
+       pr_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..926d353
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * 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 __PLAT_OMAP_DSP_IPBUF_H
+#define __PLAT_OMAP_DSP_IPBUF_H
+
+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) atomic_inc((atomic_t *)&((ipbcfg)->bsycnt))
+#define ipb_bsycnt_dec(ipbcfg) atomic_dec((atomic_t *)&((ipbcfg)->bsycnt))
+
+#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)
+
+#endif /* __PLAT_OMAP_DSP_IPBUF_H */
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..2b1e113
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * 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) ?
+                       ((mb->data == AUDIO_PWR_UP)     ? "PWR AUD /UP":
+                        (mb->data == AUDIO_PWR_DOWN)   ? "PWR AUD /DOWN":
+                        (mb->data == AUDIO_PWR_DOWN2)  ? "PWR AUD /DOWN(2)":
+                        (mb->data == DSP_PWR_UP)       ? "PWR DSP /UP":
+                        (mb->data == DSP_PWR_DOWN)     ? "PWR DSP /DOWN":
+                        (mb->data == DVFS_START)       ? "PWR DVFS/START":
+                        (mb->data == DVFS_STOP)        ? "PWR DVFS/STOP":
+                        NULL):
+
+                   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";
+               pr_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:
+               pr_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:
+               pr_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/mmu.h b/arch/arm/plat-omap/dsp/mmu.h
new file mode 100644 (file)
index 0000000..ca47b7b
--- /dev/null
@@ -0,0 +1,140 @@
+#ifndef __PLAT_OMAP_DSP_MMU_H
+#define __PLAT_OMAP_DSP_MMU_H
+
+#ifdef CONFIG_ARCH_OMAP1
+
+#ifdef CONFIG_ARCH_OMAP15XX
+struct omap_mmu dsp_mmu = {
+       .name           = "mmu:dsp",
+       .type           = OMAP_MMU_DSP,
+       .base           = DSP_MMU_BASE,
+       .membase        = OMAP15XX_DSP_BASE,
+       .memsize        = OMAP15XX_DSP_SIZE,
+       .nr_tlb_entries = 32,
+       .addrspace      = 24,
+       .irq            = INT_1510_DSP_MMU,
+       .ops            = &omap1_mmu_ops,
+};
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
+struct omap_mmu dsp_mmu = {
+       .name           = "mmu:dsp",
+       .type           = OMAP_MMU_DSP,
+       .base           = DSP_MMU_BASE,
+       .membase        = OMAP16XX_DSP_BASE,
+       .memsize        = OMAP16XX_DSP_SIZE,
+       .nr_tlb_entries = 32,
+       .addrspace      = 24,
+       .irq            = INT_1610_DSP_MMU,
+       .ops            = &omap1_mmu_ops,
+};
+#endif
+#else /* OMAP2 */
+struct omap_mmu dsp_mmu = {
+       .name           = "mmu:dsp",
+       .type           = OMAP_MMU_DSP,
+       .base           = DSP_MMU_24XX_VIRT,
+       .membase        = DSP_MEM_24XX_VIRT,
+       .memsize        = DSP_MEM_24XX_SIZE,
+       .nr_tlb_entries = 32,
+       .addrspace      = 24,
+       .irq            = INT_24XX_DSP_MMU,
+       .ops            = &omap2_mmu_ops,
+};
+
+#define IOMAP_VAL      0x3f
+#endif
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+static struct omapfb_notifier_block *omapfb_nb;
+static int omapfb_ready;
+#endif
+
+/*
+ * 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)
+#else
+#define set_emiff_dma_prio(prio)       do { } while (0)
+#endif /* CONFIG_ARCH_OMAP1 */
+
+#ifdef CONFIG_ARCH_OMAP1
+static int dsp_mmu_itack(void)
+{
+       unsigned long dspadr;
+
+       pr_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_mmu.fault_address & ~(SZ_4K-1);
+       /* FIXME: reserve TLB entry for this */
+       omap_mmu_exmap(&dsp_mmu, dspadr, 0, SZ_4K, EXMAP_TYPE_MEM);
+       pr_info("omapdsp: falling into recovery runlevel...\n");
+       dsp_set_runlevel(RUNLEVEL_RECOVERY);
+       omap_mmu_itack(&dsp_mmu);
+       udelay(100);
+       omap_mmu_exunmap(&dsp_mmu, dspadr);
+       dsp_err_clear(ERRCODE_MMU);
+       return 0;
+}
+
+/*
+ * 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);
+}
+#else
+static int intmem_enable(void) { return 0; }
+static void intmem_disable(void) { }
+static int dsp_mmu_itack(void) { return 0; }
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2
+static inline void dsp_mem_ipi_init(void)
+{
+       int i, dspmem_pg_count;
+       dspmem_pg_count = dspmem_size >> 12;
+       for (i = 0; i < dspmem_pg_count; i++) {
+               writel(i, DSP_IPI_INDEX);
+               writel(DSP_IPI_ENTRY_ELMSIZEVALUE_16, DSP_IPI_ENTRY);
+       }
+       writel(1, DSP_IPI_ENABLE);
+       writel(IOMAP_VAL, DSP_IPI_IOMAP);
+}
+#else
+static inline void dsp_mem_ipi_init(void) { }
+#endif
+
+#endif /* __PLAT_OMAP_DSP_MMU_H */
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..666ca4d
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * 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
+ *
+ */
+
+#ifndef __PLAT_OMAP_DSP_PROCLIST_H
+#define __PLAT_OMAP_DSP_PROCLIST_H
+
+struct proc_list {
+       struct list_head list_head;
+       pid_t pid;
+       struct file *file;
+};
+
+static inline int 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);
+       if (new == NULL)
+               return -ENOMEM;
+       new->pid = tsk->pid;
+       new->file = file;
+       spin_lock(lock);
+       list_add_tail(&new->list_head, list);
+       spin_unlock(lock);
+
+       return 0;
+}
+
+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);
+}
+
+#endif /* __PLAT_OMAP_DSP_PROCLIST_H */
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..f2ccbdf
--- /dev/null
@@ -0,0 +1,3039 @@
+/*
+ * 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 <asm/arch/dsp.h>
+#include "uaccess_dsp.h"
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.h"
+#include "fifo.h"
+#include "proclist.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
+
+static 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);
+
+static inline void set_taskdev_state(struct taskdev *dev, int state)
+{
+       pr_debug("omapdsp: devstate: CHANGE %s[%d]:\"%s\"->\"%s\"\n",
+                dev->name,
+                (dev->task ? dev->task->tid : -1),
+                devstate_name(dev->state),
+                devstate_name(state));
+       dev->state = state;
+}
+
+/*
+ * devstate_read_lock_timeout()
+ * devstate_write_lock_timeout():
+ * timeout != 0: dev->state can be diffeent from what you want.
+ * timeout == 0: no timeout
+ */
+#define BUILD_DEVSTATE_LOCK_TIMEOUT(rw)                                                \
+static int devstate_##rw##_lock_timeout(struct taskdev *dev, long devstate,     \
+                                     int timeout)                              \
+{                                                                              \
+       DEFINE_WAIT(wait);                                                      \
+       down_##rw(&dev->state_sem);                                             \
+       while (!(dev->state & devstate)) {                                      \
+               up_##rw(&dev->state_sem);                                       \
+               prepare_to_wait(&dev->state_wait_q, &wait, TASK_INTERRUPTIBLE); \
+               if (!timeout)                                                   \
+                       timeout = MAX_SCHEDULE_TIMEOUT;                         \
+               timeout = schedule_timeout(timeout);                            \
+               finish_wait(&dev->state_wait_q, &wait);                         \
+               if (timeout == 0)                                               \
+                       return -ETIME;                                          \
+               if (signal_pending(current))                                    \
+                       return -EINTR;                                          \
+               down_##rw(&dev->state_sem);                                     \
+       }                                                                       \
+       return 0;                                                               \
+}
+BUILD_DEVSTATE_LOCK_TIMEOUT(read)
+BUILD_DEVSTATE_LOCK_TIMEOUT(write)
+
+#define BUILD_DEVSTATE_LOCK_AND_TEST(rw)                                       \
+static int devstate_##rw##_lock_and_test(struct taskdev *dev, long devstate)   \
+{                                                                              \
+       down_##rw(&dev->state_sem);                                             \
+       if (dev->state & devstate)                                              \
+               return 1;       /* success */                                   \
+       /* failure */                                                           \
+       up_##rw(&dev->state_sem);                                               \
+       return 0;                                                               \
+}
+BUILD_DEVSTATE_LOCK_AND_TEST(read)
+BUILD_DEVSTATE_LOCK_AND_TEST(write)
+
+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);
+       pr_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;
+
+       pr_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);
+               pr_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;
+       DEFINE_WAIT(wait);
+
+       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;
+
+
+       prepare_to_wait(&dev->read_wait_q, &wait, TASK_INTERRUPTIBLE);
+       if (fifo_empty(&dev->rcvdt.fifo))
+               schedule();
+       finish_wait(&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;
+       DEFINE_WAIT(wait);
+
+       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;
+
+       prepare_to_wait(&dev->read_wait_q, &wait, TASK_INTERRUPTIBLE);
+       if (ipblink_empty(&rcvdt->link))
+               schedule();
+       finish_wait(&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;
+       DEFINE_WAIT(wait);
+
+       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;
+
+       prepare_to_wait(&dev->write_wait_q, &wait, TASK_INTERRUPTIBLE);
+       if (dev->wsz == 0)
+               schedule();
+       finish_wait(&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;
+       DEFINE_WAIT(wait);
+
+       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;
+
+       prepare_to_wait(&dev->write_wait_q, &wait, TASK_INTERRUPTIBLE);
+       if (dev->wsz == 0)
+               schedule();
+       finish_wait(&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;
+       omap_mmu_exmap_use(&dsp_mmu, 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;
+       omap_mmu_exmap_unuse(&dsp_mmu, 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 = omap_mmu_virt_to_phys(&dsp_mmu, 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;
+
+               pr_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;
+       omap_mmu_exmap_use(&dsp_mmu, 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 */
+       set_taskdev_state(dev, 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;
+               }
+               set_taskdev_state(dev, 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;
+               set_taskdev_state(dev, 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
+       ret = proc_list_add(&dev->proc_list_lock,
+                           &dev->proc_list, current, file);
+       if (ret)
+               goto out;
+
+       dev->usecount++;
+       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);
+ out:
+       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:
+               set_taskdev_state(dev, 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)) {
+                       set_taskdev_state(dev, 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..
+                        */
+                       set_taskdev_state(dev, 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:
+       case TASKDEV_ST_INVALID:
+               /* fine */
+               goto notask;
+
+       case TASKDEV_ST_ATTACHED:
+       case TASKDEV_ST_FREEZED:
+               /* task is working. kill it. */
+               set_taskdev_state(dev, 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. */
+               set_taskdev_state(dev, TASKDEV_ST_ADDFAIL);
+               wake_up_interruptible_all(&dev->state_wait_q);
+               break;
+
+       case TASKDEV_ST_DELREQ:
+               /* nobody is waiting. */
+               set_taskdev_state(dev, 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:
+       set_taskdev_state(dev, TASKDEV_ST_INVALID);
+       devstate_read_unlock(dev);
+
+       taskdev_delete(minor);
+       kfree(dev);
+
+       return 0;
+}
+
+static 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;
+       struct device *task_dev;
+
+       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';
+       set_taskdev_state(dev, (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);
+               return ret;
+       }
+       ret = device_create_file(&dev->dev, &dev_attr_devname);
+       if (ret)
+               goto fail_create_devname;
+       ret = device_create_file(&dev->dev, &dev_attr_devstate);
+       if (ret)
+               goto fail_create_devstate;
+       ret = device_create_file(&dev->dev, &dev_attr_proc_list);
+       if (ret)
+               goto fail_create_proclist;
+
+       task_dev = device_create(dsp_task_class, NULL,
+                                MKDEV(OMAP_DSP_TASK_MAJOR, minor),
+                                "dsptask%d", (int)minor);
+       
+       if (unlikely(IS_ERR(task_dev))) {
+               ret = -EINVAL;
+               goto fail_create_taskclass;
+       }
+
+       init_waitqueue_head(&dev->state_wait_q);
+       init_rwsem(&dev->state_sem);
+
+       return 0;
+
+ fail_create_taskclass:
+       device_remove_file(&dev->dev, &dev_attr_proc_list);
+ fail_create_proclist:
+       device_remove_file(&dev->dev, &dev_attr_devstate);
+ fail_create_devstate:
+       device_remove_file(&dev->dev, &dev_attr_devname);
+ fail_create_devname:
+       device_unregister(&dev->dev);
+       return ret;
+}
+
+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);
+       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);
+       if (unlikely(ret))
+               goto fail_create_taskname;
+       ret = device_create_file(&dev->dev, &dev_attr_ttyp);
+       if (unlikely(ret))
+               goto fail_create_ttyp;
+       ret = device_create_file(&dev->dev, &dev_attr_wsz);
+       if (unlikely(ret))
+               goto fail_create_wsz;
+       if (task->map_length) {
+               ret = device_create_file(&dev->dev, &dev_attr_mmap);
+               if (unlikely(ret))
+                       goto fail_create_mmap;
+       }
+       if (sndtyp_wd(ttyp)) {
+               ret = device_create_file(&dev->dev, &dev_attr_fifosz);
+               if (unlikely(ret))
+                       goto fail_create_fifosz;
+               ret = device_create_file(&dev->dev, &dev_attr_fifocnt);
+               if (unlikely(ret))
+                       goto fail_create_fifocnt;
+       } else {
+               ret = device_create_file(&dev->dev, &dev_attr_ipblink);
+               if (unlikely(ret))
+                       goto fail_create_ipblink;
+       }
+
+       dev->task = task;
+       task->dev = dev;
+
+       return 0;
+
+ fail_create_fifocnt:
+       device_remove_file(&dev->dev, &dev_attr_fifosz);
+ fail_create_ipblink:
+ fail_create_fifosz:
+       if (task->map_length)
+               device_remove_file(&dev->dev, &dev_attr_mmap);
+ fail_create_mmap:
+       device_remove_file(&dev->dev, &dev_attr_wsz);
+ fail_create_wsz:
+       device_remove_file(&dev->dev, &dev_attr_ttyp);
+ fail_create_ttyp:
+       device_remove_file(&dev->dev, &dev_attr_taskname);
+ fail_create_taskname:
+       if (task->map_length)
+               dev->fops.mmap = NULL;
+
+       dev->fops.write = NULL;
+       dev->wsz = 0;
+
+       dev->fops.read = NULL;
+       taskdev_flush_buf(dev);
+
+       if (sndtyp_wd(ttyp))
+               free_fifo(&dev->rcvdt.fifo);
+
+       dev->task = NULL;
+
+       return ret;
+}
+
+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.mmap = NULL;
+       }
+
+       dev->fops.read = NULL;
+       taskdev_flush_buf(dev);
+       if (sndtyp_wd(ttyp))
+               free_fifo(&dev->rcvdt.fifo);
+
+       dev->fops.write = NULL;
+       dev->wsz = 0;
+
+       pr_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;
+       }
+       set_taskdev_state(dev, TASKDEV_ST_ADDING);
+       devstate_write_unlock(dev);
+
+       if (adr == TADD_ABORTADR) {
+               /* aborting tadd intentionally */
+               pr_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);
+       pr_info("omapdsp: taskdev %s enabled.\n", dev->name);
+       set_taskdev_state(dev, 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");
+
+       set_taskdev_state(dev, 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:
+       set_taskdev_state(dev, 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;
+       }
+       set_taskdev_state(dev, 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. */
+               set_taskdev_state(dev, 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;
+       }
+       set_taskdev_state(dev, 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) {
+                       set_taskdev_state(dev, 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);
+       set_taskdev_state(dev, (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;
+       }
+       pr_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;
+       }
+       pr_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';
+                       pr_info("%s", s);
+                       p = s;
+                       continue;
+               }
+               if (p == s_end) {
+                       *p = '\0';
+                       pr_info("%s\n", s);
+                       p = s;
+                       continue;
+               }
+       }
+       if (p > s) {
+               *p = '\0';
+               pr_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';
+                       pr_info("%s", s);
+                       p = s;
+                       continue;
+               }
+               if (p == s_end) {
+                       *p = '\0';
+                       pr_info("%s\n", s);
+                       p = s;
+                       continue;
+               }
+       }
+       if (p > s) {
+               *p = '\0';
+               pr_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");
+       if (IS_ERR(dsp_task_class)) {
+               printk(KERN_ERR "omapdsp: failed to create DSP task class\n");
+               driver_unregister(&dsptask_driver);
+               bus_unregister(&dsptask_bus);
+               unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
+               return -EINVAL;
+       }
+
+       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..4297b51
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * 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 <asm/arch/dsp.h>
+#include "dsp_mbcmd.h"
+#include "dsp.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;
+       DEFINE_WAIT(wait);
+
+       if (dsp_cfgstat_get_stat() != CFGSTAT_READY) {
+               printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
+               return -EINVAL;
+       }
+
+       prepare_to_wait(&read_wait_q, &wait, TASK_INTERRUPTIBLE);
+       if (change_cnt == 0)    /* last check */
+               schedule();
+       finish_wait(&read_wait_q, &wait);
+
+       /* unconfigured while waiting ;-( */
+       if ((change_cnt == 0) && (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..9291930
--- /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 337455dfe64d493e64746d62caf38e7d169e71d2..3cd3d7f1465d34e7acf04f36409e52dfbc6097d7 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/ptrace.h>
 #include <linux/sysdev.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 #define OMAP24XX_GPIO_LEVELDETECT1     0x0044
 #define OMAP24XX_GPIO_RISINGDETECT     0x0048
 #define OMAP24XX_GPIO_FALLINGDETECT    0x004c
+#define OMAP24XX_GPIO_DEBOUNCE_EN      0x0050
+#define OMAP24XX_GPIO_DEBOUNCE_VAL     0x0054
 #define OMAP24XX_GPIO_CLEARIRQENABLE1  0x0060
 #define OMAP24XX_GPIO_SETIRQENABLE1    0x0064
 #define OMAP24XX_GPIO_CLEARWKUENA      0x0080
@@ -483,6 +486,43 @@ static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio, in
        /* FIXME: Possibly do 'set_irq_handler(j, handle_level_irq)' if only level
         * triggering requested. */
 }
+
+void
+omap_set_gpio_debounce(int gpio, int enable)
+{
+       struct gpio_bank *bank;
+       void __iomem *reg;
+       u32 val, l = 1 << get_gpio_index(gpio);
+
+       bank = get_gpio_bank(gpio);
+       reg = bank->base;
+
+       reg += OMAP24XX_GPIO_DEBOUNCE_EN;
+       val = __raw_readl(reg);
+
+       if (enable)
+               val |= l;
+       else
+               val &= ~l;
+
+       __raw_writel(val, reg);
+}
+EXPORT_SYMBOL(omap_set_gpio_debounce);
+
+void
+omap_set_gpio_debounce_time(int gpio, int enc_time)
+{
+       struct gpio_bank *bank;
+       void __iomem *reg;
+
+       bank = get_gpio_bank(gpio);
+       reg = bank->base;
+
+       enc_time &= 0xff;
+       reg += OMAP24XX_GPIO_DEBOUNCE_VAL;
+       __raw_writel(enc_time, reg);
+}
+EXPORT_SYMBOL(omap_set_gpio_debounce_time);
 #endif
 
 static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
diff --git a/arch/arm/plat-omap/mmu.c b/arch/arm/plat-omap/mmu.c
new file mode 100644 (file)
index 0000000..30c646e
--- /dev/null
@@ -0,0 +1,1562 @@
+/*
+ * linux/arch/arm/plat-omap/mmu.c
+ *
+ * OMAP MMU management framework
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation
+ *
+ * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *        and Paul Mundt <lethal@linux-sh.org>
+ *
+ * TWL support: Hiroshi DOYU <Hiroshi.DOYU@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/mempool.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/arch/mmu.h>
+#include <asm/sizes.h>
+
+#if defined(CONFIG_ARCH_OMAP1)
+#include "../mach-omap1/mmu.h"
+#elif defined(CONFIG_ARCH_OMAP2)
+#include "../mach-omap2/mmu.h"
+#endif
+
+/*
+ * On OMAP2 MMU_LOCK_xxx_MASK only applies to the IVA and DSP, the camera
+ * MMU has base and victim implemented in different bits in the LOCK
+ * register (shifts are still the same), all of the other registers are
+ * the same on all of the MMUs..
+ */
+#define MMU_LOCK_BASE_SHIFT            10
+#define MMU_LOCK_VICTIM_SHIFT          4
+
+#define CAMERA_MMU_LOCK_BASE_MASK      (0x7 << MMU_LOCK_BASE_SHIFT)
+#define CAMERA_MMU_LOCK_VICTIM_MASK    (0x7 << MMU_LOCK_VICTIM_SHIFT)
+
+#define is_aligned(adr,align)  (!((adr)&((align)-1)))
+#define ORDER_1MB      (20 - PAGE_SHIFT)
+#define ORDER_64KB     (16 - PAGE_SHIFT)
+#define ORDER_4KB      (12 - PAGE_SHIFT)
+
+#define MMU_CNTL_EMUTLBUPDATE  (1<<3)
+#define MMU_CNTL_TWLENABLE     (1<<2)
+#define MMU_CNTL_MMUENABLE     (1<<1)
+
+static mempool_t *mempool_1M;
+static mempool_t *mempool_64K;
+
+#define omap_mmu_for_each_tlb_entry(mmu, entry)                        \
+       for (entry = mmu->exmap_tbl; prefetch(entry + 1),       \
+            entry < (mmu->exmap_tbl + mmu->nr_tlb_entries);    \
+            entry++)
+
+#define to_dev(obj)    container_of(obj, struct device, kobj)
+
+static void *mempool_alloc_from_pool(mempool_t *pool,
+                                    unsigned int __nocast gfp_mask)
+{
+       spin_lock_irq(&pool->lock);
+       if (likely(pool->curr_nr)) {
+               void *element = pool->elements[--pool->curr_nr];
+               spin_unlock_irq(&pool->lock);
+               return element;
+       }
+
+       spin_unlock_irq(&pool->lock);
+       return mempool_alloc(pool, gfp_mask);
+}
+
+/*
+ * kmem_reserve(), kmem_release():
+ * reserve or release kernel memory for exmap().
+ *
+ * exmap() might request consecutive 1MB or 64kB,
+ * but it will be difficult after memory pages are fragmented.
+ * So, user can reserve such memory blocks in the early phase
+ * through kmem_reserve().
+ */
+static void *omap_mmu_pool_alloc(unsigned int __nocast gfp, void *order)
+{
+       return (void *)__get_dma_pages(gfp, (unsigned int)order);
+}
+
+static void omap_mmu_pool_free(void *buf, void *order)
+{
+       free_pages((unsigned long)buf, (unsigned int)order);
+}
+
+int omap_mmu_kmem_reserve(struct omap_mmu *mmu, unsigned long size)
+{
+       unsigned long len = size;
+
+       /* alignment check */
+       if (!is_aligned(size, SZ_64K)) {
+               printk(KERN_ERR
+                      "omapdsp: size(0x%lx) is not multiple of 64KB.\n", size);
+               return -EINVAL;
+       }
+
+       if (size > (1 << mmu->addrspace)) {
+               printk(KERN_ERR
+                      "omapdsp: size(0x%lx) is larger than DSP memory space "
+                      "size (0x%x.\n", size, (1 << mmu->addrspace));
+               return -EINVAL;
+       }
+
+       if (size >= SZ_1M) {
+               int nr = size >> 20;
+
+               if (likely(!mempool_1M))
+                       mempool_1M = mempool_create(nr, omap_mmu_pool_alloc,
+                                                   omap_mmu_pool_free,
+                                                   (void *)ORDER_1MB);
+               else
+                       mempool_resize(mempool_1M, mempool_1M->min_nr + nr,
+                                      GFP_KERNEL);
+
+               size &= ~(0xf << 20);
+       }
+
+       if (size >= SZ_64K) {
+               int nr = size >> 16;
+
+               if (likely(!mempool_64K))
+                       mempool_64K = mempool_create(nr, omap_mmu_pool_alloc,
+                                                    omap_mmu_pool_free,
+                                                    (void *)ORDER_64KB);
+               else
+                       mempool_resize(mempool_64K, mempool_64K->min_nr + nr,
+                                      GFP_KERNEL);
+
+               size &= ~(0xf << 16);
+       }
+
+       if (size)
+               len -= size;
+
+       return len;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_kmem_reserve);
+
+void omap_mmu_kmem_release(void)
+{
+       if (mempool_64K) {
+               mempool_destroy(mempool_64K);
+               mempool_64K = NULL;
+       }
+
+       if (mempool_1M) {
+               mempool_destroy(mempool_1M);
+               mempool_1M = NULL;
+       }
+}
+EXPORT_SYMBOL_GPL(omap_mmu_kmem_release);
+
+static void omap_mmu_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(mempool_64K))
+               mempool_free((void *)buf, mempool_64K);
+       else if ((order == ORDER_1MB) && likely(mempool_1M))
+               mempool_free((void *)buf, mempool_1M);
+       else
+               free_pages(buf, order);
+}
+
+/*
+ * ARM MMU operations
+ */
+int exmap_set_armmmu(unsigned long virt, unsigned long phys, unsigned long size)
+{
+       long off;
+       unsigned long sz_left;
+       pmd_t *pmdp;
+       pte_t *ptep;
+       int prot_pmd, prot_pte;
+
+       printk(KERN_DEBUG
+              "MMU: mapping in ARM MMU, v=0x%08lx, p=0x%08lx, sz=0x%lx\n",
+              virt, phys, size);
+
+       prot_pmd = PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_IO);
+       prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_WRITE;
+
+       pmdp = pmd_offset(pgd_offset_k(virt), virt);
+       if (pmd_none(*pmdp)) {
+               ptep = pte_alloc_one_kernel(&init_mm, 0);
+               if (ptep == NULL)
+                       return -ENOMEM;
+               /* note: two PMDs will be set  */
+               pmd_populate_kernel(&init_mm, pmdp, ptep);
+       }
+
+       off = phys - virt;
+       for (sz_left = size;
+            sz_left >= PAGE_SIZE;
+            sz_left -= PAGE_SIZE, virt += PAGE_SIZE) {
+               ptep = pte_offset_kernel(pmdp, virt);
+               set_pte_ext(ptep, __pte((virt + off) | prot_pte), 0);
+       }
+       if (sz_left)
+               BUG();
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(exmap_set_armmmu);
+
+void exmap_clear_armmmu(unsigned long virt, unsigned long size)
+{
+       unsigned long sz_left;
+       pmd_t *pmdp;
+       pte_t *ptep;
+
+       printk(KERN_DEBUG
+              "MMU: unmapping in ARM MMU, v=0x%08lx, sz=0x%lx\n",
+              virt, size);
+
+       for (sz_left = size;
+            sz_left >= PAGE_SIZE;
+            sz_left -= PAGE_SIZE, virt += PAGE_SIZE) {
+               pmdp = pmd_offset(pgd_offset_k(virt), virt);
+               ptep = pte_offset_kernel(pmdp, virt);
+               pte_clear(&init_mm, virt, ptep);
+       }
+       if (sz_left)
+               BUG();
+}
+EXPORT_SYMBOL_GPL(exmap_clear_armmmu);
+
+int exmap_valid(struct omap_mmu *mmu, void *vadr, size_t len)
+{
+       /* exmap_sem should be held before calling this function */
+       struct exmap_tbl *ent;
+
+start:
+       omap_mmu_for_each_tlb_entry(mmu, ent) {
+               void *mapadr;
+               unsigned long mapsize;
+
+               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;
+}
+EXPORT_SYMBOL_GPL(exmap_valid);
+
+/*
+ * omap_mmu_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 omap_mmu_exmap_use(struct omap_mmu *mmu, void *vadr, size_t len)
+{
+       struct exmap_tbl *ent;
+
+       down_write(&mmu->exmap_sem);
+       omap_mmu_for_each_tlb_entry(mmu, ent) {
+               void *mapadr;
+               unsigned long mapsize;
+
+               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(&mmu->exmap_sem);
+}
+EXPORT_SYMBOL_GPL(omap_mmu_exmap_use);
+
+void omap_mmu_exmap_unuse(struct omap_mmu *mmu, void *vadr, size_t len)
+{
+       struct exmap_tbl *ent;
+
+       down_write(&mmu->exmap_sem);
+       omap_mmu_for_each_tlb_entry(mmu, ent) {
+               void *mapadr;
+               unsigned long mapsize;
+
+               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(&mmu->exmap_sem);
+}
+EXPORT_SYMBOL_GPL(omap_mmu_exmap_unuse);
+
+/*
+ * omap_mmu_virt_to_phys()
+ * returns physical address, and sets len to valid length
+ */
+unsigned long
+omap_mmu_virt_to_phys(struct omap_mmu *mmu, void *vadr, size_t *len)
+{
+       struct exmap_tbl *ent;
+
+       if (omap_mmu_internal_memory(mmu, vadr)) {
+               unsigned long addr = (unsigned long)vadr;
+               *len = mmu->membase + mmu->memsize - addr;
+               return addr;
+       }
+
+       /* EXRAM */
+       omap_mmu_for_each_tlb_entry(mmu, ent) {
+               void *mapadr;
+               unsigned long mapsize;
+
+               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;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_virt_to_phys);
+
+/*
+ * PTE operations
+ */
+static inline void
+omap_mmu_alloc_section(struct mm_struct *mm, unsigned long virt,
+                      unsigned long phys, int prot)
+{
+       pmd_t *pmdp = pmd_offset(pgd_offset(mm, virt), virt);
+       if (virt & (1 << SECTION_SHIFT))
+               pmdp++;
+       *pmdp = __pmd((phys & SECTION_MASK) | prot | PMD_TYPE_SECT);
+       flush_pmd_entry(pmdp);
+}
+
+static inline void
+omap_mmu_alloc_supersection(struct mm_struct *mm, unsigned long virt,
+                           unsigned long phys, int prot)
+{
+       int i;
+       for (i = 0; i < 16; i += 1) {
+               omap_mmu_alloc_section(mm, virt, phys, prot | PMD_SECT_SUPER);
+               virt += (PGDIR_SIZE / 2);
+       }
+}
+
+static inline int
+omap_mmu_alloc_page(struct mm_struct *mm, unsigned long virt,
+                   unsigned long phys, pgprot_t prot)
+{
+       pte_t *ptep;
+       pmd_t *pmdp = pmd_offset(pgd_offset(mm, virt), virt);
+
+       if (!(prot & PTE_TYPE_MASK))
+               prot |= PTE_TYPE_SMALL;
+
+       if (pmd_none(*pmdp)) {
+               ptep = pte_alloc_one_kernel(mm, virt);
+               if (ptep == NULL)
+                       return -ENOMEM;
+               pmd_populate_kernel(mm, pmdp, ptep);
+       }
+       ptep = pte_offset_kernel(pmdp, virt);
+       ptep -= PTRS_PER_PTE;
+       *ptep = pfn_pte(phys >> PAGE_SHIFT, prot);
+       flush_pmd_entry((pmd_t *)ptep);
+       return 0;
+}
+
+static inline int
+omap_mmu_alloc_largepage(struct mm_struct *mm, unsigned long virt,
+                        unsigned long phys, pgprot_t prot)
+{
+       int i, ret;
+       for (i = 0; i < 16; i += 1) {
+               ret = omap_mmu_alloc_page(mm, virt, phys,
+                                         prot | PTE_TYPE_LARGE);
+               if (ret)
+                       return -ENOMEM; /* only 1st time */
+               virt += PAGE_SIZE;
+       }
+       return 0;
+}
+
+static int omap_mmu_load_pte(struct omap_mmu *mmu,
+                            struct omap_mmu_tlb_entry *e)
+{
+       int ret = 0;
+       struct mm_struct *mm = mmu->twl_mm;
+       const unsigned long va = e->va;
+       const unsigned long pa = e->pa;
+       const pgprot_t prot = mmu->ops->pte_get_attr(e);
+
+       spin_lock(&mm->page_table_lock);
+
+       switch (e->pgsz) {
+       case OMAP_MMU_CAM_PAGESIZE_16MB:
+               omap_mmu_alloc_supersection(mm, va, pa, prot);
+               break;
+       case OMAP_MMU_CAM_PAGESIZE_1MB:
+               omap_mmu_alloc_section(mm, va, pa, prot);
+               break;
+       case OMAP_MMU_CAM_PAGESIZE_64KB:
+               ret = omap_mmu_alloc_largepage(mm, va, pa, prot);
+               break;
+       case OMAP_MMU_CAM_PAGESIZE_4KB:
+               ret = omap_mmu_alloc_page(mm, va, pa, prot);
+               break;
+       default:
+               BUG();
+               break;
+       }
+
+       spin_unlock(&mm->page_table_lock);
+
+       return ret;
+}
+
+static void omap_mmu_clear_pte(struct omap_mmu *mmu, unsigned long virt)
+{
+       pte_t *ptep, *end;
+       pmd_t *pmdp;
+       struct mm_struct *mm = mmu->twl_mm;
+
+       spin_lock(&mm->page_table_lock);
+
+       pmdp = pmd_offset(pgd_offset(mm, virt), virt);
+
+       if (pmd_none(*pmdp))
+               goto out;
+
+       if (!pmd_table(*pmdp))
+               goto invalidate_pmd;
+
+       ptep = pte_offset_kernel(pmdp, virt);
+       pte_clear(mm, virt, ptep);
+       flush_pmd_entry((pmd_t *)ptep);
+
+       /* zap pte */
+       end = pmd_page_vaddr(*pmdp);
+       ptep = end - PTRS_PER_PTE;
+       while (ptep < end) {
+               if (!pte_none(*ptep))
+                       goto out;
+               ptep++;
+       }
+       pte_free_kernel(pmd_page_vaddr(*pmdp));
+
+ invalidate_pmd:
+       pmd_clear(pmdp);
+       flush_pmd_entry(pmdp);
+ out:
+       spin_unlock(&mm->page_table_lock);
+}
+
+/*
+ * TLB operations
+ */
+static struct cam_ram_regset *
+omap_mmu_cam_ram_alloc(struct omap_mmu *mmu, struct omap_mmu_tlb_entry *entry)
+{
+       return mmu->ops->cam_ram_alloc(entry);
+}
+
+static int omap_mmu_cam_ram_valid(struct omap_mmu *mmu,
+                                 struct cam_ram_regset *cr)
+{
+       return mmu->ops->cam_ram_valid(cr);
+}
+
+static inline void
+omap_mmu_get_tlb_lock(struct omap_mmu *mmu, struct omap_mmu_tlb_lock *tlb_lock)
+{
+       unsigned long lock = omap_mmu_read_reg(mmu, MMU_LOCK);
+       int mask;
+
+       mask = (mmu->type == OMAP_MMU_CAMERA) ?
+                       CAMERA_MMU_LOCK_BASE_MASK : MMU_LOCK_BASE_MASK;
+       tlb_lock->base = (lock & mask) >> MMU_LOCK_BASE_SHIFT;
+
+       mask = (mmu->type == OMAP_MMU_CAMERA) ?
+                       CAMERA_MMU_LOCK_VICTIM_MASK : MMU_LOCK_VICTIM_MASK;
+       tlb_lock->victim = (lock & mask) >> MMU_LOCK_VICTIM_SHIFT;
+}
+
+static inline void
+omap_mmu_set_tlb_lock(struct omap_mmu *mmu, struct omap_mmu_tlb_lock *lock)
+{
+       omap_mmu_write_reg(mmu,
+                          (lock->base << MMU_LOCK_BASE_SHIFT) |
+                          (lock->victim << MMU_LOCK_VICTIM_SHIFT), MMU_LOCK);
+}
+
+static inline void omap_mmu_flush(struct omap_mmu *mmu)
+{
+       omap_mmu_write_reg(mmu, 0x1, MMU_FLUSH_ENTRY);
+}
+
+static inline void omap_mmu_ldtlb(struct omap_mmu *mmu)
+{
+       omap_mmu_write_reg(mmu, 0x1, MMU_LD_TLB);
+}
+
+void omap_mmu_read_tlb(struct omap_mmu *mmu, struct omap_mmu_tlb_lock *lock,
+                      struct cam_ram_regset *cr)
+{
+       /* set victim */
+       omap_mmu_set_tlb_lock(mmu, lock);
+
+       if (likely(mmu->ops->read_tlb))
+               mmu->ops->read_tlb(mmu, cr);
+}
+EXPORT_SYMBOL_GPL(omap_mmu_read_tlb);
+
+void omap_mmu_load_tlb(struct omap_mmu *mmu, struct cam_ram_regset *cr)
+{
+       if (likely(mmu->ops->load_tlb))
+               mmu->ops->load_tlb(mmu, cr);
+
+       /* flush the entry */
+       omap_mmu_flush(mmu);
+
+       /* load a TLB entry */
+       omap_mmu_ldtlb(mmu);
+}
+
+int omap_mmu_load_tlb_entry(struct omap_mmu *mmu,
+                           struct omap_mmu_tlb_entry *entry)
+{
+       struct omap_mmu_tlb_lock lock;
+       struct cam_ram_regset *cr;
+
+       clk_enable(mmu->clk);
+       omap_dsp_request_mem();
+
+       omap_mmu_get_tlb_lock(mmu, &lock);
+       for (lock.victim = 0; lock.victim < lock.base; lock.victim++) {
+               struct cam_ram_regset tmp;
+
+               /* read a TLB entry */
+               omap_mmu_read_tlb(mmu, &lock, &tmp);
+               if (!omap_mmu_cam_ram_valid(mmu, &tmp))
+                       goto found_victim;
+       }
+       omap_mmu_set_tlb_lock(mmu, &lock);
+
+found_victim:
+       /* The last entry cannot be locked? */
+       if (lock.victim == (mmu->nr_tlb_entries - 1)) {
+               printk(KERN_ERR "MMU: TLB is full.\n");
+               return -EBUSY;
+       }
+
+       cr = omap_mmu_cam_ram_alloc(mmu, entry);
+       if (IS_ERR(cr))
+               return PTR_ERR(cr);
+
+       omap_mmu_load_tlb(mmu, cr);
+       kfree(cr);
+
+       /* update lock base */
+       if (lock.victim == lock.base)
+               lock.base++;
+
+       omap_mmu_set_tlb_lock(mmu, &lock);
+
+       omap_dsp_release_mem();
+       clk_disable(mmu->clk);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_load_tlb_entry);
+
+static inline unsigned long
+omap_mmu_cam_va(struct omap_mmu *mmu, struct cam_ram_regset *cr)
+{
+       return mmu->ops->cam_va(cr);
+}
+
+int omap_mmu_clear_tlb_entry(struct omap_mmu *mmu, unsigned long vadr)
+{
+       struct omap_mmu_tlb_lock lock;
+       int i;
+       int max_valid = 0;
+
+       clk_enable(mmu->clk);
+       omap_dsp_request_mem();
+
+       omap_mmu_get_tlb_lock(mmu, &lock);
+       for (i = 0; i < lock.base; i++) {
+               struct cam_ram_regset cr;
+
+               /* read a TLB entry */
+               lock.victim = i;
+               omap_mmu_read_tlb(mmu, &lock, &cr);
+               if (!omap_mmu_cam_ram_valid(mmu, &cr))
+                       continue;
+
+               if (omap_mmu_cam_va(mmu, &cr) == vadr)
+                       /* flush the entry */
+                       omap_mmu_flush(mmu);
+               else
+                       max_valid = i;
+       }
+
+       /* set new lock base */
+       lock.base = lock.victim = max_valid + 1;
+       omap_mmu_set_tlb_lock(mmu, &lock);
+
+       omap_dsp_release_mem();
+       clk_disable(mmu->clk);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_clear_tlb_entry);
+
+static void omap_mmu_gflush(struct omap_mmu *mmu)
+{
+       struct omap_mmu_tlb_lock lock;
+
+       clk_enable(mmu->clk);
+       omap_dsp_request_mem();
+
+       omap_mmu_write_reg(mmu, 0x1, MMU_GFLUSH);
+       lock.base = lock.victim = mmu->nr_exmap_preserved;
+       omap_mmu_set_tlb_lock(mmu, &lock);
+
+       omap_dsp_release_mem();
+       clk_disable(mmu->clk);
+}
+
+int omap_mmu_load_pte_entry(struct omap_mmu *mmu,
+                           struct omap_mmu_tlb_entry *entry)
+{
+       int ret = -1;
+       if ((!entry->prsvd) && (mmu->ops->pte_get_attr)) {
+               /*XXX use PG_flag for prsvd */
+               ret = omap_mmu_load_pte(mmu, entry);
+               if (ret)
+                       return ret;
+       }
+       if (entry->tlb)
+               ret = omap_mmu_load_tlb_entry(mmu, entry);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_load_pte_entry);
+
+int omap_mmu_clear_pte_entry(struct omap_mmu *mmu, unsigned long vadr)
+{
+       int ret = omap_mmu_clear_tlb_entry(mmu, vadr);
+       if (ret)
+               return ret;
+       if (mmu->ops->pte_get_attr)
+               omap_mmu_clear_pte(mmu, vadr);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_clear_pte_entry);
+
+/*
+ * omap_mmu_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.
+ */
+int omap_mmu_exmap(struct omap_mmu *mmu, unsigned long dspadr,
+                  unsigned long padr, unsigned long size,
+                  enum exmap_type type)
+{
+       unsigned long pgsz;
+       void *buf;
+       unsigned int order = 0;
+       unsigned long unit;
+       int prev = -1;
+       unsigned long _dspadr = dspadr;
+       unsigned long _padr = padr;
+       void *_vadr = omap_mmu_to_virt(mmu, dspadr);
+       unsigned long _size = size;
+       struct omap_mmu_tlb_entry tlb_ent;
+       struct exmap_tbl *exmap_ent, *tmp_ent;
+       int status;
+       int idx;
+
+#define MINIMUM_PAGESZ SZ_4K
+       /*
+        * alignment check
+        */
+       if (!is_aligned(size, MINIMUM_PAGESZ)) {
+               printk(KERN_ERR
+                      "MMU: size(0x%lx) is not multiple of 4KB.\n", size);
+               return -EINVAL;
+       }
+       if (!is_aligned(dspadr, MINIMUM_PAGESZ)) {
+               printk(KERN_ERR
+                      "MMU: DSP address(0x%lx) is not aligned.\n", dspadr);
+               return -EINVAL;
+       }
+       if (!is_aligned(padr, MINIMUM_PAGESZ)) {
+               printk(KERN_ERR
+                      "MMU: physical address(0x%lx) is not aligned.\n",
+                      padr);
+               return -EINVAL;
+       }
+
+       /* address validity check */
+       if ((dspadr < mmu->memsize) ||
+           (dspadr >= (1 << mmu->addrspace))) {
+               printk(KERN_ERR
+                      "MMU: illegal address/size for %s().\n",
+                      __FUNCTION__);
+               return -EINVAL;
+       }
+
+       down_write(&mmu->exmap_sem);
+
+       /* overlap check */
+       omap_mmu_for_each_tlb_entry(mmu, tmp_ent) {
+               unsigned long mapsize;
+
+               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 "MMU: exmap page overlap!\n");
+                       up_write(&mmu->exmap_sem);
+                       return -EINVAL;
+               }
+       }
+
+start:
+       buf = NULL;
+       /* Are there any free TLB lines?  */
+       for (idx = 0; idx < mmu->nr_tlb_entries; idx++)
+               if (!mmu->exmap_tbl[idx].valid)
+                       goto found_free;
+
+       printk(KERN_ERR "MMU: DSP TLB is full.\n");
+       status = -EBUSY;
+       goto fail;
+
+found_free:
+       exmap_ent = mmu->exmap_tbl + idx;
+
+       if ((_size >= SZ_1M) &&
+           (is_aligned(_padr, SZ_1M) || (padr == 0)) &&
+           is_aligned(_dspadr, SZ_1M)) {
+               unit = SZ_1M;
+               pgsz = OMAP_MMU_CAM_PAGESIZE_1MB;
+       } else if ((_size >= SZ_64K) &&
+                  (is_aligned(_padr, SZ_64K) || (padr == 0)) &&
+                  is_aligned(_dspadr, SZ_64K)) {
+               unit = SZ_64K;
+               pgsz = OMAP_MMU_CAM_PAGESIZE_64KB;
+       } else {
+               unit = SZ_4K;
+               pgsz = OMAP_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(mempool_1M))
+                       buf = mempool_alloc_from_pool(mempool_1M, GFP_KERNEL);
+               else if ((order == ORDER_64KB) && likely(mempool_64K))
+                       buf = mempool_alloc_from_pool(mempool_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 cached.
+        */
+       status = exmap_set_armmmu((unsigned long)_vadr, _padr, unit);
+       if (status < 0)
+               goto fail;
+
+       /* loading DSP PTE entry */
+       INIT_TLB_ENTRY(&tlb_ent, _dspadr, _padr, pgsz);
+       status = omap_mmu_load_pte_entry(mmu, &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)
+               mmu->exmap_tbl[prev].link.next = idx;
+
+       if ((_size -= unit) == 0) {     /* normal completion */
+               up_write(&mmu->exmap_sem);
+               return size;
+       }
+
+       _dspadr += unit;
+       _vadr   += unit;
+       _padr = padr ? _padr + unit : 0;
+       prev = idx;
+       goto start;
+
+fail:
+       up_write(&mmu->exmap_sem);
+       if (buf)
+               omap_mmu_free_pages((unsigned long)buf, order);
+       omap_mmu_exunmap(mmu, dspadr);
+       return status;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_exmap);
+
+static unsigned long unmap_free_arm(struct exmap_tbl *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) {
+               omap_mmu_free_pages((unsigned long)ent->buf, ent->order);
+               printk(KERN_DEBUG
+                      "MMU: freeing 0x%lx bytes @ adr 0x%8p\n",
+                      size, ent->buf);
+       }
+
+       ent->valid = 0;
+       return size;
+}
+
+int omap_mmu_exunmap(struct omap_mmu *mmu, unsigned long dspadr)
+{
+       void *vadr;
+       unsigned long size;
+       int total = 0;
+       struct exmap_tbl *ent;
+       int idx;
+
+       vadr = omap_mmu_to_virt(mmu, dspadr);
+       down_write(&mmu->exmap_sem);
+       for (idx = 0; idx < mmu->nr_tlb_entries; idx++) {
+               ent = mmu->exmap_tbl + idx;
+               if (!ent->valid || ent->prsvd)
+                       continue;
+               if (ent->vadr == vadr)
+                       goto found_map;
+       }
+       up_write(&mmu->exmap_sem);
+       printk(KERN_WARNING
+              "MMU: address %06lx not found in exmap_tbl.\n", dspadr);
+       return -EINVAL;
+
+found_map:
+       if (ent->usecount > 0) {
+               printk(KERN_ERR
+                      "MMU: 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(&mmu->exmap_sem);
+               return -EINVAL;
+       }
+       /* clearing DSP PTE entry */
+       omap_mmu_clear_pte_entry(mmu, dspadr);
+
+       /* clear ARM MMU and free buffer */
+       size = unmap_free_arm(ent);
+       total += size;
+
+       /* we don't free PTEs */
+
+       /* flush TLB */
+       flush_tlb_kernel_range((unsigned long)vadr, (unsigned long)vadr + size);
+
+       /* check if next mapping is in same group */
+       idx = ent->link.next;
+       if (idx < 0)
+               goto up_out;    /* normal completion */
+       ent = mmu->exmap_tbl + idx;
+       dspadr += size;
+       vadr   += size;
+       if (ent->vadr == vadr)
+               goto found_map; /* continue */
+
+       printk(KERN_ERR
+              "MMU: illegal exmap_tbl grouping!\n"
+              "expected vadr = %p, exmap_tbl[%d].vadr = %p\n",
+              vadr, idx, ent->vadr);
+       up_write(&mmu->exmap_sem);
+       return -EINVAL;
+
+up_out:
+       up_write(&mmu->exmap_sem);
+       return total;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_exunmap);
+
+void omap_mmu_exmap_flush(struct omap_mmu *mmu)
+{
+       struct exmap_tbl *ent;
+
+       down_write(&mmu->exmap_sem);
+
+       /* clearing TLB entry */
+       omap_mmu_gflush(mmu);
+
+       omap_mmu_for_each_tlb_entry(mmu, ent)
+               if (ent->valid && !ent->prsvd)
+                       unmap_free_arm(ent);
+
+       /* flush TLB */
+       if (likely(mmu->membase))
+               flush_tlb_kernel_range(mmu->membase + mmu->memsize,
+                                      mmu->membase + (1 << mmu->addrspace));
+
+       up_write(&mmu->exmap_sem);
+}
+EXPORT_SYMBOL_GPL(omap_mmu_exmap_flush);
+
+void exmap_setup_preserved_mem_page(struct omap_mmu *mmu, void *buf,
+                                   unsigned long dspadr, int index)
+{
+       unsigned long phys;
+       void *virt;
+       struct omap_mmu_tlb_entry tlb_ent;
+
+       phys = __pa(buf);
+       virt = omap_mmu_to_virt(mmu, dspadr);
+       exmap_set_armmmu((unsigned long)virt, phys, PAGE_SIZE);
+       INIT_EXMAP_TBL_ENTRY_4KB_PRESERVED(mmu->exmap_tbl + index, buf, virt);
+       INIT_TLB_ENTRY_4KB_PRESERVED(&tlb_ent, dspadr, phys);
+       omap_mmu_load_pte_entry(mmu, &tlb_ent);
+}
+EXPORT_SYMBOL_GPL(exmap_setup_preserved_mem_page);
+
+void exmap_clear_mem_page(struct omap_mmu *mmu, unsigned long dspadr)
+{
+       void *virt = omap_mmu_to_virt(mmu, dspadr);
+
+       exmap_clear_armmmu((unsigned long)virt, PAGE_SIZE);
+       /* DSP MMU is shutting down. not handled here. */
+}
+EXPORT_SYMBOL_GPL(exmap_clear_mem_page);
+
+static void omap_mmu_reset(struct omap_mmu *mmu)
+{
+       int i;
+
+       omap_mmu_write_reg(mmu, 0x2, MMU_SYSCONFIG);
+
+       for (i = 0; i < 10000; i++)
+               if (likely(omap_mmu_read_reg(mmu, MMU_SYSSTATUS) & 0x1))
+                       break;
+}
+
+void omap_mmu_disable(struct omap_mmu *mmu)
+{
+       omap_mmu_write_reg(mmu, 0x00, MMU_CNTL);
+}
+EXPORT_SYMBOL_GPL(omap_mmu_disable);
+
+void omap_mmu_enable(struct omap_mmu *mmu, int reset)
+{
+       u32 val = MMU_CNTL_MMUENABLE;
+       u32 pa = (u32)virt_to_phys(mmu->twl_mm->pgd);
+
+       if (likely(reset))
+               omap_mmu_reset(mmu);
+
+       if (mmu->ops->pte_get_attr) {
+               omap_mmu_write_reg(mmu, pa, MMU_TTB);
+               val |= MMU_CNTL_TWLENABLE;
+       }
+
+       omap_mmu_write_reg(mmu, val, MMU_CNTL);
+}
+EXPORT_SYMBOL_GPL(omap_mmu_enable);
+
+static irqreturn_t omap_mmu_interrupt(int irq, void *dev_id)
+{
+       struct omap_mmu *mmu = dev_id;
+
+       if (likely(mmu->ops->interrupt))
+               mmu->ops->interrupt(mmu);
+
+       return IRQ_HANDLED;
+}
+
+static int omap_mmu_init(struct omap_mmu *mmu)
+{
+       struct omap_mmu_tlb_lock tlb_lock;
+       int ret = 0;
+
+       clk_enable(mmu->clk);
+       omap_dsp_request_mem();
+       down_write(&mmu->exmap_sem);
+
+       ret = request_irq(mmu->irq, omap_mmu_interrupt, IRQF_DISABLED,
+                         mmu->name,  mmu);
+       if (ret < 0) {
+               printk(KERN_ERR
+                      "failed to register MMU interrupt: %d\n", ret);
+               goto fail;
+       }
+
+       omap_mmu_disable(mmu);  /* clear all */
+       udelay(100);
+       omap_mmu_enable(mmu, 1);
+
+       memset(&tlb_lock, 0, sizeof(struct omap_mmu_tlb_lock));
+       omap_mmu_set_tlb_lock(mmu, &tlb_lock);
+
+       if (unlikely(mmu->ops->startup))
+               ret = mmu->ops->startup(mmu);
+ fail:
+       up_write(&mmu->exmap_sem);
+       omap_dsp_release_mem();
+       clk_disable(mmu->clk);
+
+       return ret;
+}
+
+static void omap_mmu_shutdown(struct omap_mmu *mmu)
+{
+       free_irq(mmu->irq, mmu);
+
+       if (unlikely(mmu->ops->shutdown))
+               mmu->ops->shutdown(mmu);
+
+       omap_mmu_exmap_flush(mmu);
+       omap_mmu_disable(mmu); /* clear all */
+}
+
+/*
+ * omap_mmu_mem_enable() / disable()
+ */
+int omap_mmu_mem_enable(struct omap_mmu *mmu, void *addr)
+{
+       if (unlikely(mmu->ops->mem_enable))
+               return mmu->ops->mem_enable(mmu, addr);
+
+       down_read(&mmu->exmap_sem);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_mem_enable);
+
+void omap_mmu_mem_disable(struct omap_mmu *mmu, void *addr)
+{
+       if (unlikely(mmu->ops->mem_disable)) {
+               mmu->ops->mem_disable(mmu, addr);
+               return;
+       }
+
+       up_read(&mmu->exmap_sem);
+}
+EXPORT_SYMBOL_GPL(omap_mmu_mem_disable);
+
+/*
+ * dsp_mem file operations
+ */
+static ssize_t intmem_read(struct omap_mmu *mmu, char *buf, size_t count,
+                          loff_t *ppos)
+{
+       unsigned long p = *ppos;
+       void *vadr = omap_mmu_to_virt(mmu, p);
+       ssize_t size = mmu->memsize;
+       ssize_t read;
+
+       if (p >= size)
+               return 0;
+       clk_enable(mmu->memclk);
+       read = count;
+       if (count > size - p)
+               read = size - p;
+       if (copy_to_user(buf, vadr, read)) {
+               read = -EFAULT;
+               goto out;
+       }
+       *ppos += read;
+out:
+       clk_disable(mmu->memclk);
+       return read;
+}
+
+static ssize_t exmem_read(struct omap_mmu *mmu, char *buf, size_t count,
+                         loff_t *ppos)
+{
+       unsigned long p = *ppos;
+       void *vadr = omap_mmu_to_virt(mmu, p);
+
+       if (!exmap_valid(mmu, vadr, count)) {
+               printk(KERN_ERR
+                      "MMU: DSP address %08lx / size %08x "
+                      "is not valid!\n", p, count);
+               return -EFAULT;
+       }
+       if (count > (1 << mmu->addrspace) - p)
+               count = (1 << mmu->addrspace) - p;
+       if (copy_to_user(buf, vadr, count))
+               return -EFAULT;
+       *ppos += count;
+
+       return count;
+}
+
+static ssize_t omap_mmu_mem_read(struct kobject *kobj, char *buf,
+                                loff_t offset, size_t count)
+{
+       struct device *dev = to_dev(kobj);
+       struct omap_mmu *mmu = dev_get_drvdata(dev);
+       unsigned long p = (unsigned long)offset;
+       void *vadr = omap_mmu_to_virt(mmu, p);
+       int ret;
+
+       if (omap_mmu_mem_enable(mmu, vadr) < 0)
+               return -EBUSY;
+
+       if (p < mmu->memsize)
+               ret = intmem_read(mmu, buf, count, &offset);
+       else
+               ret = exmem_read(mmu, buf, count, &offset);
+
+       omap_mmu_mem_disable(mmu, vadr);
+
+       return ret;
+}
+
+static ssize_t intmem_write(struct omap_mmu *mmu, const char *buf, size_t count,
+                           loff_t *ppos)
+{
+       unsigned long p = *ppos;
+       void *vadr = omap_mmu_to_virt(mmu, p);
+       ssize_t size = mmu->memsize;
+       ssize_t written;
+
+       if (p >= size)
+               return 0;
+       clk_enable(mmu->memclk);
+       written = count;
+       if (count > size - p)
+               written = size - p;
+       if (copy_from_user(vadr, buf, written)) {
+               written = -EFAULT;
+               goto out;
+       }
+       *ppos += written;
+out:
+       clk_disable(mmu->memclk);
+       return written;
+}
+
+static ssize_t exmem_write(struct omap_mmu *mmu, char *buf, size_t count,
+                          loff_t *ppos)
+{
+       unsigned long p = *ppos;
+       void *vadr = omap_mmu_to_virt(mmu, p);
+
+       if (!exmap_valid(mmu, vadr, count)) {
+               printk(KERN_ERR
+                      "MMU: DSP address %08lx / size %08x "
+                      "is not valid!\n", p, count);
+               return -EFAULT;
+       }
+       if (count > (1 << mmu->addrspace) - p)
+               count = (1 << mmu->addrspace) - p;
+       if (copy_from_user(vadr, buf, count))
+               return -EFAULT;
+       *ppos += count;
+
+       return count;
+}
+
+static ssize_t omap_mmu_mem_write(struct kobject *kobj, char *buf,
+                                 loff_t offset, size_t count)
+{
+       struct device *dev = to_dev(kobj);
+       struct omap_mmu *mmu = dev_get_drvdata(dev);
+       unsigned long p = (unsigned long)offset;
+       void *vadr = omap_mmu_to_virt(mmu, p);
+       int ret;
+
+       if (omap_mmu_mem_enable(mmu, vadr) < 0)
+               return -EBUSY;
+
+       if (p < mmu->memsize)
+               ret = intmem_write(mmu, buf, count, &offset);
+       else
+               ret = exmem_write(mmu, buf, count, &offset);
+
+       omap_mmu_mem_disable(mmu, vadr);
+
+       return ret;
+}
+
+static struct bin_attribute dev_attr_mem = {
+       .attr   = {
+               .name   = "mem",
+               .owner  = THIS_MODULE,
+               .mode   = S_IRUSR | S_IWUSR | S_IRGRP,
+       },
+
+       .read   = omap_mmu_mem_read,
+       .write  = omap_mmu_mem_write,
+};
+
+/* To be obsolete for backward compatibility */
+ssize_t __omap_mmu_mem_read(struct omap_mmu *mmu, char *buf,
+                           loff_t offset, size_t count)
+{
+       return omap_mmu_mem_read(&mmu->dev.kobj, buf, offset, count);
+}
+EXPORT_SYMBOL_GPL(__omap_mmu_mem_read);
+
+ssize_t __omap_mmu_mem_write(struct omap_mmu *mmu, char *buf,
+                            loff_t offset, size_t count)
+{
+       return omap_mmu_mem_write(&mmu->dev.kobj, buf, offset, count);
+}
+EXPORT_SYMBOL_GPL(__omap_mmu_mem_write);
+
+/*
+ * sysfs files
+ */
+static ssize_t omap_mmu_show(struct device *dev, struct device_attribute *attr,
+                            char *buf)
+{
+       struct omap_mmu *mmu = dev_get_drvdata(dev);
+       struct omap_mmu_tlb_lock tlb_lock;
+       int ret = -EIO;
+
+       clk_enable(mmu->clk);
+       omap_dsp_request_mem();
+
+       down_read(&mmu->exmap_sem);
+
+       omap_mmu_get_tlb_lock(mmu, &tlb_lock);
+
+       if (likely(mmu->ops->show))
+               ret = mmu->ops->show(mmu, buf, &tlb_lock);
+
+       /* restore victim entry */
+       omap_mmu_set_tlb_lock(mmu, &tlb_lock);
+
+       up_read(&mmu->exmap_sem);
+       omap_dsp_release_mem();
+       clk_disable(mmu->clk);
+
+       return ret;
+}
+
+static DEVICE_ATTR(mmu, S_IRUGO, omap_mmu_show, NULL);
+
+static ssize_t exmap_show(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       struct omap_mmu *mmu = dev_get_drvdata(dev);
+       struct exmap_tbl *ent;
+       int len;
+       int i = 0;
+
+       down_read(&mmu->exmap_sem);
+       len = sprintf(buf, "  dspadr     size         buf     size uc\n");
+                        /* 0x300000 0x123000  0xc0171000 0x100000  0*/
+
+       omap_mmu_for_each_tlb_entry(mmu, ent) {
+               void *vadr;
+               unsigned long size;
+               enum exmap_type 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 = mmu->exmap_tbl + idx;
+                       size += PAGE_SIZE << ent->order;
+               } while ((idx = ent->link.next) >= 0);
+
+               len += sprintf(buf + len, "0x%06lx %#8lx",
+                              virt_to_omap_mmu(mmu, vadr), size);
+
+               if (type == EXMAP_TYPE_FB) {
+                       len += sprintf(buf + len, "    framebuf\n");
+               } else {
+                       len += sprintf(buf + len, "\n");
+                       idx = i;
+                       do {
+                               ent = mmu->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);
+               }
+
+               i++;
+       }
+
+       up_read(&mmu->exmap_sem);
+       return len;
+}
+
+static ssize_t exmap_store(struct device *dev, struct device_attribute *attr,
+                          const char *buf,
+                          size_t count)
+{
+       struct omap_mmu *mmu = dev_get_drvdata(dev);
+       unsigned long base = 0, len = 0;
+       int ret;
+
+       sscanf(buf, "%lx %lx", &base, &len);
+
+       if (!base)
+               return -EINVAL;
+
+       if (len) {
+               /* Add the mapping */
+               ret = omap_mmu_exmap(mmu, base, 0, len, EXMAP_TYPE_MEM);
+               if (ret < 0)
+                       return ret;
+       } else {
+               /* Remove the mapping */
+               ret = omap_mmu_exunmap(mmu, base);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return count;
+}
+
+static DEVICE_ATTR(exmap, S_IRUGO | S_IWUSR, exmap_show, exmap_store);
+
+static ssize_t mempool_show(struct class *class, 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(mempool_1M)) {
+               min_nr_1M  = mempool_1M->min_nr;
+               curr_nr_1M = mempool_1M->curr_nr;
+               total += min_nr_1M * SZ_1M;
+       }
+       if (likely(mempool_64K)) {
+               min_nr_64K  = mempool_64K->min_nr;
+               curr_nr_64K = mempool_64K->curr_nr;
+               total += min_nr_64K * SZ_64K;
+       }
+
+       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);
+}
+
+
+static CLASS_ATTR(mempool, S_IRUGO, mempool_show, NULL);
+
+static void omap_mmu_class_dev_release(struct device *dev)
+{
+}
+
+static struct class omap_mmu_class = {
+       .name           = "mmu",
+       .dev_release    = omap_mmu_class_dev_release,
+};
+
+int omap_mmu_register(struct omap_mmu *mmu)
+{
+       int ret;
+
+       mmu->dev.class = &omap_mmu_class;
+       strlcpy(mmu->dev.bus_id, mmu->name, KOBJ_NAME_LEN);
+       dev_set_drvdata(&mmu->dev, mmu);
+
+       mmu->exmap_tbl = kzalloc(sizeof(struct exmap_tbl) * mmu->nr_tlb_entries,
+                                GFP_KERNEL);
+       if (!mmu->exmap_tbl)
+               return -ENOMEM;
+
+       if (mmu->ops->pte_get_attr) {
+               struct mm_struct *mm =  mm_alloc();
+               if (!mm) {
+                       ret = -ENOMEM;
+                       goto err_mm_alloc;
+               }
+               mmu->twl_mm = mm;
+       }
+
+       ret = device_register(&mmu->dev);
+       if (unlikely(ret))
+               goto err_dev_register;
+
+       init_rwsem(&mmu->exmap_sem);
+
+       ret = omap_mmu_read_reg(mmu, MMU_REVISION);
+       printk(KERN_NOTICE "MMU: OMAP %s MMU initialized (HW v%d.%d)\n",
+              mmu->name, (ret >> 4) & 0xf, ret & 0xf);
+
+       ret = omap_mmu_init(mmu);
+       if (unlikely(ret))
+               goto err_mmu_init;
+
+       ret = device_create_file(&mmu->dev, &dev_attr_mmu);
+       if (unlikely(ret))
+               goto err_dev_create_mmu;
+       ret = device_create_file(&mmu->dev, &dev_attr_exmap);
+       if (unlikely(ret))
+               goto err_dev_create_exmap;
+
+       if (likely(mmu->membase)) {
+               dev_attr_mem.size = mmu->memsize;
+               ret = device_create_bin_file(&mmu->dev,
+                                            &dev_attr_mem);
+               if (unlikely(ret))
+                       goto err_bin_create_mem;
+       }
+
+       return 0;
+
+err_bin_create_mem:
+       device_remove_file(&mmu->dev, &dev_attr_exmap);
+err_dev_create_exmap:
+       device_remove_file(&mmu->dev, &dev_attr_mmu);
+err_dev_create_mmu:
+       omap_mmu_shutdown(mmu);
+err_mmu_init:
+       device_unregister(&mmu->dev);
+err_dev_register:
+       kfree(mmu->twl_mm);
+       mmu->twl_mm = NULL;
+err_mm_alloc:
+       kfree(mmu->exmap_tbl);
+       mmu->exmap_tbl = NULL;
+       return ret;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_register);
+
+void omap_mmu_unregister(struct omap_mmu *mmu)
+{
+       omap_mmu_shutdown(mmu);
+       omap_mmu_kmem_release();
+
+       device_remove_file(&mmu->dev, &dev_attr_mmu);
+       device_remove_file(&mmu->dev, &dev_attr_exmap);
+
+       if (likely(mmu->membase))
+               device_remove_bin_file(&mmu->dev,
+                                            &dev_attr_mem);
+
+       kfree(mmu->exmap_tbl);
+       mmu->exmap_tbl = NULL;
+
+       if (mmu->ops->pte_get_attr) {
+               if (mmu->twl_mm) {
+                       __mmdrop(mmu->twl_mm);
+                       mmu->twl_mm = NULL;
+               }
+       }
+
+       device_unregister(&mmu->dev);
+}
+EXPORT_SYMBOL_GPL(omap_mmu_unregister);
+
+static int __init omap_mmu_class_init(void)
+{
+       int ret = class_register(&omap_mmu_class);
+       if (!ret)
+               ret = class_create_file(&omap_mmu_class, &class_attr_mempool);
+
+       return ret;
+}
+
+static void __exit omap_mmu_class_exit(void)
+{
+       class_remove_file(&omap_mmu_class, &class_attr_mempool);
+       class_unregister(&omap_mmu_class);
+}
+
+subsys_initcall(omap_mmu_class_init);
+module_exit(omap_mmu_class_exit);
+
+MODULE_LICENSE("GPL");
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..aed89da
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * 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, NULL,
+                                        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 050323fd79e9ae78f4f528ce260e08a8ec89f38b..abb0e2771d95dc7eaec31ee5f2f2774f0c6184ee 100644 (file)
@@ -84,4 +84,6 @@ source "drivers/auxdisplay/Kconfig"
 
 source "drivers/kvm/Kconfig"
 
+source "drivers/ssi/Kconfig"
+
 endmenu
index 7fe5da8f323770af6853b0fc54ff655e9e1228ef..55a613a2154796d607e4c3f29e1606bb58652024 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-$(CONFIG_I2C)              += i2c/
+obj-y                          += cbus/
 obj-$(CONFIG_NUBUS)            += nubus/
 obj-$(CONFIG_ATM)              += atm/
 obj-y                          += macintosh/
@@ -51,14 +56,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-y                          += i2c/
 obj-$(CONFIG_W1)               += w1/
 obj-$(CONFIG_HWMON)            += hwmon/
 obj-$(CONFIG_PHONE)            += telephony/
index b9fbe6e7f9ae6e6fd9da5e78990efd5e87229bc4..2e8ac693d80504ae74e74a9eff25f8d606aa07e5 100644 (file)
@@ -147,6 +147,27 @@ 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_HCIH4P
+       tristate "HCI driver with H4 Nokia extensions"
+       depends on BT && ARCH_OMAP 
+       help 
+         Bluetooth HCI driver with H4 extensions.  This driver provides
+         support for H4+ Bluetooth chip with vendor-specific H4 extensions.
+
+         Say Y here to compile support for h4 extended devices into the kernel
+         or say M to compile it as module (hci_h4p).
+
 config BT_HCIVHCI
        tristate "HCI VHCI (Virtual HCI device) driver"
        help
index 08c10e178e02400fd3aae0027943a94b6c91daea..d5a449d0c36bf12c6b6a188a872d61318498be1b 100644 (file)
@@ -12,6 +12,8 @@ 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
+obj-$(CONFIG_BT_HCIH4P)                += hci_h4p/
 
 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 */
diff --git a/drivers/bluetooth/hci_h4p/Makefile b/drivers/bluetooth/hci_h4p/Makefile
new file mode 100644 (file)
index 0000000..07608a4
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile for the Linux Bluetooth HCI device drivers.
+#
+
+obj-$(CONFIG_BT_HCIH4P)                += hci_h4p.o
+
+hci_h4p-objs := core.o fw.o uart.o sysfs.o fw-ti.o fw-csr.o
diff --git a/drivers/bluetooth/hci_h4p/core.c b/drivers/bluetooth/hci_h4p/core.c
new file mode 100644 (file)
index 0000000..09c1f93
--- /dev/null
@@ -0,0 +1,1007 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: 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
+ * 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/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/timer.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/board.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/pm.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+
+#include "hci_h4p.h"
+
+#define PM_TIMEOUT 200
+
+/* This should be used in function that cannot release clocks */
+static void hci_h4p_set_clk(struct hci_h4p_info *info, int *clock, int enable)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&info->clocks_lock, flags);
+       if (enable && !*clock) {
+               NBT_DBG_POWER("Enabling %p\n", clock);
+               clk_enable(info->uart_fclk);
+#ifdef CONFIG_ARCH_OMAP2
+               if (cpu_is_omap24xx()) {
+                       clk_enable(info->uart_iclk);
+                       omap2_block_sleep();
+               }
+#endif
+       }
+       if (!enable && *clock) {
+               NBT_DBG_POWER("Disabling %p\n", clock);
+               clk_disable(info->uart_fclk);
+#ifdef CONFIG_ARCH_OMAP2
+               if (cpu_is_omap24xx()) {
+                       clk_disable(info->uart_iclk);
+                       omap2_allow_sleep();
+               }
+#endif
+       }
+
+       *clock = enable;
+       spin_unlock_irqrestore(&info->clocks_lock, flags);
+}
+
+/* Power management functions */
+static void hci_h4p_disable_tx(struct hci_h4p_info *info)
+{
+       NBT_DBG_POWER("\n");
+
+       if (!info->pm_enabled)
+               return;
+
+       mod_timer(&info->tx_pm_timer, jiffies + msecs_to_jiffies(PM_TIMEOUT));
+}
+
+static void hci_h4p_enable_tx(struct hci_h4p_info *info)
+{
+       NBT_DBG_POWER("\n");
+
+       if (!info->pm_enabled)
+               return;
+
+       del_timer_sync(&info->tx_pm_timer);
+       if (info->tx_pm_enabled) {
+               info->tx_pm_enabled = 0;
+               hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+               omap_set_gpio_dataout(info->bt_wakeup_gpio, 1);
+       }
+}
+
+static void hci_h4p_tx_pm_timer(unsigned long data)
+{
+       struct hci_h4p_info *info;
+
+       NBT_DBG_POWER("\n");
+
+       info = (struct hci_h4p_info *)data;
+
+       if (hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT) {
+               omap_set_gpio_dataout(info->bt_wakeup_gpio, 0);
+               hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+               info->tx_pm_enabled = 1;
+       }
+       else {
+               mod_timer(&info->tx_pm_timer, jiffies + msecs_to_jiffies(PM_TIMEOUT));
+       }
+}
+
+static void hci_h4p_disable_rx(struct hci_h4p_info *info)
+{
+       if (!info->pm_enabled)
+               return;
+
+       mod_timer(&info->rx_pm_timer, jiffies + msecs_to_jiffies(PM_TIMEOUT));
+}
+
+static void hci_h4p_enable_rx(struct hci_h4p_info *info)
+{
+       unsigned long flags;
+
+       if (!info->pm_enabled)
+               return;
+
+       del_timer_sync(&info->rx_pm_timer);
+       spin_lock_irqsave(&info->lock, flags);
+       if (info->rx_pm_enabled) {
+               hci_h4p_set_clk(info, &info->rx_clocks_en, 1);
+               hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) | UART_IER_RDI);
+               hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
+               info->rx_pm_enabled = 0;
+       }
+       spin_unlock_irqrestore(&info->lock, flags);
+}
+
+static void hci_h4p_rx_pm_timer(unsigned long data)
+{
+       unsigned long flags;
+       struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+
+       spin_lock_irqsave(&info->lock, flags);
+       if (!(hci_h4p_inb(info, UART_LSR) & UART_LSR_DR)) {
+               hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
+               hci_h4p_set_rts(info, 0);
+               hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) & ~UART_IER_RDI);
+               hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+               info->rx_pm_enabled = 1;
+       }
+       else {
+               mod_timer(&info->rx_pm_timer, jiffies + msecs_to_jiffies(PM_TIMEOUT));
+       }
+       spin_unlock_irqrestore(&info->lock, flags);
+}
+
+/* Negotiation functions */
+int hci_h4p_send_alive_packet(struct hci_h4p_info *info)
+{
+       NBT_DBG("Sending alive packet\n");
+
+       if (!info->alive_cmd_skb)
+               return -EINVAL;
+
+       /* Keep reference to buffer so we can reuse it */
+       info->alive_cmd_skb = skb_get(info->alive_cmd_skb);
+
+       skb_queue_tail(&info->txq, info->alive_cmd_skb);
+       tasklet_schedule(&info->tx_task);
+
+       NBT_DBG("Alive packet sent\n");
+
+       return 0;
+}
+
+static void hci_h4p_alive_packet(struct hci_h4p_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 hci_h4p_send_negotiation(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+       NBT_DBG("Sending negotiation..\n");
+
+       hci_h4p_change_speed(info, INIT_SPEED);
+
+       info->init_error = 0;
+       init_completion(&info->init_completion);
+       skb_queue_tail(&info->txq, skb);
+       tasklet_schedule(&info->tx_task);
+
+       if (!wait_for_completion_interruptible_timeout(&info->init_completion,
+                               msecs_to_jiffies(1000))) 
+               return -ETIMEDOUT;
+
+       NBT_DBG("Negotiation sent\n");
+       return info->init_error;
+}
+
+static void hci_h4p_negotiation_packet(struct hci_h4p_info *info,
+                                      struct sk_buff *skb)
+{
+       int err = 0;
+
+       if (skb->data[1] == 0x20) {
+               /* Change to operational settings */
+               hci_h4p_set_rts(info, 0);
+
+               err = hci_h4p_wait_for_cts(info, 0, 100);
+               if (err < 0)
+                       goto neg_ret;
+
+               hci_h4p_change_speed(info, MAX_BAUD_RATE);
+               hci_h4p_set_rts(info, 1);
+
+               err = hci_h4p_wait_for_cts(info, 1, 100);
+               if (err < 0)
+                       goto neg_ret;
+
+               hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_CTS | UART_EFR_RTS);
+
+               err = hci_h4p_send_alive_packet(info);
+               if (err < 0)
+                       goto neg_ret;
+       } else {
+               dev_err(info->dev, "Could not negotiate hci_h4p settings\n");
+               err = -EINVAL;
+               goto neg_ret;
+       }
+
+       kfree_skb(skb);
+       return;
+
+neg_ret:
+       complete(&info->init_completion);
+       info->init_error = err;
+       kfree_skb(skb);
+}
+
+/* H4 packet handling functions */
+static int hci_h4p_get_hdr_len(struct hci_h4p_info *info, 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 = 11;
+               break;
+       case H4_ALIVE_PKT:
+               retval = 3;
+               break;
+       default:
+               dev_err(info->dev, "Unknown H4 packet type 0x%.2x\n", pkt_type);
+               retval = -1;
+               break;
+       }
+
+       return retval;
+}
+
+static unsigned int hci_h4p_get_data_len(struct hci_h4p_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 inline void hci_h4p_recv_frame(struct hci_h4p_info *info,
+                                     struct sk_buff *skb)
+{
+
+       if (unlikely(!test_bit(HCI_RUNNING, &info->hdev->flags))) {
+               NBT_DBG("fw_event\n");
+               hci_h4p_parse_fw_event(info, skb);
+       } else {
+               hci_recv_frame(skb);
+               NBT_DBG("Frame sent to upper layer\n");
+       }
+}
+
+static void hci_h4p_rx_tasklet(unsigned long data)
+{
+       u8 byte;
+       unsigned long flags;
+       struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+
+       NBT_DBG("tasklet woke up\n");
+       NBT_DBG_TRANSFER("rx_tasklet woke up\ndata ");
+
+       while (hci_h4p_inb(info, UART_LSR) & UART_LSR_DR) {
+               byte = hci_h4p_inb(info, UART_RX);
+               if (info->garbage_bytes) {
+                       info->garbage_bytes--;
+                       continue;
+               }
+               if (info->rx_skb == NULL) {
+                       info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC | GFP_DMA);
+                       if (!info->rx_skb) {
+                               dev_err(info->dev, "Can't allocate memory for new packet\n");
+                               goto finish_task;
+                       }
+                       info->rx_state = WAIT_FOR_PKT_TYPE;
+                       info->rx_skb->dev = (void *)info->hdev;
+               }
+               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 = hci_h4p_get_hdr_len(info, byte);
+                       if (info->rx_count < 0) {
+                               info->hdev->stat.err_rx++;
+                               kfree_skb(info->rx_skb);
+                               info->rx_skb = NULL;
+                       } else {
+                               info->rx_state = WAIT_FOR_HEADER;
+                       }
+                       break;
+               case WAIT_FOR_HEADER:
+                       info->rx_count--;
+                       *skb_put(info->rx_skb, 1) = byte;
+                       if (info->rx_count == 0) {
+                               info->rx_count = hci_h4p_get_data_len(info, info->rx_skb);
+                               if (info->rx_count > skb_tailroom(info->rx_skb)) {
+                                       dev_err(info->dev, "Frame is %ld bytes too long.\n",
+                                              info->rx_count - skb_tailroom(info->rx_skb));
+                                       kfree_skb(info->rx_skb);
+                                       info->rx_skb = NULL;
+                                       info->garbage_bytes = info->rx_count - skb_tailroom(info->rx_skb);
+                                       break;
+                               }
+                               info->rx_state = WAIT_FOR_DATA;
+
+                               if (bt_cb(info->rx_skb)->pkt_type == H4_NEG_PKT) {
+                                       hci_h4p_negotiation_packet(info, info->rx_skb);
+                                       info->rx_skb = NULL;
+                                       info->rx_state = WAIT_FOR_PKT_TYPE;
+                                       goto finish_task;
+                               }
+                               if (bt_cb(info->rx_skb)->pkt_type == H4_ALIVE_PKT) {
+                                       hci_h4p_alive_packet(info, info->rx_skb);
+                                       info->rx_skb = NULL;
+                                       info->rx_state = WAIT_FOR_PKT_TYPE;
+                                       goto finish_task;
+                               }
+                       }
+                       break;
+               case WAIT_FOR_DATA:
+                       info->rx_count--;
+                       *skb_put(info->rx_skb, 1) = byte;
+                       if (info->rx_count == 0) {
+                               /* H4+ devices should allways send word aligned packets */
+                               if (!(info->rx_skb->len % 2)) {
+                                       info->garbage_bytes++;
+                               }
+                               hci_h4p_recv_frame(info, info->rx_skb);
+                               info->rx_skb = NULL;
+                       }
+                       break;
+               default:
+                       WARN_ON(1);
+                       break;
+               }
+       }
+
+finish_task:
+       spin_lock_irqsave(&info->lock, flags);
+       hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) | UART_IER_RDI);
+       spin_unlock_irqrestore(&info->lock, flags);
+
+       NBT_DBG_TRANSFER_NF("\n");
+       NBT_DBG("rx_ended\n");
+}
+
+static void hci_h4p_tx_tasklet(unsigned long data)
+{
+       unsigned int sent = 0;
+       unsigned long flags;
+       struct sk_buff *skb;
+       struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+
+       NBT_DBG("tasklet woke up\n");
+       NBT_DBG_TRANSFER("tx_tasklet woke up\n data ");
+
+       skb = skb_dequeue(&info->txq);
+       if (!skb) {
+               /* No data in buffer */
+               NBT_DBG("skb ready\n");
+               hci_h4p_disable_tx(info);
+               return;
+       }
+
+       /* Copy data to tx fifo */
+       while (!(hci_h4p_inb(info, UART_OMAP_SSR) & UART_OMAP_SSR_TXFULL) &&
+              (sent < skb->len)) {
+               NBT_DBG_TRANSFER_NF("0x%.2x ", skb->data[sent]);
+               hci_h4p_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);
+       } else {
+               skb_pull(skb, sent);
+               skb_queue_head(&info->txq, skb);
+       }
+
+       spin_lock_irqsave(&info->lock, flags);
+       hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) | UART_IER_THRI);
+       spin_unlock_irqrestore(&info->lock, flags);
+}
+
+static irqreturn_t hci_h4p_interrupt(int irq, void *data)
+{
+       struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+       u8 iir, msr;
+       int ret;
+       unsigned long flags;
+
+       ret = IRQ_NONE;
+
+       iir = hci_h4p_inb(info, UART_IIR);
+       if (iir & UART_IIR_NO_INT) {
+               dev_err(info->dev, "Interrupt but no reason irq 0x%.2x\n", iir);
+               return IRQ_HANDLED;
+       }
+
+       NBT_DBG("In interrupt handler iir 0x%.2x\n", iir);
+
+       iir &= UART_IIR_ID;
+
+       if (iir == UART_IIR_MSI) {
+               msr = hci_h4p_inb(info, UART_MSR);
+               ret = IRQ_HANDLED;
+       }
+       if (iir == UART_IIR_RLSI) {
+               hci_h4p_inb(info, UART_RX);
+               hci_h4p_inb(info, UART_LSR);
+               ret = IRQ_HANDLED;
+       }
+
+       if (iir == UART_IIR_RDI) {
+               spin_lock_irqsave(&info->lock, flags);
+               hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) & ~UART_IER_RDI);
+               spin_unlock_irqrestore(&info->lock, flags);
+               tasklet_schedule(&info->rx_task);
+               ret = IRQ_HANDLED;
+       }
+
+       if (iir == UART_IIR_THRI) {
+               spin_lock_irqsave(&info->lock, flags);
+               hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) & ~UART_IER_THRI);
+               spin_unlock_irqrestore(&info->lock, flags);
+               tasklet_schedule(&info->tx_task);
+               ret = IRQ_HANDLED;
+       }
+
+
+       return ret;
+}
+
+static irqreturn_t hci_h4p_wakeup_interrupt(int irq, void *dev_inst)
+{
+       struct hci_h4p_info *info = dev_inst;
+       int should_wakeup;
+       struct hci_dev *hdev;
+
+       if (!info->hdev)
+               return IRQ_HANDLED;
+
+       hdev = info->hdev;
+
+       if (!test_bit(HCI_RUNNING, &hdev->flags))
+               return IRQ_HANDLED;
+
+       should_wakeup = omap_get_gpio_datain(info->host_wakeup_gpio);
+       NBT_DBG_POWER("gpio interrupt %d\n", should_wakeup);
+       if (should_wakeup) {
+               hci_h4p_enable_rx(info);
+       } else {
+               hci_h4p_disable_rx(info);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int hci_h4p_reset(struct hci_h4p_info *info)
+{
+       int err;
+
+       hci_h4p_init_uart(info);
+       hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_CTS | UART_EFR_RTS);
+       hci_h4p_set_rts(info, 0);
+
+       omap_set_gpio_dataout(info->reset_gpio, 0);
+       msleep(100);
+       omap_set_gpio_dataout(info->bt_wakeup_gpio, 1);
+       omap_set_gpio_dataout(info->reset_gpio, 1);
+       msleep(100);
+
+       err = hci_h4p_wait_for_cts(info, 1, 10);
+       if (err < 0) {
+               dev_err(info->dev, "No cts from bt chip\n");
+               return err;
+       }
+
+       hci_h4p_set_rts(info, 1);
+
+       return 0;
+}
+
+/* hci callback functions */
+static int hci_h4p_hci_flush(struct hci_dev *hdev)
+{
+       struct hci_h4p_info *info;
+       info = hdev->driver_data;
+
+       skb_queue_purge(&info->txq);
+
+       return 0;
+}
+
+static int hci_h4p_hci_open(struct hci_dev *hdev)
+{
+       struct hci_h4p_info *info;
+       int err;
+       struct sk_buff *neg_cmd_skb;
+       struct sk_buff_head fw_queue;
+
+       info = hdev->driver_data;
+
+       if (test_bit(HCI_RUNNING, &hdev->flags))
+               return 0;
+
+       skb_queue_head_init(&fw_queue);
+       err = hci_h4p_read_fw(info, &fw_queue);
+       if (err < 0) {
+               dev_err(info->dev, "Cannot read firmware\n");
+               return err;
+       }
+       neg_cmd_skb = skb_dequeue(&fw_queue);
+       if (!neg_cmd_skb) {
+               err = -EPROTO;
+               goto err_clean;
+       }
+       info->alive_cmd_skb = skb_dequeue(&fw_queue);
+       if (!info->alive_cmd_skb) {
+               err = -EPROTO;
+               goto err_clean;
+       }
+
+       hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+       hci_h4p_set_clk(info, &info->rx_clocks_en, 1);
+
+       tasklet_enable(&info->tx_task);
+       tasklet_enable(&info->rx_task);
+       info->rx_state = WAIT_FOR_PKT_TYPE;
+       info->rx_count = 0;
+       info->garbage_bytes = 0;
+       info->rx_skb = NULL;
+       info->pm_enabled = 0;
+       init_completion(&info->fw_completion);
+
+       err = hci_h4p_reset(info);
+       if (err < 0)
+               goto err_clean;
+
+       err = hci_h4p_send_negotiation(info, neg_cmd_skb);
+       neg_cmd_skb = NULL;
+       if (err < 0)
+               goto err_clean;
+
+       hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_CTS | UART_EFR_RTS);
+
+       err = hci_h4p_send_fw(info, &fw_queue);
+       if (err < 0) {
+               dev_err(info->dev, "Sending firmware failed.\n");
+               goto err_clean;
+       }
+
+       kfree_skb(info->alive_cmd_skb);
+       info->alive_cmd_skb = NULL;
+       info->pm_enabled = 1;
+       info->tx_pm_enabled = 1;
+       info->rx_pm_enabled = 0;
+       set_bit(HCI_RUNNING, &hdev->flags);
+
+       NBT_DBG("hci up and running\n");
+       return 0;
+
+err_clean:
+       hci_h4p_hci_flush(hdev);
+       tasklet_disable(&info->tx_task);
+       tasklet_disable(&info->rx_task);
+       hci_h4p_reset_uart(info);
+       hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+       hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+       omap_set_gpio_dataout(info->reset_gpio, 0);
+       omap_set_gpio_dataout(info->bt_wakeup_gpio, 0);
+       skb_queue_purge(&fw_queue);
+       kfree_skb(neg_cmd_skb);
+       neg_cmd_skb = NULL;
+       kfree_skb(info->alive_cmd_skb);
+       info->alive_cmd_skb = NULL;
+       kfree_skb(info->rx_skb);
+
+       return err;
+}
+
+static int hci_h4p_hci_close(struct hci_dev *hdev)
+{
+       struct hci_h4p_info *info = hdev->driver_data;
+
+       if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+               return 0;
+
+       hci_h4p_hci_flush(hdev);
+       del_timer_sync(&info->tx_pm_timer);
+       del_timer_sync(&info->rx_pm_timer);
+       tasklet_disable(&info->tx_task);
+       tasklet_disable(&info->rx_task);
+       hci_h4p_reset_uart(info);
+       hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+       hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+       omap_set_gpio_dataout(info->reset_gpio, 0);
+       omap_set_gpio_dataout(info->bt_wakeup_gpio, 0);
+       kfree_skb(info->rx_skb);
+
+       return 0;
+}
+
+static void hci_h4p_hci_destruct(struct hci_dev *hdev)
+{
+}
+
+static int hci_h4p_hci_send_frame(struct sk_buff *skb)
+{
+       struct hci_h4p_info *info;
+       struct hci_dev *hdev = (struct hci_dev *)skb->dev;
+       int err = 0;
+
+       if (!hdev) {
+               printk(KERN_WARNING "hci_h4p: Frame for unknown device\n");
+               return -ENODEV;
+       }
+
+       NBT_DBG("dev %p, skb %p\n", hdev, skb);
+
+       info = hdev->driver_data;
+
+       if (!test_bit(HCI_RUNNING, &hdev->flags)) {
+               dev_warn(info->dev, "Frame for non-running device\n");
+               return -EIO;
+       }
+
+       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 */
+       *skb_push(skb, 1) = (bt_cb(skb)->pkt_type);
+       /* We should allways send word aligned data to h4+ devices */
+       if (skb->len % 2) {
+               err = skb_pad(skb, 1);
+       }
+       if (err)
+               return err;
+
+       hci_h4p_enable_tx(info);
+       skb_queue_tail(&info->txq, skb);
+       tasklet_schedule(&info->tx_task);
+
+       return 0;
+}
+
+static int hci_h4p_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
+{
+       return -ENOIOCTLCMD;
+}
+
+static int hci_h4p_register_hdev(struct hci_h4p_info *info)
+{
+       struct hci_dev *hdev;
+
+       /* Initialize and register HCI device */
+
+       hdev = hci_alloc_dev();
+       if (!hdev) {
+               dev_err(info->dev, "Can't allocate memory for device\n");
+               return -ENOMEM;
+       }
+       info->hdev = hdev;
+
+       hdev->type = HCI_UART;
+       hdev->driver_data = info;
+
+       hdev->open = hci_h4p_hci_open;
+       hdev->close = hci_h4p_hci_close;
+       hdev->flush = hci_h4p_hci_flush;
+       hdev->send = hci_h4p_hci_send_frame;
+       hdev->destruct = hci_h4p_hci_destruct;
+       hdev->ioctl = hci_h4p_hci_ioctl;
+
+       hdev->owner = THIS_MODULE;
+
+       if (hci_register_dev(hdev) < 0) {
+               dev_err(info->dev, "hci_h4p: Can't register HCI device %s.\n", hdev->name);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int hci_h4p_probe(struct platform_device *pdev)
+{
+       struct omap_bluetooth_config *bt_config;
+       struct hci_h4p_info *info;
+       int irq, err;
+
+       dev_info(&pdev->dev, "Registering HCI H4P device\n");
+       info = kzalloc(sizeof(struct hci_h4p_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       info->dev = &pdev->dev;
+       info->pm_enabled = 0;
+       info->tx_pm_enabled = 0;
+       info->rx_pm_enabled = 0;
+       info->garbage_bytes = 0;
+       info->tx_clocks_en = 0;
+       info->rx_clocks_en = 0;
+       tasklet_init(&info->tx_task, hci_h4p_tx_tasklet, (unsigned long)info);
+       tasklet_init(&info->rx_task, hci_h4p_rx_tasklet, (unsigned long)info);
+       /* hci_h4p_hci_open assumes that tasklet is disabled in startup */
+       tasklet_disable(&info->tx_task);
+       tasklet_disable(&info->rx_task);
+       spin_lock_init(&info->lock);
+       spin_lock_init(&info->clocks_lock);
+       skb_queue_head_init(&info->txq);
+       init_timer(&info->tx_pm_timer);
+       info->tx_pm_timer.function = hci_h4p_tx_pm_timer;
+       info->tx_pm_timer.data = (unsigned long)info;
+       init_timer(&info->rx_pm_timer);
+       info->rx_pm_timer.function = hci_h4p_rx_pm_timer;
+       info->rx_pm_timer.data = (unsigned long)info;
+
+       if (pdev->dev.platform_data == NULL) {
+               dev_err(&pdev->dev, "Could not get Bluetooth config data\n");
+               return -ENODATA;
+       }
+
+       bt_config = pdev->dev.platform_data;
+       info->chip_type = bt_config->chip_type;
+       info->bt_wakeup_gpio = bt_config->bt_wakeup_gpio;
+       info->host_wakeup_gpio = bt_config->host_wakeup_gpio;
+       info->reset_gpio = bt_config->reset_gpio;
+       info->bt_sysclk = bt_config->bt_sysclk;
+
+       NBT_DBG("RESET gpio: %d\n", info->reset_gpio);
+       NBT_DBG("BTWU gpio: %d\n", info->bt_wakeup_gpio);
+       NBT_DBG("HOSTWU gpio: %d\n", info->host_wakeup_gpio);
+       NBT_DBG("Uart: %d\n", bt_config->bt_uart);
+       NBT_DBG("sysclk: %d\n", info->bt_sysclk);
+
+       err = omap_request_gpio(info->reset_gpio);
+       if (err < 0) {
+               dev_err(&pdev->dev, "Cannot get GPIO line %d\n",
+                       info->reset_gpio);
+               kfree(info);
+               goto cleanup;
+       }
+
+       err = omap_request_gpio(info->bt_wakeup_gpio);
+       if (err < 0)
+       {
+               dev_err(info->dev, "Cannot get GPIO line 0x%d",
+                       info->bt_wakeup_gpio);
+               omap_free_gpio(info->reset_gpio);
+               kfree(info);
+               goto cleanup;
+       }
+
+       err = omap_request_gpio(info->host_wakeup_gpio);
+       if (err < 0)
+       {
+               dev_err(info->dev, "Cannot get GPIO line %d",
+                      info->host_wakeup_gpio);
+               omap_free_gpio(info->reset_gpio);
+               omap_free_gpio(info->bt_wakeup_gpio);
+               kfree(info);
+               goto cleanup;
+       }
+
+       omap_set_gpio_direction(info->reset_gpio, 0);
+       omap_set_gpio_direction(info->bt_wakeup_gpio, 0);
+       omap_set_gpio_direction(info->host_wakeup_gpio, 1);
+
+       switch (bt_config->bt_uart) {
+       case 1:
+               if (cpu_is_omap16xx()) {
+                       irq = INT_UART1;
+                       info->uart_fclk = clk_get(NULL, "uart1_ck");
+               } else if (cpu_is_omap24xx()) {
+                       irq = INT_24XX_UART1_IRQ;
+                       info->uart_iclk = clk_get(NULL, "uart1_ick");
+                       info->uart_fclk = clk_get(NULL, "uart1_fck");
+               }
+               info->uart_base = (void *)io_p2v(OMAP_UART1_BASE);
+               break;
+       case 2:
+               if (cpu_is_omap16xx()) {
+                       irq = INT_UART2;
+                       info->uart_fclk = clk_get(NULL, "uart2_ck");
+               } else {
+                       irq = INT_24XX_UART2_IRQ;
+                       info->uart_iclk = clk_get(NULL, "uart2_ick");
+                       info->uart_fclk = clk_get(NULL, "uart2_fck");
+               }
+               info->uart_base = (void *)io_p2v(OMAP_UART2_BASE);
+               break;
+       case 3:
+               if (cpu_is_omap16xx()) {
+                       irq = INT_UART3;
+                       info->uart_fclk = clk_get(NULL, "uart3_ck");
+               } else {
+                       irq = INT_24XX_UART3_IRQ;
+                       info->uart_iclk = clk_get(NULL, "uart3_ick");
+                       info->uart_fclk = clk_get(NULL, "uart3_fck");
+               }
+               info->uart_base = (void *)io_p2v(OMAP_UART3_BASE);
+               break;
+       default:
+               dev_err(info->dev, "No uart defined\n");
+               goto cleanup;
+       }
+
+       info->irq = irq;
+       err = request_irq(irq, hci_h4p_interrupt, 0, "hci_h4p", (void *)info);
+       if (err < 0) {
+               dev_err(info->dev, "hci_h4p: unable to get IRQ %d\n", irq);
+               goto cleanup;
+       }
+
+       err = request_irq(OMAP_GPIO_IRQ(info->host_wakeup_gpio),
+                         hci_h4p_wakeup_interrupt, SA_TRIGGER_FALLING | SA_TRIGGER_RISING,
+                         "hci_h4p_wkup", (void *)info);
+       if (err < 0) {
+               dev_err(info->dev, "hci_h4p: unable to get wakeup IRQ %d\n",
+                         OMAP_GPIO_IRQ(info->host_wakeup_gpio));
+               free_irq(irq, (void *)info);
+               goto cleanup;
+       }
+
+       hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+       err = hci_h4p_init_uart(info);
+       if (err < 0)
+               goto cleanup_irq;
+       hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_CTS | UART_EFR_RTS);
+       hci_h4p_set_rts(info, 0);
+       err = hci_h4p_reset(info);
+       if (err < 0)
+               goto cleanup_irq;
+       err = hci_h4p_wait_for_cts(info, 1, 10);
+       if (err < 0)
+               goto cleanup_irq;
+       hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+
+       platform_set_drvdata(pdev, info);
+       err = hci_h4p_sysfs_create_files(info->dev);
+       if (err < 0)
+               goto cleanup_irq;
+
+       if (hci_h4p_register_hdev(info) < 0) {
+               dev_err(info->dev, "failed to register hci_h4p hci device\n");
+               goto cleanup_irq;
+       }
+       omap_set_gpio_dataout(info->reset_gpio, 0);
+
+       return 0;
+
+cleanup_irq:
+       free_irq(irq, (void *)info);
+       free_irq(OMAP_GPIO_IRQ(info->host_wakeup_gpio), (void *)info);
+cleanup:
+       omap_set_gpio_dataout(info->reset_gpio, 0);
+       omap_free_gpio(info->reset_gpio);
+       omap_free_gpio(info->bt_wakeup_gpio);
+       omap_free_gpio(info->host_wakeup_gpio);
+       kfree(info);
+
+       return err;
+
+}
+
+static int hci_h4p_remove(struct platform_device *dev)
+{
+       struct hci_h4p_info *info;
+
+       info = platform_get_drvdata(dev);
+
+       hci_h4p_hci_close(info->hdev);
+       free_irq(OMAP_GPIO_IRQ(info->host_wakeup_gpio), (void *) info);
+       hci_free_dev(info->hdev);
+       omap_free_gpio(info->reset_gpio);
+       omap_free_gpio(info->bt_wakeup_gpio);
+       omap_free_gpio(info->host_wakeup_gpio);
+       free_irq(info->irq, (void *) info);
+       kfree(info);
+
+       return 0;
+}
+
+static struct platform_driver hci_h4p_driver = {
+       .probe          = hci_h4p_probe,
+       .remove         = hci_h4p_remove,
+       .driver         = {
+               .name   = "hci_h4p",
+       },
+};
+
+static int __init hci_h4p_init(void)
+{
+       int err = 0;
+
+       /* Register the driver with LDM */
+       err = platform_driver_register(&hci_h4p_driver);
+       if (err < 0)
+               printk(KERN_WARNING "failed to register hci_h4p driver\n");
+
+       return err;
+}
+
+static void __exit hci_h4p_exit(void)
+{
+       platform_driver_unregister(&hci_h4p_driver);
+}
+
+module_init(hci_h4p_init);
+module_exit(hci_h4p_exit);
+
+MODULE_DESCRIPTION("h4 driver with nokia extensions");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ville Tervo");
diff --git a/drivers/bluetooth/hci_h4p/fw-csr.c b/drivers/bluetooth/hci_h4p/fw-csr.c
new file mode 100644 (file)
index 0000000..209aab2
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: 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
+ * 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/skbuff.h>
+#include <linux/delay.h>
+#include <linux/serial_reg.h>
+
+#include "hci_h4p.h"
+
+void hci_h4p_bc4_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+       /* Check if this is fw packet */
+       if (skb->data[0] != 0xff) {
+               hci_recv_frame(skb);
+               return;
+       }
+
+       if (skb->data[11] || skb->data[12]) {
+               dev_err(info->dev, "Firmware sending command failed\n");
+               info->fw_error = -EPROTO;
+       }
+
+       kfree_skb(skb);
+       complete(&info->fw_completion);
+}
+
+int hci_h4p_bc4_send_fw(struct hci_h4p_info *info,
+                       struct sk_buff_head *fw_queue)
+{
+       struct sk_buff *skb;
+       unsigned int offset;
+       int retries, count, i;
+
+       info->fw_error = 0;
+
+       NBT_DBG_FW("Sending firmware\n");
+       skb = skb_dequeue(fw_queue);
+
+       if (!skb)
+               return -ENOMSG;
+
+       /* Check if this is bd_address packet */
+       if (skb->data[15] == 0x01 && skb->data[16] == 0x00) {
+               offset = 21;
+               skb->data[offset + 1] = 0x00;
+               skb->data[offset + 5] = 0x00;
+               skb->data[offset + 7] = info->bdaddr[0];
+               skb->data[offset + 6] = info->bdaddr[1];
+               skb->data[offset + 4] = info->bdaddr[2];
+               skb->data[offset + 0] = info->bdaddr[3];
+               skb->data[offset + 3] = info->bdaddr[4];
+               skb->data[offset + 2] = info->bdaddr[5];
+       }
+
+       for (i = 0; i < 6; i++) {
+               if (info->bdaddr[i] != 0x00)
+                       break;
+       }
+
+       if (i > 5) {
+               dev_info(info->dev, "Valid bluetooth address not found.\n");
+               kfree_skb(skb);
+               return -ENODEV;
+       }
+
+       for (count = 1; ; count++) {
+               NBT_DBG_FW("Sending firmware command %d\n", count);
+               init_completion(&info->fw_completion);
+               skb_queue_tail(&info->txq, skb);
+               tasklet_schedule(&info->tx_task);
+
+               skb = skb_dequeue(fw_queue);
+               if (!skb)
+                       break;
+
+               if (!wait_for_completion_timeout(&info->fw_completion,
+                                                msecs_to_jiffies(1000))) {
+                       dev_err(info->dev, "No reply to fw command\n");
+                       return -ETIMEDOUT;
+               }
+
+               if (info->fw_error) {
+                       dev_err(info->dev, "FW error\n");
+                       return -EPROTO;
+               }
+       };
+
+       /* Wait for chip warm reset */
+       retries = 100;
+       while ((!skb_queue_empty(&info->txq) ||
+              !(hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT)) &&
+              retries--) {
+               msleep(10);
+       }
+       if (!retries) {
+               dev_err(info->dev, "Transmitter not empty\n");
+               return -ETIMEDOUT;
+       }
+
+       hci_h4p_change_speed(info, BC4_MAX_BAUD_RATE);
+
+       if (hci_h4p_wait_for_cts(info, 1, 100)) {
+               dev_err(info->dev, "cts didn't go down after final speed change\n");
+               return -ETIMEDOUT;
+       }
+
+       retries = 100;
+       do {
+               init_completion(&info->init_completion);
+               hci_h4p_send_alive_packet(info);
+               retries--;
+       } while (!wait_for_completion_timeout(&info->init_completion, 100) &&
+                retries > 0);
+
+       if (!retries) {
+               dev_err(info->dev, "No alive reply after speed change\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
diff --git a/drivers/bluetooth/hci_h4p/fw-ti.c b/drivers/bluetooth/hci_h4p/fw-ti.c
new file mode 100644 (file)
index 0000000..b98b579
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: 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
+ * 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/skbuff.h>
+
+#include "hci_h4p.h"
+
+void hci_h4p_brf6150_parse_fw_event(struct hci_h4p_info *info,
+                                   struct sk_buff *skb)
+{
+       struct hci_fw_event *ev;
+       int err = 0;
+
+       if (bt_cb(skb)->pkt_type != H4_EVT_PKT) {
+               dev_err(info->dev, "Got non event fw packet.\n");
+               err = -EPROTO;
+               goto ret;
+       }
+
+       ev = (struct hci_fw_event *)skb->data;
+       if (ev->hev.evt != HCI_EV_CMD_COMPLETE) {
+               dev_err(info->dev, "Got non cmd complete fw event\n");
+               err = -EPROTO;
+               goto ret;
+       }
+
+       if (ev->status != 0) {
+               dev_err(info->dev, "Got error status from fw command\n");
+               err = -EPROTO;
+               goto ret;
+       }
+
+ret:
+       info->fw_error = err;
+       complete(&info->fw_completion);
+}
+
+int hci_h4p_brf6150_send_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue)
+{
+       struct sk_buff *skb;
+       int err = 0;
+
+       info->fw_error = 0;
+
+       while ((skb = skb_dequeue(fw_queue)) != NULL) {
+               /* We should allways send word aligned data to h4+ devices */
+               if (skb->len % 2) {
+                       err = skb_pad(skb, 1);
+               }
+               if (err)
+                       return err;
+
+               init_completion(&info->fw_completion);
+               skb_queue_tail(&info->txq, skb);
+               tasklet_schedule(&info->tx_task);
+
+               if (!wait_for_completion_timeout(&info->fw_completion, HZ)) {
+                       dev_err(info->dev, "Timeout while sending brf6150 fw\n");
+                       return -ETIMEDOUT;
+               }
+
+               if (info->fw_error) {
+                       dev_err(info->dev, "There was fw_error while sending bfr6150 fw\n");
+                       return -EPROTO;
+               }
+       }
+       NBT_DBG_FW("Firmware sent\n");
+
+       return 0;
+}
diff --git a/drivers/bluetooth/hci_h4p/fw.c b/drivers/bluetooth/hci_h4p/fw.c
new file mode 100644 (file)
index 0000000..792b6b7
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: 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
+ * 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/skbuff.h>
+#include <linux/firmware.h>
+#include <linux/clk.h>
+
+#include <net/bluetooth/bluetooth.h>
+
+#include "hci_h4p.h"
+
+static int fw_pos;
+
+/* Firmware handling */
+static int hci_h4p_open_firmware(struct hci_h4p_info *info,
+                                const struct firmware **fw_entry)
+{
+       int err;
+
+       fw_pos = 0;
+       NBT_DBG_FW("Opening %d firmware\n", info->chip_type);
+       switch (info->chip_type) {
+       case BT_CHIP_TI:
+               err = request_firmware(fw_entry, "brf6150fw.bin", info->dev);
+               break;
+       case BT_CHIP_CSR:
+               err = request_firmware(fw_entry, "bc4fw.bin", info->dev);
+               break;
+       default:
+               dev_err(info->dev, "Invalid chip type\n");
+               *fw_entry = NULL;
+               err = -EINVAL;
+       }
+
+       return err;
+}
+
+static void hci_h4p_close_firmware(const struct firmware *fw_entry)
+{
+       release_firmware(fw_entry);
+}
+
+/* Read fw. Return length of the command. If no more commands in
+ * fw 0 is returned. In error case return value is negative.
+ */
+static int hci_h4p_read_fw_cmd(struct hci_h4p_info *info, struct sk_buff **skb,
+                              const struct firmware *fw_entry, int how)
+{
+       unsigned int cmd_len;
+
+       if (fw_pos >= fw_entry->size) {
+               return 0;
+       }
+
+       cmd_len = fw_entry->data[fw_pos++];
+       if (!cmd_len)
+               return 0;
+
+       if (fw_pos + cmd_len > fw_entry->size) {
+               dev_err(info->dev, "Corrupted firmware image\n");
+               return -EMSGSIZE;
+       }
+
+       *skb = bt_skb_alloc(cmd_len, how);
+       if (!*skb) {
+               dev_err(info->dev, "Cannot reserve memory for buffer\n");
+               return -ENOMEM;
+       }
+       memcpy(skb_put(*skb, cmd_len), &fw_entry->data[fw_pos], cmd_len);
+
+       fw_pos += cmd_len;
+
+       return (*skb)->len;
+}
+
+int hci_h4p_read_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue)
+{
+       const struct firmware *fw_entry = NULL;
+       struct sk_buff *skb = NULL;
+       int err;
+
+       err = hci_h4p_open_firmware(info, &fw_entry);
+       if (err < 0 || !fw_entry)
+               goto err_clean;
+
+       while ((err = hci_h4p_read_fw_cmd(info, &skb, fw_entry, GFP_KERNEL))) {
+               if (err < 0 || !skb)
+                       goto err_clean;
+
+               skb_queue_tail(fw_queue, skb);
+       }
+
+err_clean:
+       hci_h4p_close_firmware(fw_entry);
+       return err;
+}
+
+int hci_h4p_send_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue)
+{
+       int err;
+
+       switch(info->chip_type) {
+       case BT_CHIP_CSR:
+               err = hci_h4p_bc4_send_fw(info, fw_queue);
+               break;
+       case BT_CHIP_TI:
+               err = hci_h4p_brf6150_send_fw(info, fw_queue);
+               break;
+       default:
+               dev_err(info->dev, "Don't know how to send firmware\n");
+               err = -EINVAL;
+       }
+
+       return err;
+}
+
+void hci_h4p_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+       switch (info->chip_type) {
+       case BT_CHIP_CSR:
+               hci_h4p_bc4_parse_fw_event(info, skb);
+               break;
+       case BT_CHIP_TI:
+               hci_h4p_brf6150_parse_fw_event(info, skb);
+               break;
+       default:
+               dev_err(info->dev, "Don't know how to parse fw event\n");
+               info->fw_error = -EINVAL;
+       }
+
+       return;
+}
diff --git a/drivers/bluetooth/hci_h4p/hci_h4p.h b/drivers/bluetooth/hci_h4p/hci_h4p.h
new file mode 100644 (file)
index 0000000..af9da25
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: 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
+ * 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 <asm/arch/board.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+
+#ifndef __DRIVERS_BLUETOOTH_HCI_H4P_H
+#define __DRIVERS_BLUETOOTH_HCI_H4P_H
+
+#define UART_SYSC_OMAP_RESET   0x03
+#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
+
+#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
+
+#if 0
+#define NBT_DBG_DMA(fmt, arg...)  printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG_DMA(...)
+#endif
+
+struct hci_h4p_info {
+       struct hci_dev *hdev;
+       spinlock_t lock;
+
+       void __iomem *uart_base;
+       unsigned long uart_phys_base;
+       int irq;
+       struct device *dev;
+       u8 bdaddr[6];
+       u8 chip_type;
+       u8 bt_wakeup_gpio;
+       u8 host_wakeup_gpio;
+       u8 reset_gpio;
+       u8 bt_sysclk;
+
+
+       struct sk_buff_head fw_queue;
+       struct sk_buff *alive_cmd_skb;
+       struct completion init_completion;
+       struct completion fw_completion;
+       int fw_error;
+       int init_error;
+
+       struct sk_buff_head txq;
+       struct tasklet_struct tx_task;
+
+       struct sk_buff *rx_skb;
+       long rx_count;
+       unsigned long rx_state;
+       unsigned long garbage_bytes;
+       struct tasklet_struct rx_task;
+
+       int pm_enabled;
+       int tx_pm_enabled;
+       int rx_pm_enabled;
+       struct timer_list tx_pm_timer;
+       struct timer_list rx_pm_timer;
+
+       int tx_clocks_en;
+       int rx_clocks_en;
+       spinlock_t clocks_lock;
+       struct clk *uart_iclk;
+       struct clk *uart_fclk;
+};
+
+#define MAX_BAUD_RATE          921600
+#define BC4_MAX_BAUD_RATE      3692300
+#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));
+
+struct hci_bc4_set_bdaddr {
+       u8 type;
+       struct hci_command_hdr cmd_hdr;
+} __attribute__ ((packed));
+
+int hci_h4p_send_alive_packet(struct hci_h4p_info *info);
+
+void hci_h4p_bc4_parse_fw_event(struct hci_h4p_info *info,
+                               struct sk_buff *skb);
+int hci_h4p_bc4_send_fw(struct hci_h4p_info *info,
+                       struct sk_buff_head *fw_queue);
+
+void hci_h4p_brf6150_parse_fw_event(struct hci_h4p_info *info,
+                                   struct sk_buff *skb);
+int hci_h4p_brf6150_send_fw(struct hci_h4p_info *info,
+                           struct sk_buff_head *fw_queue);
+
+int hci_h4p_read_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue);
+int hci_h4p_send_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue);
+void hci_h4p_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb);
+
+int hci_h4p_sysfs_create_files(struct device *dev);
+
+void hci_h4p_outb(struct hci_h4p_info *info, unsigned int offset, u8 val);
+u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset);
+void hci_h4p_set_rts(struct hci_h4p_info *info, int active);
+int hci_h4p_wait_for_cts(struct hci_h4p_info *info, int active, int timeout_ms);
+void hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which);
+void hci_h4p_change_speed(struct hci_h4p_info *info, unsigned long speed);
+int hci_h4p_reset_uart(struct hci_h4p_info *info);
+int hci_h4p_init_uart(struct hci_h4p_info *info);
+
+#endif /* __DRIVERS_BLUETOOTH_HCI_H4P_H */
diff --git a/drivers/bluetooth/hci_h4p/sysfs.c b/drivers/bluetooth/hci_h4p/sysfs.c
new file mode 100644 (file)
index 0000000..687df69
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: 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
+ * 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/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+#include "hci_h4p.h"
+
+#ifdef CONFIG_SYSFS
+
+static ssize_t hci_h4p_store_bdaddr(struct device *dev, struct device_attribute *attr,
+                                   const char *buf, size_t count)
+{
+       struct hci_h4p_info *info = (struct hci_h4p_info*)dev_get_drvdata(dev);
+       unsigned int bdaddr[6];
+       int ret, i;
+
+       ret = sscanf(buf, "%2x:%2x:%2x:%2x:%2x:%2x\n",
+                       &bdaddr[0], &bdaddr[1], &bdaddr[2],
+                       &bdaddr[3], &bdaddr[4], &bdaddr[5]);
+
+       if (ret != 6) {
+               return -EINVAL;
+       }
+
+       for (i = 0; i < 6; i++)
+               info->bdaddr[i] = bdaddr[i] & 0xff;
+
+       return count;
+}
+
+static ssize_t hci_h4p_show_bdaddr(struct device *dev, struct device_attribute *attr,
+                                  char *buf)
+{
+       struct hci_h4p_info *info = (struct hci_h4p_info*)dev_get_drvdata(dev);
+
+       return sprintf(buf, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
+                      info->bdaddr[0],
+                      info->bdaddr[1],
+                      info->bdaddr[2],
+                      info->bdaddr[3],
+                      info->bdaddr[4],
+                      info->bdaddr[5]);
+}
+
+static DEVICE_ATTR(bdaddr, S_IRUGO | S_IWUSR, hci_h4p_show_bdaddr, hci_h4p_store_bdaddr);
+int hci_h4p_sysfs_create_files(struct device *dev)
+{
+       return device_create_file(dev, &dev_attr_bdaddr);
+}
+
+#endif
diff --git a/drivers/bluetooth/hci_h4p/uart.c b/drivers/bluetooth/hci_h4p/uart.c
new file mode 100644 (file)
index 0000000..67220fb
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: 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
+ * 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/serial_reg.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+
+#include "hci_h4p.h"
+
+inline void hci_h4p_outb(struct hci_h4p_info *info, unsigned int offset, u8 val)
+{
+       outb(val, info->uart_base + (offset << 2));
+}
+
+inline u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset)
+{
+       return inb(info->uart_base + (offset << 2));
+}
+
+void hci_h4p_set_rts(struct hci_h4p_info *info, int active)
+{
+       u8 b;
+
+       b = hci_h4p_inb(info, UART_MCR);
+       if (active)
+               b |= UART_MCR_RTS;
+       else
+               b &= ~UART_MCR_RTS;
+       hci_h4p_outb(info, UART_MCR, b);
+}
+
+int hci_h4p_wait_for_cts(struct hci_h4p_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 = hci_h4p_inb(info, UART_MSR) & UART_MSR_CTS;
+               if (active) {
+                       if (state)
+                               return 0;
+               } else {
+                       if (!state)
+                               return 0;
+               }
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
+       }
+}
+
+void hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which)
+{
+       u8 lcr, b;
+
+       lcr = hci_h4p_inb(info, UART_LCR);
+       hci_h4p_outb(info, UART_LCR, 0xbf);
+       b = hci_h4p_inb(info, UART_EFR);
+       if (on)
+               b |= which;
+       else
+               b &= ~which;
+       hci_h4p_outb(info, UART_EFR, b);
+       hci_h4p_outb(info, UART_LCR, lcr);
+}
+
+void hci_h4p_change_speed(struct hci_h4p_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;
+       }
+
+       hci_h4p_outb(info, UART_OMAP_MDR1, 7); /* Make sure UART mode is disabled */
+       lcr = hci_h4p_inb(info, UART_LCR);
+       hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB);     /* Set DLAB */
+       hci_h4p_outb(info, UART_DLL, divisor & 0xff);    /* Set speed */
+       hci_h4p_outb(info, UART_DLM, divisor >> 8);
+       hci_h4p_outb(info, UART_LCR, lcr);
+       hci_h4p_outb(info, UART_OMAP_MDR1, mdr1); /* Make sure UART mode is enabled */
+}
+
+int hci_h4p_reset_uart(struct hci_h4p_info *info)
+{
+       int count = 0;
+
+       /* Reset the  UART */
+       hci_h4p_outb(info, UART_OMAP_SYSC, UART_SYSC_OMAP_RESET);
+       while (!(hci_h4p_inb(info, UART_OMAP_SYSS) & UART_SYSS_RESETDONE)) {
+               if (count++ > 100) {
+                       dev_err(info->dev, "hci_h4p: UART reset timeout\n");
+                       return -ENODEV;
+               }
+               udelay(1);
+       }
+
+       return 0;
+}
+
+int hci_h4p_init_uart(struct hci_h4p_info *info)
+{
+       int err;
+
+       err = hci_h4p_reset_uart(info);
+       if (err < 0)
+               return err;
+
+       /* Enable and setup FIFO */
+       hci_h4p_outb(info, UART_LCR, UART_LCR_WLEN8);
+       hci_h4p_outb(info, UART_OMAP_MDR1, 0x00); /* Make sure UART mode is enabled */
+       hci_h4p_outb(info, UART_OMAP_SCR, 0x80);
+       hci_h4p_outb(info, UART_EFR, UART_EFR_ECB);
+       hci_h4p_outb(info, UART_MCR, UART_MCR_TCRTLR);
+       hci_h4p_outb(info, UART_TI752_TLR, 0x1f);
+       hci_h4p_outb(info, UART_TI752_TCR, 0xef);
+       hci_h4p_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
+                    UART_FCR_CLEAR_XMIT | UART_FCR_R_TRIG_00);
+       hci_h4p_outb(info, UART_IER, UART_IER_RDI);
+
+       return 0;
+}
index 2df42fdcdc91d5ae87991f1de54de44b756ab040..30347e9caf623f8234bcb78b64cdbfc8fd195cca 100644 (file)
@@ -839,6 +839,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 2f56ecc035aa9366ba018074ef1aba24065b3b6b..110d711653f1c6d7a86f9c41da66289361475fab 100644 (file)
@@ -72,6 +72,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-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 c2dd7d65823d731370b59777f414bc39ce65aa5f..9b62c3b122a06c61460d6d24cd9f6aec405ff89d 100644 (file)
@@ -126,6 +126,10 @@ config TWL4030_CORE
        help
          Say yes here if you have TWL4030 chip on your board
 
+config TWL4030_GPIO
+       bool "TWL4030 GPIO Driver"
+       depends on TWL4030_CORE
+
 config SENSORS_M41T00
        tristate "ST M41T00 RTC chip"
        depends on PPC32
index 2ea4a4a09c19cad26b918907805cb1320bebdb67..a48cb8a81f3884e106ed5548850436eab446d098 100644 (file)
@@ -16,6 +16,7 @@ obj-$(CONFIG_SENSORS_TLV320AIC23) += tlv320aic23.o
 obj-$(CONFIG_GPIOEXPANDER_OMAP)        += gpio_expander_omap.o
 obj-$(CONFIG_MENELAUS)         += menelaus.o
 obj-$(CONFIG_TWL4030_CORE)      += twl4030_core.o
+obj-$(CONFIG_TWL4030_GPIO)     += twl4030_gpio.o
 obj-$(CONFIG_RTC_X1205_I2C)    += x1205.o
 
 ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
index c12ff20832147be7cea072d271287f9efc9bf0b4..5004915576552e9aee870e821b044176e7a8d0d4 100644 (file)
@@ -940,8 +940,7 @@ static int __init menelaus_init(void)
 
 static void __exit menelaus_exit(void)
 {
-       if (i2c_del_driver(&menelaus_i2c_driver) < 0)
-               pr_err("driver remove failed\n");
+       i2c_del_driver(&menelaus_i2c_driver);
 
        /* FIXME: Shutdown menelaus parts that can be shut down */
 }
index 65a8e6246c0c89b3139ab97b9c64560ab18601da..aaf9d1c46f1ce682275210f8bf6ddd277e53e0bc 100644 (file)
@@ -655,8 +655,7 @@ static void __exit aic23_exit(void)
        int res;
 
        aic23_power_down();
-       if ((res = i2c_del_driver(&aic23_driver)))
-               printk("aic23 i2c: Driver remove failed, module not removed.\n");
+       i2c_del_driver(&aic23_driver);
 
        platform_device_unregister(&audio_i2c_device);
        platform_driver_unregister(&audio_i2c_driver);
index 31340642ce182051b74ff671011ec9e55af9cf10..2278b5c7412b647615b01bf54963aa3c94aaac2e 100644 (file)
@@ -325,6 +325,7 @@ int twl4030_i2c_read(u8 mod_no, u8 * value, u8 reg, u8 num_bytes)
        msg = &(client->xfer_msg[0]);
        msg->addr = client->address;
        msg->len = 1;
+       msg->flags = 0; /* Read the register value */
        val = twl4030_map[mod_no].base + reg;
        msg->buf = &val;
        /* [MSG2] fill the data rx buffer */
@@ -393,7 +394,7 @@ static void do_twl4030_module_irq(unsigned int irq, irq_desc_t *desc)
        /*
         * Earlier this was desc->triggered = 1;
         */
-       desc->status = IRQ_INPROGRESS;
+       desc->status |= IRQ_LEVEL;
 
        /*
         * The desc->handle method would normally call the desc->chip->ack
@@ -510,12 +511,11 @@ static int twl4030_irq_thread(void *data)
 static void do_twl4030_irq(unsigned int irq, irq_desc_t *desc)
 {
        const unsigned int cpu = smp_processor_id();
-       struct task_struct *thread = (struct task_struct *)desc->chip_data;
-
+       struct task_struct *thread = get_irq_data(irq);
        /*
         * Earlier this was desc->triggered = 1;
         */
-       desc->status = IRQ_INPROGRESS;
+       desc->status |= IRQ_LEVEL;
 
        /*
         * Acknowledge, clear _AND_ disable the interrupt.
@@ -891,9 +891,7 @@ static int __init twl4030_init(void)
 
 static void __exit twl4030_exit(void)
 {
-       if (i2c_del_driver(&twl4030_driver))
-               printk(KERN_ERR
-                       "TWL4030: Driver remove failed, module not removed\n");
+       i2c_del_driver(&twl4030_driver);
        twl_irq_used = FREE;
 }
 
diff --git a/drivers/i2c/chips/twl4030_gpio.c b/drivers/i2c/chips/twl4030_gpio.c
new file mode 100644 (file)
index 0000000..f92e6ef
--- /dev/null
@@ -0,0 +1,842 @@
+/*
+ * linux/drivers/i2c/chips/twl4030_gpio.c
+ *
+ * Copyright (C) 2006-2007 Texas Instruments, Inc.
+ * Copyright (C) 2006 MontaVista Software, Inc.
+ *
+ * Code re-arranged and cleaned up by:
+ *     Syed Mohammed Khasim <x0khasim@ti.com>
+ *
+ * Initial Code:
+ *     Andy Lowe / Nishanth Menon
+ *
+ * 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_stat.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/interrupt.h>
+#include <linux/random.h>
+#include <linux/syscalls.h>
+#include <linux/kthread.h>
+
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+#include <asm/arch/twl4030.h>
+#include <asm/arch/irqs.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+
+#include <linux/device.h>
+
+/****************************************
+* GPIO Block Register definitions
+****************************************/
+
+#define REG_GPIODATAIN1                        (0x0)
+#define REG_GPIODATAIN2                        (0x1)
+#define REG_GPIODATAIN3                        (0x2)
+#define REG_GPIODATADIR1               (0x3)
+#define REG_GPIODATADIR2               (0x4)
+#define REG_GPIODATADIR3               (0x5)
+#define REG_GPIODATAOUT1               (0x6)
+#define REG_GPIODATAOUT2               (0x7)
+#define REG_GPIODATAOUT3               (0x8)
+#define REG_CLEARGPIODATAOUT1          (0x9)
+#define REG_CLEARGPIODATAOUT2          (0xA)
+#define REG_CLEARGPIODATAOUT3          (0xB)
+#define REG_SETGPIODATAOUT1            (0xC)
+#define REG_SETGPIODATAOUT2            (0xD)
+#define REG_SETGPIODATAOUT3            (0xE)
+#define REG_GPIO_DEBEN1                        (0xF)
+#define REG_GPIO_DEBEN2                        (0x10)
+#define REG_GPIO_DEBEN3                        (0x11)
+#define REG_GPIO_CTRL                  (0x12)
+#define REG_GPIOPUPDCTR1               (0x13)
+#define REG_GPIOPUPDCTR2               (0x14)
+#define REG_GPIOPUPDCTR3               (0x15)
+#define REG_GPIOPUPDCTR4               (0x16)
+#define REG_GPIOPUPDCTR5               (0x17)
+#define REG_GPIO_ISR1A                 (0x19)
+#define REG_GPIO_ISR2A                 (0x1A)
+#define REG_GPIO_ISR3A                 (0x1B)
+#define REG_GPIO_IMR1A                 (0x1C)
+#define REG_GPIO_IMR2A                 (0x1D)
+#define REG_GPIO_IMR3A                 (0x1E)
+#define REG_GPIO_ISR1B                 (0x1F)
+#define REG_GPIO_ISR2B                 (0x20)
+#define REG_GPIO_ISR3B                 (0x21)
+#define REG_GPIO_IMR1B                 (0x22)
+#define REG_GPIO_IMR2B                 (0x23)
+#define REG_GPIO_IMR3B                 (0x24)
+#define REG_GPIO_EDR1                  (0x28)
+#define REG_GPIO_EDR2                  (0x29)
+#define REG_GPIO_EDR3                  (0x2A)
+#define REG_GPIO_EDR4                  (0x2B)
+#define REG_GPIO_EDR5                  (0x2C)
+#define REG_GPIO_SIH_CTRL              (0x2D)
+
+/**** BitField Definitions */
+
+/***** Data banks : 3 banks for 8 gpios each */
+#define DATA_BANK_MAX                          8
+#define GET_GPIO_DATA_BANK(x)                  ((x)/DATA_BANK_MAX)
+#define GET_GPIO_DATA_OFF(x)                   ((x)%DATA_BANK_MAX)
+
+/* GPIODATADIR Fields each block 0-7 */
+#define BIT_GPIODATADIR_GPIOxDIR(x)            (x)
+#define MASK_GPIODATADIR_GPIOxDIR(x)           (0x01<<(x))
+
+/* GPIODATAIN Fields each block 0-7 */
+#define BIT_GPIODATAIN_GPIOxIN(x)              (x)
+#define MASK_GPIODATAIN_GPIOxIN(x)             (0x01<<(x))
+
+/* GPIODATAOUT Fields each block 0-7 */
+#define BIT_GPIODATAOUT_GPIOxOUT(x)            (x)
+#define MASK_GPIODATAOUT_GPIOxOUT(x)           (0x01<<(x))
+
+/* CLEARGPIODATAOUT Fields */
+#define BIT_CLEARGPIODATAOUT_GPIOxOUT(x)       (x)
+#define MASK_CLEARGPIODATAOUT_GPIOxOUT(x)      (0x01<<(x))
+
+/* SETGPIODATAOUT Fields */
+#define BIT_SETGPIODATAOUT_GPIOxOUT(x)         (x)
+#define MASK_SETGPIODATAOUT_GPIOxOUT(x)                (0x01<<(x))
+
+/* GPIO_DEBEN Fields */
+#define BIT_GPIO_DEBEN_GPIOxDEB(x)             (x)
+#define MASK_GPIO_DEBEN_GPIOxDEB(x)            (0x01<<(x))
+
+/* GPIO_ISR1A Fields */
+#define BIT_GPIO_ISR_GPIOxISR(x)               (x)
+#define MASK_GPIO_ISR_GPIOxISR(x)              (0x01<<(x))
+
+/* GPIO_IMR1A Fields */
+#define BIT_GPIO_IMR1A_GPIOxIMR(x)             (x)
+#define MASK_GPIO_IMR1A_GPIOxIMR(x)            (0x01<<(x))
+
+/* GPIO_SIR1 Fields */
+#define BIT_GPIO_SIR1_GPIOxSIR(x)              (x)
+#define MASK_GPIO_SIR1_GPIO0SIR                        (0x01<<(x))
+
+
+/**** Control banks : 5 banks for 4 gpios each */
+#define DATA_CTL_MAX                   4
+#define GET_GPIO_CTL_BANK(x)           ((x)/DATA_CTL_MAX)
+#define GET_GPIO_CTL_OFF(x)            ((x)%DATA_CTL_MAX)
+#define GPIO_BANK_MAX                  GET_GPIO_CTL_BANK(TWL4030_GPIO_MAX)
+
+/* GPIOPUPDCTRx Fields 5 banks of 4 gpios each */
+#define BIT_GPIOPUPDCTR1_GPIOxPD(x)    (2 *(x))
+#define MASK_GPIOPUPDCTR1_GPIOxPD(x)   (0x01<<(2*(x)))
+#define BIT_GPIOPUPDCTR1_GPIOxPU(x)    ((x) + 1)
+#define MASK_GPIOPUPDCTR1_GPIOxPU(x)   (0x01<<(((2*(x)) + 1)))
+
+/* GPIO_EDR1 Fields */
+#define BIT_GPIO_EDR1_GPIOxFALLING(x)  (2 *(x))
+#define MASK_GPIO_EDR1_GPIOxFALLING(x) (0x01<<(2*(x)))
+#define BIT_GPIO_EDR1_GPIOxRISING(x)   ((x) + 1)
+#define MASK_GPIO_EDR1_GPIOxRISING(x)  (0x01<<(((2*(x)) + 1)))
+
+/* GPIO_SIH_CTRL Fields */
+#define BIT_GPIO_SIH_CTRL_EXCLEN       (0x000)
+#define MASK_GPIO_SIH_CTRL_EXCLEN      (0x00000001)
+#define BIT_GPIO_SIH_CTRL_PENDDIS      (0x001)
+#define MASK_GPIO_SIH_CTRL_PENDDIS     (0x00000002)
+#define BIT_GPIO_SIH_CTRL_COR          (0x002)
+#define MASK_GPIO_SIH_CTRL_COR         (0x00000004)
+
+/* GPIO_CTRL Fields */
+#define BIT_GPIO_CTRL_GPIO0CD1         (0x000)
+#define MASK_GPIO_CTRL_GPIO0CD1                (0x00000001)
+#define BIT_GPIO_CTRL_GPIO1CD2         (0x001)
+#define MASK_GPIO_CTRL_GPIO1CD2                (0x00000002)
+#define BIT_GPIO_CTRL_GPIO_ON          (0x002)
+#define MASK_GPIO_CTRL_GPIO_ON         (0x00000004)
+
+/* Mask for GPIO registers when aggregated into a 32-bit integer */
+#define GPIO_32_MASK                   0x0003ffff
+
+/* Data structures */
+static struct semaphore gpio_sem;
+
+/* store usage of each GPIO. - each bit represents one GPIO */
+static unsigned int gpio_usage_count;
+
+/* shadow the imr register */
+static unsigned int gpio_imr_shadow;
+
+/* bitmask of pending requests to unmask gpio interrupts */
+static unsigned int gpio_pending_unmask;
+
+/* pointer to gpio unmask thread struct */
+static struct task_struct *gpio_unmask_thread;
+
+static inline int gpio_twl4030_read(u8 address);
+static inline int gpio_twl4030_write(u8 address, u8 data);
+
+/*
+ * Helper functions to read and write the GPIO ISR and IMR registers as
+ * 32-bit integers. Functions return 0 on success, non-zero otherwise.
+ * The caller must hold a lock on gpio_sem.
+ */
+
+static int gpio_read_isr(unsigned int *isr)
+{
+       int ret;
+
+       *isr = 0;
+       ret = twl4030_i2c_read(TWL4030_MODULE_GPIO, (u8 *) isr,
+                       REG_GPIO_ISR1A, 3);
+       le32_to_cpup(isr);
+       *isr &= GPIO_32_MASK;
+
+       return ret;
+}
+
+static int gpio_write_isr(unsigned int isr)
+{
+       int ret;
+
+       isr &= GPIO_32_MASK;
+       /*
+        * The buffer passed to the twl4030_i2c_write() routine must have an
+        * extra byte at the beginning reserved for its internal use.
+        */
+       isr <<= 8;
+       isr = cpu_to_le32(isr);
+       ret = twl4030_i2c_write(TWL4030_MODULE_GPIO, (u8 *) &isr,
+                               REG_GPIO_ISR1A, 3);
+       return ret;
+}
+
+static int gpio_write_imr(unsigned int imr)
+{
+       int ret;
+
+       imr &= GPIO_32_MASK;
+       /*
+        * The buffer passed to the twl4030_i2c_write() routine must have an
+        * extra byte at the beginning reserved for its internal use.
+        */
+       imr <<= 8;
+       imr = cpu_to_le32(imr);
+       ret = twl4030_i2c_write(TWL4030_MODULE_GPIO, (u8 *) &imr,
+                               REG_GPIO_IMR1A, 3);
+       return ret;
+}
+
+/*
+ * These routines are analagous to the irqchip methods, but they are designed
+ * to be called from thread context with cpu interrupts enabled and with no
+ * locked spinlocks.  We call these routines from our custom IRQ handler
+ * instead of the usual irqchip methods.
+ */
+static void twl4030_gpio_mask_and_ack(unsigned int irq)
+{
+       int gpio = irq - IH_TWL4030_GPIO_BASE;
+
+       down(&gpio_sem);
+       /* mask */
+       gpio_imr_shadow |= (1 << gpio);
+       gpio_write_imr(gpio_imr_shadow);
+       /* ack */
+       gpio_write_isr(1 << gpio);
+       up(&gpio_sem);
+}
+
+static void twl4030_gpio_unmask(unsigned int irq)
+{
+       int gpio = irq - IH_TWL4030_GPIO_BASE;
+
+       down(&gpio_sem);
+       gpio_imr_shadow &= ~(1 << gpio);
+       gpio_write_imr(gpio_imr_shadow);
+       up(&gpio_sem);
+}
+
+/*
+ * These are the irqchip methods for the TWL4030 GPIO interrupts.
+ * Our IRQ handle method doesn't call these, but they will be called by
+ * other routines such as setup_irq() and enable_irq().  They are called
+ * with cpu interrupts disabled and with a lock on the irq_controller_lock
+ * spinlock.  This complicates matters, because accessing the TWL4030 GPIO
+ * interrupt controller requires I2C bus transactions that can't be initiated
+ * in this context.  Our solution is to defer accessing the interrupt
+ * controller to a kernel thread.  We only need to support the unmask method.
+ */
+
+static void twl4030_gpio_mask_and_ack_irqchip(unsigned int irq) {}
+static void twl4030_gpio_mask_irqchip(unsigned int irq) {}
+
+static void twl4030_gpio_unmask_irqchip(unsigned int irq)
+{
+       int gpio = irq - IH_TWL4030_GPIO_BASE;
+
+       gpio_pending_unmask |= (1 << gpio);
+       if (gpio_unmask_thread && gpio_unmask_thread->state != TASK_RUNNING)
+               wake_up_process(gpio_unmask_thread);
+}
+
+static struct irq_chip twl4030_gpio_irq_chip = {
+       .name   = "twl4030-gpio",
+       .ack    = twl4030_gpio_mask_and_ack_irqchip,
+       .mask   = twl4030_gpio_mask_irqchip,
+       .unmask = twl4030_gpio_unmask_irqchip,
+};
+
+/*
+ * These are the irqchip methods for the TWL4030 PIH GPIO module interrupt.
+ * The PIH module doesn't have interrupt masking capability, so these
+ * methods are NULL.
+ */
+static void twl4030_gpio_module_ack(unsigned int irq) {}
+static void twl4030_gpio_module_mask(unsigned int irq) {}
+static void twl4030_gpio_module_unmask(unsigned int irq) {}
+static struct irq_chip twl4030_gpio_module_irq_chip = {
+       .ack    = twl4030_gpio_module_ack,
+       .mask   = twl4030_gpio_module_mask,
+       .unmask = twl4030_gpio_module_unmask,
+};
+
+/*
+ * twl4030 GPIO request function
+ */
+int twl4030_request_gpio(int gpio)
+{
+       int ret = 0;
+
+       if (unlikely(gpio >= TWL4030_GPIO_MAX))
+               return -EPERM;
+
+       down(&gpio_sem);
+       if (gpio_usage_count & (0x1 << gpio))
+               ret = -EBUSY;
+       else {
+               u8 clear_pull[6] = { 0, 0, 0, 0, 0, 0 };
+               /* First time usage? - switch on GPIO module */
+               if (!gpio_usage_count) {
+                       ret =
+                       gpio_twl4030_write(REG_GPIO_CTRL,
+                                       MASK_GPIO_CTRL_GPIO_ON);
+                       ret = gpio_twl4030_write(REG_GPIO_SIH_CTRL, 0x00);
+               }
+               if (!ret)
+                       gpio_usage_count |= (0x1 << gpio);
+
+               ret =
+               twl4030_i2c_write(TWL4030_MODULE_GPIO, clear_pull,
+                               REG_GPIOPUPDCTR1, 5);
+       }
+       up(&gpio_sem);
+       return ret;
+}
+
+/*
+ * TWL4030 GPIO free module
+ */
+int twl4030_free_gpio(int gpio)
+{
+       int ret = 0;
+
+       if (unlikely(gpio >= TWL4030_GPIO_MAX))
+               return -EPERM;
+
+       down(&gpio_sem);
+
+       if ((gpio_usage_count & (0x1 << gpio)) == 0)
+               ret = -EPERM;
+       else
+               gpio_usage_count &= ~(0x1 << gpio);
+
+       /* Last time usage? - switch off GPIO module */
+       if (!gpio_usage_count)
+               ret = gpio_twl4030_write(REG_GPIO_CTRL, 0x0);
+
+       up(&gpio_sem);
+       return ret;
+}
+
+/*
+ * Set direction for TWL4030 GPIO
+ */
+int twl4030_set_gpio_direction(int gpio, int is_input)
+{
+       u8 d_bnk = GET_GPIO_DATA_BANK(gpio);
+       u8 d_msk = MASK_GPIODATADIR_GPIOxDIR(GET_GPIO_DATA_OFF(gpio));
+       u8 reg = 0;
+       u8 base = 0;
+       int ret = 0;
+
+       if (unlikely((gpio >= TWL4030_GPIO_MAX)
+               || !(gpio_usage_count & (0x1 << gpio))))
+               return -EPERM;
+
+       base = REG_GPIODATADIR1 + d_bnk;
+
+       down(&gpio_sem);
+       ret = gpio_twl4030_read(base);
+       if (ret >= 0) {
+               if (is_input)
+                       reg = (u8) ((ret) & ~(d_msk));
+               else
+                       reg = (u8) ((ret) | (d_msk));
+
+               ret = gpio_twl4030_write(base, reg);
+       }
+       up(&gpio_sem);
+       return ret;
+}
+
+/*
+ * To enable/disable GPIO pin on TWL4030
+ */
+int twl4030_set_gpio_dataout(int gpio, int enable)
+{
+       u8 d_bnk = GET_GPIO_DATA_BANK(gpio);
+       u8 d_msk = MASK_GPIODATAOUT_GPIOxOUT(GET_GPIO_DATA_OFF(gpio));
+       u8 base = 0;
+       int ret = 0;
+
+       if (unlikely((gpio >= TWL4030_GPIO_MAX)
+               || !(gpio_usage_count & (0x1 << gpio))))
+               return -EPERM;
+
+       if (enable)
+               base = REG_SETGPIODATAOUT1 + d_bnk;
+       else
+               base = REG_CLEARGPIODATAOUT1 + d_bnk;
+
+       down(&gpio_sem);
+       ret = gpio_twl4030_write(base, d_msk);
+       up(&gpio_sem);
+       return ret;
+}
+
+/*
+ * To get the status of a GPIO pin on TWL4030
+ */
+int twl4030_get_gpio_datain(int gpio)
+{
+       u8 d_bnk = GET_GPIO_DATA_BANK(gpio);
+       u8 d_off = BIT_GPIODATAIN_GPIOxIN(GET_GPIO_DATA_OFF(gpio));
+       u8 base = 0;
+       int ret = 0;
+
+       if (unlikely((gpio >= TWL4030_GPIO_MAX)
+               || !(gpio_usage_count & (0x1 << gpio))))
+               return -EPERM;
+
+       base = REG_GPIODATAIN1 + d_bnk;
+       down(&gpio_sem);
+       ret = gpio_twl4030_read(base);
+       up(&gpio_sem);
+       if (ret > 0)
+               ret = (ret >> d_off) & 0x1;
+
+       return ret;
+}
+
+/*
+ * Configure PULL type for a GPIO pin on TWL4030
+ */
+int twl4030_set_gpio_pull(int gpio, int pull_dircn)
+{
+       u8 c_bnk = GET_GPIO_CTL_BANK(gpio);
+       u8 c_off = GET_GPIO_CTL_OFF(gpio);
+       u8 c_msk = 0;
+       u8 reg = 0;
+       u8 base = 0;
+       int ret = 0;
+
+       if (unlikely((gpio >= TWL4030_GPIO_MAX) ||
+               !(gpio_usage_count & (0x1 << gpio))))
+               return -EPERM;
+
+       base = REG_GPIOPUPDCTR1 + c_bnk;
+       if (pull_dircn == TWL4030_GPIO_PULL_DOWN)
+               c_msk = MASK_GPIOPUPDCTR1_GPIOxPD(c_off);
+       else if (pull_dircn == TWL4030_GPIO_PULL_UP)
+               c_msk = MASK_GPIOPUPDCTR1_GPIOxPU(c_off);
+
+       down(&gpio_sem);
+       ret = gpio_twl4030_read(base);
+       if (ret >= 0) {
+               /* clear the previous up/down values */
+               reg = (u8) (ret);
+               reg &= ~(MASK_GPIOPUPDCTR1_GPIOxPU(c_off) |
+                       MASK_GPIOPUPDCTR1_GPIOxPD(c_off));
+               reg |= c_msk;
+               ret = gpio_twl4030_write(base, reg);
+       }
+       up(&gpio_sem);
+       return ret;
+}
+
+/*
+ * Configure Edge control for a GPIO pin on TWL4030
+ */
+int twl4030_set_gpio_edge_ctrl(int gpio, int edge)
+{
+       u8 c_bnk = GET_GPIO_CTL_BANK(gpio);
+       u8 c_off = GET_GPIO_CTL_OFF(gpio);
+       u8 c_msk = 0;
+       u8 reg = 0;
+       u8 base = 0;
+       int ret = 0;
+
+       if (unlikely((gpio >= TWL4030_GPIO_MAX)
+               || !(gpio_usage_count & (0x1 << gpio))))
+               return -EPERM;
+
+       base = REG_GPIO_EDR1 + c_bnk;
+
+       if (edge & TWL4030_GPIO_EDGE_RISING)
+               c_msk |= MASK_GPIO_EDR1_GPIOxRISING(c_off);
+
+       if (edge & TWL4030_GPIO_EDGE_FALLING)
+               c_msk |= MASK_GPIO_EDR1_GPIOxFALLING(c_off);
+
+       down(&gpio_sem);
+       ret = gpio_twl4030_read(base);
+       if (ret >= 0) {
+               /* clear the previous rising/falling values */
+               reg =
+               (u8) (ret &
+                       ~(MASK_GPIO_EDR1_GPIOxFALLING(c_off) |
+                       MASK_GPIO_EDR1_GPIOxRISING(c_off)));
+               reg |= c_msk;
+               ret = gpio_twl4030_write(base, reg);
+       }
+       up(&gpio_sem);
+       return ret;
+}
+
+/*
+ * Configure debounce timing value for a GPIO pin on TWL4030
+ */
+int twl4030_set_gpio_debounce(int gpio, int enable)
+{
+       u8 d_bnk = GET_GPIO_DATA_BANK(gpio);
+       u8 d_msk = MASK_GPIO_DEBEN_GPIOxDEB(GET_GPIO_DATA_OFF(gpio));
+       u8 reg = 0;
+       u8 base = 0;
+       int ret = 0;
+
+       if (unlikely((gpio >= TWL4030_GPIO_MAX)
+               || !(gpio_usage_count & (0x1 << gpio))))
+               return -EPERM;
+
+       base = REG_GPIO_DEBEN1 + d_bnk;
+       down(&gpio_sem);
+       ret = gpio_twl4030_read(base);
+       if (ret >= 0) {
+               if (enable)
+                       reg = (u8) ((ret) | (d_msk));
+               else
+                       reg = (u8) ((ret) & ~(d_msk));
+
+               ret = gpio_twl4030_write(base, reg);
+       }
+       up(&gpio_sem);
+       return ret;
+}
+
+/*
+ * Configure Card detect for GPIO pin on TWL4030
+ */
+int twl4030_set_gpio_card_detect(int gpio, int enable)
+{
+       u8 reg = 0;
+       u8 msk = (1 << gpio);
+       int ret = 0;
+
+       /* Only GPIO 0 or 1 can be used for CD feature.. */
+       if (unlikely((gpio >= TWL4030_GPIO_MAX)
+               || !(gpio_usage_count & (0x1 << gpio))
+               || (gpio >= TWL4030_GPIO_MAX_CD))) {
+               return -EPERM;
+       }
+
+       down(&gpio_sem);
+       ret = gpio_twl4030_read(REG_GPIO_CTRL);
+       if (ret >= 0) {
+               if (enable)
+                       reg = (u8) (ret | msk);
+               else
+                       reg = (u8) (ret & ~msk);
+
+               ret = gpio_twl4030_write(REG_GPIO_CTRL, reg);
+       }
+       up(&gpio_sem);
+       return (ret);
+}
+
+/**** MODULE FUNCTIONS ***/
+
+/*
+ * To configure TWL4030 GPIO module registers
+ */
+static inline int gpio_twl4030_write(u8 address, u8 data)
+{
+       int ret = 0;
+
+       ret = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, data, address);
+       return ret;
+}
+
+/*
+ * To read a TWL4030 GPIO module register
+ */
+static inline int gpio_twl4030_read(u8 address)
+{
+       u8 data;
+       int ret = 0;
+
+       ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, &data, address);
+       if (ret >= 0)
+               ret = data;
+       return ret;
+}
+
+/*
+ * gpio_unmask_thread() runs as a kernel thread.  It is awakened by the unmask
+ * method for the GPIO interrupts.  It unmasks all of the GPIO interrupts
+ * specified in the gpio_pending_unmask bitmask.  We have to do the unmasking
+ * in a kernel thread rather than directly in the unmask method because of the
+ * need to access the TWL4030 via the I2C bus.  Note that we don't need to be
+ * concerned about race conditions where the request to unmask a GPIO interrupt
+ * has already been cancelled before this thread does the unmasking.  If a GPIO
+ * interrupt is improperly unmasked, then the IRQ handler for it will mask it
+ * when an interrupt occurs.
+ */
+static int twl4030_gpio_unmask_thread(void *data)
+{
+       current->flags |= PF_NOFREEZE;
+
+       while (!kthread_should_stop()) {
+               int irq;
+               unsigned int gpio_unmask;
+
+               local_irq_disable();
+               gpio_unmask = gpio_pending_unmask;
+               gpio_pending_unmask = 0;
+               local_irq_enable();
+
+               for (irq = IH_TWL4030_GPIO_BASE; 0 != gpio_unmask;
+                               gpio_unmask >>= 1, irq++) {
+                       if (gpio_unmask & 0x1)
+                               twl4030_gpio_unmask(irq);
+               }
+
+               local_irq_disable();
+               if (!gpio_pending_unmask)
+                       set_current_state(TASK_INTERRUPTIBLE);
+               local_irq_enable();
+
+               schedule();
+       }
+       set_current_state(TASK_RUNNING);
+       return 0;
+}
+
+/*
+ * do_twl4030_gpio_irq() is the desc->handle method for each of the twl4030
+ * gpio interrupts.  It executes in kernel thread context.
+ * On entry, cpu interrupts are enabled.
+ */
+static void do_twl4030_gpio_irq(unsigned int irq, irq_desc_t *desc)
+{
+       struct irqaction *action;
+       const unsigned int cpu = smp_processor_id();
+
+       desc->status |= IRQ_LEVEL;
+
+       /*
+        * Acknowledge, clear _AND_ disable the interrupt.
+        */
+       twl4030_gpio_mask_and_ack(irq);
+
+       if (!desc->depth) {
+               kstat_cpu(cpu).irqs[irq]++;
+
+               action = desc->action;
+               if (action) {
+                       int ret;
+                       int status = 0;
+                       int retval = 0;
+                       do {
+                               /* Call the ISR with cpu interrupts enabled. */
+                               ret = action->handler(irq, action->dev_id);
+                               if (ret == IRQ_HANDLED)
+                                       status |= action->flags;
+                               retval |= ret;
+                               action = action->next;
+                       } while (action);
+
+                       if (retval != IRQ_HANDLED)
+                               printk(KERN_ERR "ISR for TWL4030 GPIO"
+                                       " irq %d can't handle interrupt\n",
+                                       irq);
+
+                       if (!desc->depth)
+                               twl4030_gpio_unmask(irq);
+               }
+       }
+}
+
+/*
+ * do_twl4030_gpio_module_irq() is the desc->handle method for the twl4030 gpio
+ * module interrupt.  It executes in kernel thread context.
+ * This is a chained interrupt, so there is no desc->action method for it.
+ * We query the gpio module interrupt controller in the twl4030 to determine
+ * which gpio lines are generating interrupt requests, and then call the
+ * desc->handle method for each gpio that needs service.
+ * On entry, cpu interrupts are disabled.
+ */
+static void do_twl4030_gpio_module_irq(unsigned int irq, irq_desc_t *desc)
+{
+       const unsigned int cpu = smp_processor_id();
+
+       desc->status |= IRQ_LEVEL;
+       /*
+       * The desc->handle method would normally call the desc->chip->ack
+       * method here, but we won't bother since our ack method is NULL.
+       */
+       if (!desc->depth) {
+               int gpio_irq;
+               unsigned int gpio_isr;
+
+               kstat_cpu(cpu).irqs[irq]++;
+               local_irq_enable();
+
+               down(&gpio_sem);
+               if (gpio_read_isr(&gpio_isr))
+                       gpio_isr = 0;
+               up(&gpio_sem);
+
+               for (gpio_irq = IH_TWL4030_GPIO_BASE; 0 != gpio_isr;
+                       gpio_isr >>= 1, gpio_irq++) {
+                       if (gpio_isr & 0x1) {
+                               irq_desc_t *d = irq_desc + gpio_irq;
+                               d->handle_irq(gpio_irq, d);
+                       }
+               }
+
+               local_irq_disable();
+               /*
+                * Here is where we should call the unmask method, but again we
+                * won't bother since it is NULL.
+                */
+       }
+}
+
+/* TWL4030 Initialization module */
+static int __init gpio_twl4030_init(void)
+{
+       int ret;
+       int irq = 0;
+
+       /* init the global locking sem */
+       sema_init(&gpio_sem, 1);
+
+       /* All GPIO interrupts are initially masked */
+       gpio_pending_unmask = 0;
+       gpio_imr_shadow = GPIO_32_MASK;
+       ret = gpio_write_imr(gpio_imr_shadow);
+       if (!ret) {
+               /*
+               * Create a kernel thread to handle deferred unmasking of gpio
+               * interrupts.
+               */
+               gpio_unmask_thread = kthread_create(twl4030_gpio_unmask_thread,
+                       NULL, "twl4030 gpio");
+               if (!gpio_unmask_thread) {
+                       printk(KERN_ERR
+                               "%s: could not create twl4030 gpio unmask thread!\n",
+                               __FUNCTION__);
+                       ret = -ENOMEM;
+               }
+       }
+
+       if (!ret) {
+               /* install an irq handler for each of the gpio interrupts */
+               for (irq = IH_TWL4030_GPIO_BASE; irq < IH_TWL4030_GPIO_END;
+                       irq++) {
+                       set_irq_chip(irq, &twl4030_gpio_irq_chip);
+                       set_irq_handler(irq, do_twl4030_gpio_irq);
+                       set_irq_flags(irq, IRQF_VALID);
+               }
+
+               /*
+                * Install an irq handler to demultiplex the gpio module
+                * interrupt.
+                */
+               set_irq_chip(TWL4030_MODIRQ_GPIO,
+                       &twl4030_gpio_module_irq_chip);
+               set_irq_chained_handler(TWL4030_MODIRQ_GPIO,
+                       do_twl4030_gpio_module_irq);
+       }
+
+       printk(KERN_INFO "TWL4030 GPIO Demux: IRQ Range %d to %d,"
+               " Initialization %s\n", IH_TWL4030_GPIO_BASE,
+               IH_TWL4030_GPIO_END, (ret) ? "Failed" : "Success");
+       return ret;
+}
+
+/* TWL GPIO exit module */
+static void __exit gpio_twl4030_exit(void)
+{
+       int irq;
+
+       /* uninstall the gpio demultiplexing interrupt handler */
+       set_irq_handler(TWL4030_MODIRQ_GPIO, NULL);
+       set_irq_flags(TWL4030_MODIRQ_GPIO, 0);
+
+       /* uninstall the irq handler for each of the gpio interrupts */
+       for (irq = IH_TWL4030_GPIO_BASE; irq < IH_TWL4030_GPIO_END; irq++) {
+               set_irq_handler(irq, NULL);
+               set_irq_flags(irq, 0);
+       }
+
+       /* stop the gpio unmask kernel thread */
+       if (gpio_unmask_thread) {
+               kthread_stop(gpio_unmask_thread);
+               gpio_unmask_thread = NULL;
+       }
+}
+
+module_init(gpio_twl4030_init);
+module_exit(gpio_twl4030_exit);
+
+EXPORT_SYMBOL(twl4030_request_gpio);
+EXPORT_SYMBOL(twl4030_free_gpio);
+EXPORT_SYMBOL(twl4030_set_gpio_direction);
+EXPORT_SYMBOL(twl4030_set_gpio_dataout);
+EXPORT_SYMBOL(twl4030_get_gpio_datain);
+EXPORT_SYMBOL(twl4030_set_gpio_pull);
+EXPORT_SYMBOL(twl4030_set_gpio_edge_ctrl);
+EXPORT_SYMBOL(twl4030_set_gpio_debounce);
+EXPORT_SYMBOL(twl4030_set_gpio_card_detect);
+
+MODULE_AUTHOR("Texas Instruments, Inc.");
+MODULE_DESCRIPTION("GPIO interface for TWL4030");
+MODULE_LICENSE("GPL");
index bd707b86c114a9b7fa323a46b51ccb15fd410b9f..31200944161f656d25b09e69d8c2ea60a2cdae2c 100644 (file)
@@ -214,6 +214,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_PXA27x
        tristate "PXA27x keyboard support"
        depends on PXA27x
@@ -250,4 +260,10 @@ config KEYBOARD_GPIO
          To compile this driver as a module, choose M here: the
          module will be called gpio-keys.
 
+config KEYBOARD_TSC2301
+       tristate "TSC2301 keypad support"
+       depends on SPI_TSC2301
+       help
+         Say Y here for if you are using the keypad features of TSC2301.
+
 endif
index 28d211b87b1486ea95ce661910c77e197f7d4a77..0e36829b24384628e2401fc78158f4e03059e869 100644 (file)
@@ -17,8 +17,10 @@ obj-$(CONFIG_KEYBOARD_CORGI)         += corgikbd.o
 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_KEYBOARD_OMAP)             += omap-keypad.o
+obj-$(CONFIG_OMAP_PS2)                 += innovator_ps2.o
 obj-$(CONFIG_KEYBOARD_PXA27x)          += pxa27x_keyboard.o
-obj-$(CONFIG_KEYBOARD_AAED2000)                += aaed2000_kbd.o
+obj-$(CONFIG_KEYBOARD_AAED2000)         += aaed2000_kbd.o
 obj-$(CONFIG_KEYBOARD_GPIO)            += gpio_keys.o
+obj-$(CONFIG_KEYBOARD_TSC2301)         += tsc2301_kp.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 3a228634f1015239aae5f669c035b401613f90b7..6aea1b16b9e864fcc71fbd7f23e7c4a122156db2 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())
diff --git a/drivers/input/keyboard/tsc2301_kp.c b/drivers/input/keyboard/tsc2301_kp.c
new file mode 100644 (file)
index 0000000..da14be5
--- /dev/null
@@ -0,0 +1,559 @@
+/*
+ * TSC2301 keypad driver
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation
+ *
+ * Written by Jarkko Oikarinen
+ * Rewritten by Juha Yrjola <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/module.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+
+#ifdef CONFIG_ARCH_OMAP
+#include <asm/arch/gpio.h>
+#endif
+
+#include <linux/spi/tsc2301.h>
+
+#define TSC2301_KEYBOARD_PRODUCT_ID      0x0051
+#define TSC2301_KEYBOARD_PRODUCT_VERSION 0x0001
+#define TSC2301_DEBOUNCE_TIME_2MS        0x0000
+#define TSC2301_DEBOUNCE_TIME_10MS       0x0800
+#define TSC2301_DEBOUNCE_TIME_20MS       0x1000
+#define TSC2301_DEBOUNCE_TIME_50MS       0x1800
+#define TSC2301_DEBOUNCE_TIME_60MS       0x2000
+#define TSC2301_DEBOUNCE_TIME_80MS       0x2800
+#define TSC2301_DEBOUNCE_TIME_100MS      0x3000
+#define TSC2301_DEBOUNCE_TIME_120MS      0x3800
+
+#define TSC2301_DEBOUNCE_TIME          TSC2301_DEBOUNCE_TIME_20MS
+
+#define TSC2301_POLL_TIME              30
+
+struct tsc2301_kp {
+       struct input_dev        *idev;
+       char                    phys[32];
+       spinlock_t              lock;
+       struct mutex            mutex;
+       struct timer_list       timer;
+       u16                     keys_pressed;
+       unsigned                pending:1;
+       unsigned                user_disabled:1;
+       unsigned                disable_depth;
+
+       struct spi_transfer     read_xfer[4];
+       struct spi_message      read_msg;
+       u16                     state;
+       u16                     data;
+       u16                     mask;
+
+       int                     irq;
+       s16                     keymap[16];
+
+       int                     (*get_keyb_irq_state)(struct device *dev);
+};
+
+static inline int tsc2301_kp_disabled(struct tsc2301 *tsc)
+{
+       return tsc->kp->disable_depth != 0;
+}
+
+static inline void tsc2301_kp_set_keypressed_state(struct tsc2301 *tsc)
+{
+       struct tsc2301_kp *kp = tsc->kp;
+
+       /* kp->state is updated only if we don't have the callback */
+       if (kp->get_keyb_irq_state != NULL) {
+               if (kp->get_keyb_irq_state(&tsc->spi->dev))
+                       kp->state = 1 << 15;
+               else
+                       kp->state = 0;
+       }
+}
+
+static inline int tsc2301_kp_key_is_pressed(struct tsc2301 *tsc)
+{
+       return tsc->kp->state & (1 << 15);
+}
+
+static void tsc2301_kp_send_key_events(struct tsc2301 *tsc,
+                                      u16 prev_state,
+                                      u16 new_state)
+{
+       struct tsc2301_kp *kp = tsc->kp;
+       u16 common, released, pressed;
+       int i;
+
+       common = prev_state & new_state;
+       released = common ^ prev_state;
+       pressed = common ^ new_state;
+       if (!released && !pressed)
+               return;
+       for (i = 0; i < 16 && (released || pressed); i++) {
+               if (released & 1) {
+                       dev_dbg(&tsc->spi->dev, "key %d released\n", i);
+                       input_report_key(kp->idev, kp->keymap[i], 0);
+               }
+               released >>= 1;
+               if (pressed & 1) {
+                       dev_dbg(&tsc->spi->dev, "key %d pressed\n", i);
+                       input_report_key(kp->idev, kp->keymap[i], 1);
+               }
+               pressed >>= 1;
+       }
+       input_sync(kp->idev);
+}
+
+static inline void tsc2301_kp_release_all_keys(struct tsc2301 *tsc)
+{
+       struct tsc2301_kp *kp = tsc->kp;
+       unsigned long flags;
+       int keys_pressed;
+
+       spin_lock_irqsave(&kp->lock, flags);
+       keys_pressed = kp->keys_pressed;
+       kp->keys_pressed = 0;
+       spin_unlock_irqrestore(&kp->lock, flags);
+       if (keys_pressed)
+               tsc2301_kp_send_key_events(tsc, keys_pressed, 0);
+}
+
+static inline void _filter_out(struct tsc2301 *tsc, u16 prev_state,
+                              u16 *new_state, int row1, int row2, u8 rect_pat)
+{
+       u16 mask;
+
+       mask = (rect_pat << (row1 * 4)) | (rect_pat << (row2 * 4));
+       mask &= ~prev_state;
+       *new_state &= ~mask;
+       dev_dbg(&tsc->spi->dev, "filtering ghost keys %02x\n", mask);
+}
+
+static void tsc2301_filter_ghost_keys(struct tsc2301 *tsc, u16 prev_state,
+                                     u16 *new_state)
+{
+       int row1, row2;
+       u16 key_map;
+       u16 row1_map;
+       static const u8 rect_pat[] = {
+               0x3, 0x5, 0x9, 0x6, 0xa, 0xc, 0,
+       };
+
+       key_map = *new_state;
+       for (row1 = 0; row1 < 4; row1++) {
+               row1_map = (key_map >> (row1 * 4)) & 0xf;
+               if (!row1_map)
+                       continue;
+               for (row2 = row1 + 1; row2 < 4; row2++) {
+                       u16 rect_map = (key_map >> (row2 * 4)) & 0xf;
+                       const u8 *rp;
+
+                       rect_map &= row1_map;
+                       if (!rect_map)
+                               continue;
+                       for (rp = rect_pat; *rp; rp++)
+                               if ((rect_map & *rp) == *rp)
+                                       _filter_out(tsc, prev_state, new_state,
+                                                   row1, row2, *rp);
+               }
+       }
+}
+
+static void tsc2301_kp_timer(unsigned long arg)
+{
+       struct tsc2301 *tsc = (void *) arg;
+       int r;
+
+       /* This needs to be done early enough, since reading the key data
+        * register clears the IRQ line, which may be used to determine
+        * the key pressed state.
+        */
+       tsc2301_kp_set_keypressed_state(tsc);
+       r = spi_async(tsc->spi, &tsc->kp->read_msg);
+       if (unlikely(r < 0 && printk_ratelimit()))
+               dev_err(&tsc->spi->dev, "kp: spi_async() failed");
+}
+
+static void tsc2301_kp_rx(void *arg)
+{
+       struct tsc2301 *tsc = arg;
+       struct tsc2301_kp *kp = tsc->kp;
+       unsigned long flags;
+       int key_pressed;
+       u16 kp_data;
+
+       kp_data = kp->data;
+       key_pressed = tsc2301_kp_key_is_pressed(tsc);
+       dev_dbg(&tsc->spi->dev, "KP data %04x (%s)\n",
+               kp_data, key_pressed ? "pressed" : "not pressed");
+       if (!key_pressed)
+               kp_data = 0;
+       else
+               tsc2301_filter_ghost_keys(tsc, kp->keys_pressed, &kp_data);
+       tsc2301_kp_send_key_events(tsc, kp->keys_pressed, kp_data);
+       kp->keys_pressed = kp_data;
+       spin_lock_irqsave(&kp->lock, flags);
+       if (likely(!tsc2301_kp_disabled(tsc))) {
+               if (likely(key_pressed))
+                       mod_timer(&kp->timer,
+                                jiffies + msecs_to_jiffies(TSC2301_POLL_TIME));
+               else {
+                       kp->pending = 0;
+                       enable_irq(kp->irq);
+               }
+       } else
+               kp->pending = 0;
+       spin_unlock_irqrestore(&kp->lock, flags);
+}
+
+static irqreturn_t tsc2301_kp_irq_handler(int irq, void *dev_id)
+{
+       struct tsc2301 *tsc = dev_id;
+       struct tsc2301_kp *kp = tsc->kp;
+       unsigned long flags;
+
+       spin_lock_irqsave(&kp->lock, flags);
+       BUG_ON(kp->pending);
+       if (tsc2301_kp_disabled(tsc)) {
+               spin_unlock_irqrestore(&kp->lock, flags);
+               return IRQ_HANDLED;
+       }
+       kp->pending = 1;
+       disable_irq_nosync(irq);
+       spin_unlock_irqrestore(&kp->lock, flags);
+       tsc2301_kp_timer((unsigned long) tsc);
+       return IRQ_HANDLED;
+}
+
+static void tsc2301_kp_start_scan(struct tsc2301 *tsc)
+{
+       tsc2301_write_reg(tsc, TSC2301_REG_KPMASK, tsc->kp->mask);
+       tsc2301_write_reg(tsc, TSC2301_REG_KEY, TSC2301_DEBOUNCE_TIME);
+}
+
+static void tsc2301_kp_stop_scan(struct tsc2301 *tsc)
+{
+       tsc2301_write_reg(tsc, TSC2301_REG_KEY, 1 << 14);
+       tsc2301_write_reg(tsc, TSC2301_REG_KPMASK, 0xffff);
+}
+
+/* Must be called with the mutex held */
+static void tsc2301_kp_enable(struct tsc2301 *tsc)
+{
+       struct tsc2301_kp *kp = tsc->kp;
+       unsigned long flags;
+
+       spin_lock_irqsave(&kp->lock, flags);
+       BUG_ON(!tsc2301_kp_disabled(tsc));
+       if (--kp->disable_depth != 0) {
+               spin_unlock_irqrestore(&kp->lock, flags);
+               return;
+       }
+       if (kp->keys_pressed)
+               kp->pending = 1;
+       spin_unlock_irqrestore(&kp->lock, flags);
+
+       set_irq_type(kp->irq, IRQT_FALLING);
+       tsc2301_kp_start_scan(tsc);
+       if (kp->pending)
+               /* continue an interrupted polling */
+               mod_timer(&kp->timer,
+                         jiffies + msecs_to_jiffies(TSC2301_POLL_TIME));
+       else
+               enable_irq(kp->irq);
+}
+
+/* Must be called with the mutex held */
+static int tsc2301_kp_disable(struct tsc2301 *tsc, int release_keys)
+{
+       struct tsc2301_kp *kp = tsc->kp;
+       unsigned long flags;
+
+       spin_lock_irqsave(&kp->lock, flags);
+       if (kp->disable_depth++ != 0) {
+               spin_unlock_irqrestore(&kp->lock, flags);
+               goto out;
+       }
+       if (!kp->pending)
+               disable_irq_nosync(kp->irq);
+
+       while (kp->pending) {
+               spin_unlock_irqrestore(&kp->lock, flags);
+               msleep(1);
+               spin_lock_irqsave(&kp->lock, flags);
+       }
+       spin_unlock_irqrestore(&kp->lock, flags);
+
+       tsc2301_kp_stop_scan(tsc);
+       set_irq_type(kp->irq, IRQT_NOEDGE);
+out:
+       if (release_keys)
+               tsc2301_kp_release_all_keys(tsc);
+
+       return 0;
+}
+
+/* The following workaround is needed for a HW bug triggered by the
+ * following:
+ * 1. keep any key pressed
+ * 2. disable keypad
+ * 3. release all keys
+ * 4. reenable keypad
+ * 5. disable touch screen controller
+ *
+ * After this the keypad scanner will get stuck in busy state and won't
+ * report any interrupts for further keypresses. One way to recover is to
+ * restart the keypad scanner whenever we enable / disable the
+ * touchscreen controller.
+ */
+void tsc2301_kp_restart(struct tsc2301 *tsc)
+{
+       struct tsc2301_kp *kp = tsc->kp;
+
+       mutex_lock(&kp->mutex);
+       if (!kp->user_disabled) {
+               tsc2301_kp_disable(tsc, 0);
+               tsc2301_kp_enable(tsc);
+       }
+       mutex_unlock(&kp->mutex);
+}
+
+static ssize_t tsc2301_kp_disable_show(struct device *dev,
+                                      struct device_attribute *attr, char *buf)
+{
+       struct tsc2301          *tsc = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%u\n", tsc2301_kp_disabled(tsc) ? 1 : 0);
+}
+
+static ssize_t tsc2301_kp_disable_store(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       struct tsc2301          *tsc = dev_get_drvdata(dev);
+       struct tsc2301_kp       *kp = tsc->kp;
+       char *endp;
+       int i;
+
+       i = simple_strtoul(buf, &endp, 10);
+       i = i ? 1 : 0;
+
+       mutex_lock(&kp->mutex);
+       if (i == kp->user_disabled) {
+               mutex_unlock(&kp->mutex);
+               return count;
+       }
+       kp->user_disabled = i;
+
+       if (i)
+               tsc2301_kp_disable(tsc, 1);
+       else
+               tsc2301_kp_enable(tsc);
+       mutex_unlock(&kp->mutex);
+
+       return count;
+}
+
+static DEVICE_ATTR(disable_kp, 0664, tsc2301_kp_disable_show,
+                  tsc2301_kp_disable_store);
+
+static const u16 tsc2301_kp_read_data = 0x8000 | TSC2301_REG_KPDATA;
+static const u16 tsc2301_kp_read_state = 0x8000 | TSC2301_REG_KEY;
+
+static void tsc2301_kp_setup_spi_xfer(struct tsc2301 *tsc)
+{
+       struct tsc2301_kp *kp = tsc->kp;
+       struct spi_message *m = &kp->read_msg;
+       struct spi_transfer *x = &kp->read_xfer[0];
+
+       spi_message_init(&kp->read_msg);
+
+       if (kp->get_keyb_irq_state == NULL) {
+               /* No platform specific way for determining the keypress
+                * state, so we'll need an extra status register read.
+                */
+               x->tx_buf = &tsc2301_kp_read_state;
+               x->len = 2;
+               spi_message_add_tail(x, m);
+               x++;
+
+               x->rx_buf = &kp->state;
+               x->len = 2;
+               x->cs_change = 1;
+               spi_message_add_tail(x, m);
+               x++;
+       }
+
+       x->tx_buf = &tsc2301_kp_read_data;
+       x->len = 2;
+       spi_message_add_tail(x, m);
+       x++;
+
+       x->rx_buf = &kp->data;
+       x->len = 2;
+       spi_message_add_tail(x, m);
+
+       m->complete = tsc2301_kp_rx;
+       m->context = tsc;
+}
+
+#ifdef CONFIG_PM
+int tsc2301_kp_suspend(struct tsc2301 *tsc)
+{
+       struct tsc2301_kp *kp = tsc->kp;
+
+       mutex_lock(&kp->mutex);
+       tsc2301_kp_disable(tsc, 1);
+       mutex_unlock(&kp->mutex);
+       return 0;
+}
+
+void tsc2301_kp_resume(struct tsc2301 *tsc)
+{
+       struct tsc2301_kp *kp = tsc->kp;
+
+       mutex_lock(&kp->mutex);
+       tsc2301_kp_enable(tsc);
+       mutex_unlock(&kp->mutex);
+}
+#endif
+
+int __devinit tsc2301_kp_init(struct tsc2301 *tsc,
+                             struct tsc2301_platform_data *pdata)
+{
+       struct input_dev *idev;
+       struct tsc2301_kp *kp;
+       int r, i;
+       u16 mask;
+
+       if (pdata->keyb_int < 0) {
+               dev_err(&tsc->spi->dev, "need kbirq");
+               return -EINVAL;
+       }
+
+       kp = kzalloc(sizeof(*kp), GFP_KERNEL);
+       if (kp == NULL)
+               return -ENOMEM;
+       tsc->kp = kp;
+
+       kp->irq = pdata->keyb_int;
+       spin_lock_init(&kp->lock);
+       mutex_init(&kp->mutex);
+
+       init_timer(&kp->timer);
+       kp->timer.data = (unsigned long) tsc;
+       kp->timer.function = tsc2301_kp_timer;
+
+       kp->get_keyb_irq_state = pdata->get_keyb_irq_state;
+
+       idev = input_allocate_device();
+       if (idev == NULL) {
+               r = -ENOMEM;
+               goto err1;
+       }
+       idev->name = "TSC2301 keypad";
+       snprintf(kp->phys, sizeof(kp->phys), "%s/input-kp", tsc->spi->dev.bus_id);
+       idev->phys = kp->phys;
+
+       mask = 0;
+       idev->evbit[0] = BIT(EV_KEY);
+       for (i = 0; i < 16; i++) {
+               if (pdata->keymap[i] > 0) {
+                       set_bit(pdata->keymap[i], idev->keybit);
+                       kp->keymap[i] = pdata->keymap[i];
+               } else {
+                       kp->keymap[i] = -1;
+                       mask |= 1 << i;
+               }
+       }
+
+       if (pdata->kp_rep)
+               set_bit(EV_REP, idev->evbit);
+
+       kp->idev = idev;
+
+       tsc2301_kp_setup_spi_xfer(tsc);
+
+       r = device_create_file(&tsc->spi->dev, &dev_attr_disable_kp);
+       if (r < 0)
+               goto err2;
+
+       tsc2301_kp_start_scan(tsc);
+
+       /* IRQ mode 0 is faulty, it can cause the KBIRQ to get stuck.
+        * Mode 2 deasserts the IRQ at:
+        * - HW or SW reset
+        * - Setting SCS flag in REG_KEY register
+        * - Releasing all keys
+        * - Reading the REG_KPDATA
+        */
+       tsc2301_write_kbc(tsc, 2);
+
+       tsc2301_write_reg(tsc, TSC2301_REG_KPMASK, mask);
+       kp->mask = mask;
+
+       set_irq_type(kp->irq, IRQT_FALLING);
+
+       r = request_irq(kp->irq, tsc2301_kp_irq_handler, SA_SAMPLE_RANDOM,
+                       "tsc2301-kp", tsc);
+       if (r < 0) {
+               dev_err(&tsc->spi->dev, "unable to get kbirq IRQ");
+               goto err3;
+       }
+       set_irq_wake(kp->irq, 1);
+
+       /* We need to read the register once..? */
+       tsc2301_read_reg(tsc, TSC2301_REG_KPDATA);
+
+       r = input_register_device(idev);
+       if (r < 0) {
+               dev_err(&tsc->spi->dev, "can't register keypad device\n");
+               goto err4;
+       }
+
+       return 0;
+
+err4:
+       free_irq(kp->irq, tsc);
+err3:
+       tsc2301_kp_stop_scan(tsc);
+       device_remove_file(&tsc->spi->dev, &dev_attr_disable_kp);
+err2:
+       input_free_device(kp->idev);
+err1:
+       kfree(kp);
+       return r;
+}
+
+void __devexit tsc2301_kp_exit(struct tsc2301 *tsc)
+{
+       struct tsc2301_kp *kp = tsc->kp;
+
+       tsc2301_kp_disable(tsc, 1);
+       input_unregister_device(kp->idev);
+       free_irq(kp->irq, tsc);
+       device_remove_file(&tsc->spi->dev, &dev_attr_disable_kp);
+
+       kfree(kp);
+}
index 5e640aeb03cdfa0ac1eb781c6232c6b3b117ff0c..22cc23cc2ef195407b8293958409d3682e2d404f 100644 (file)
@@ -164,6 +164,18 @@ config TOUCHSCREEN_UCB1400
          To compile this driver as a module, choose M here: the
          module will be called ucb1400_ts.
 
+config TOUCHSCREEN_TSC2301
+       tristate "TSC2301 touchscreen support"
+       depends on SPI_TSC2301
+       help
+         Say Y here for if you are using the touchscreen features of TSC2301.
+
+config TOUCHSCREEN_TSC2046
+       tristate "TSC2046 touchscreen support"
+       default MACH_OMAP2430SDP
+         help
+         Say Y here for if you are using the touchscreen features of TSC2046
+
 config TOUCHSCREEN_USB_COMPOSITE
        tristate "USB Touchscreen Driver"
        select USB
index 2f86d6ad06d3a193fedcdd01b2a4dd7dbb498491..5489b7ed4c7b7ebcadba59d5e9082527ee437cd2 100644 (file)
@@ -17,3 +17,7 @@ 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/
+obj-$(CONFIG_TOUCHSCREEN_TSC2301)      += tsc2301_ts.o
+obj-$(CONFIG_TOUCHSCREEN_TSC2046)      += tsc2046_ts.o
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/tsc2046_ts.c b/drivers/input/touchscreen/tsc2046_ts.c
new file mode 100644 (file)
index 0000000..4689fb6
--- /dev/null
@@ -0,0 +1,564 @@
+/*
+ * TSC2046 Touchscreen driver
+ *
+ * Author: Kevin Hilman, MontaVista Software, Inc. <source@mvista.com>
+ *
+ * Communication details from original TI driver
+ * Copyright (C) 2004-2005 Texas Instruments, Inc.
+ *
+ * Structure based heavily on TSC2301 driver
+ * Copyright (C) 2005-2006 Nokia Corporation
+ *
+ * 2007 (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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+
+#ifdef CONFIG_ARCH_OMAP
+#include <asm/arch/gpio.h>
+#endif
+
+#include <linux/spi/tsc2046.h>
+
+/* TSC2046 commands */
+#define START_BYTE             0x8000
+#define        X_CMDWD                 0xd300
+#define Y_CMDWD                        0x9300
+#define Z1_CMDWD               0xb300
+#define Z2_CMDWD               0xc300
+
+#define TSC2046_TS_SCAN_TIME   1
+#define MAX_12BIT              ((1 << 12) - 1)
+
+struct tsc2046_ts {
+       struct input_dev        *idev;
+       char                    phys[32];
+       struct timer_list       timer;
+       spinlock_t              lock;
+
+       struct spi_transfer     read_xfer[3];
+       struct spi_message      read_msg;
+       struct spi_message      enable_msg;
+       u16                     data[5];
+
+       u16                     x;
+       u16                     y;
+       u16                     p;
+       int                     sample_cnt;
+
+       int                     ignore_last : 1;
+       u16                     x_plate_ohm;
+       int                     max_pressure;
+       int                     touch_pressure;
+       int                     pressure_limit;
+
+       u16                     irq_enabled:1;
+       u16                     pen_down:1;
+       u16                     disabled:1;
+       u16                     pending:1;
+
+       s16                     dav_gpio;
+       int                     irq;
+};
+
+static const u16 tsc2046_ts_cmd_data[] = {
+       START_BYTE, X_CMDWD, Y_CMDWD, Z1_CMDWD, Z2_CMDWD,
+};
+
+static int device_suspended(struct device *dev)
+{
+       struct tsc2046 *tsc = dev_get_drvdata(dev);
+       return dev->power.power_state.event != PM_EVENT_ON || tsc->ts->disabled;
+}
+
+static void update_pen_state(struct tsc2046 *tsc, int x, int y, int pressure)
+{
+       struct tsc2046_ts *ts = tsc->ts;
+       int sync = 0;
+
+       if (pressure) {
+               input_report_abs(ts->idev, ABS_X, x);
+               input_report_abs(ts->idev, ABS_Y, y);
+               input_report_abs(ts->idev, ABS_PRESSURE, pressure);
+               if (!ts->pen_down)
+                       input_report_key(ts->idev, BTN_TOUCH, 1);
+               sync = 1;
+       } else if (ts->pen_down) {
+               input_report_abs(ts->idev, ABS_PRESSURE, 0);
+               input_report_key(ts->idev, BTN_TOUCH, 0);
+               sync = 1;
+       }
+
+       if (sync)
+               input_sync(ts->idev);
+
+       ts->pen_down = pressure ? 1 : 0;
+
+#ifdef VERBOSE
+       dev_dbg(&tsc->spi->dev, "x %4d y %4d p %4d\n", x, y, pressure);
+#endif
+}
+
+#define CONV_DATA(d1, d2) \
+  (((d1 & 0x7f) << 5) | ((d2 >> 11) & 0x1f))
+
+/*
+ * This procedure is called by the SPI framework after the coordinates
+ * have been read from TSC2046
+ */
+static void tsc2046_ts_rx(void *arg)
+{
+       struct tsc2046 *tsc = arg;
+       struct tsc2046_ts *ts = tsc->ts;
+       unsigned int x, y, z1, z2, pressure;
+
+       x  = CONV_DATA(ts->data[2], ts->data[3]);
+       y  = CONV_DATA(ts->data[1], ts->data[2]);
+       z1 = CONV_DATA(ts->data[3], ts->data[4]);
+       z2 = CONV_DATA(ts->data[4], 0);
+
+       if (z1) {
+               pressure = ts->x_plate_ohm * x;
+               pressure /= 4096;
+               pressure *= z2 - z1;
+               pressure /= z1;
+       } else
+               pressure = 0;
+
+       /*
+        * If pressure value is above a preset limit (pen is barely
+        * touching the screen) we can't trust the coordinate values.
+        */
+       if (pressure < ts->pressure_limit && x < MAX_12BIT && y < MAX_12BIT) {
+               ts->pressure_limit = ts->max_pressure;
+               if (ts->ignore_last) {
+                       if (ts->sample_cnt)
+                               update_pen_state(tsc, ts->x, ts->y, ts->p);
+                       ts->x = x;
+                       ts->y = y;
+                       ts->p = pressure;
+               } else
+                       update_pen_state(tsc, x, y, pressure);
+               ts->sample_cnt++;
+       }
+
+       mod_timer(&ts->timer,
+                 jiffies + msecs_to_jiffies(TSC2046_TS_SCAN_TIME));
+}
+
+static int is_pen_down(struct tsc2046_ts *ts)
+{
+       return ts->pen_down;
+}
+
+/*
+ * Timer is called every TSC2046_TS_SCAN_TIME when the pen is down
+ */
+static void tsc2046_ts_timer(unsigned long arg)
+{
+       struct tsc2046 *tsc = (void *) arg;
+       struct tsc2046_ts *ts = tsc->ts;
+       unsigned long flags;
+       int ndav;
+       int r;
+
+       spin_lock_irqsave(&ts->lock, flags);
+       ndav = omap_get_gpio_datain(ts->dav_gpio);
+       if (ndav || device_suspended(&tsc->spi->dev)) {
+               /* Pen has been lifted */
+               if (!device_suspended(&tsc->spi->dev) &&
+                   !ts->irq_enabled) {
+                       ts->irq_enabled = 1;
+                       enable_irq(ts->irq);
+               }
+               update_pen_state(tsc, 0, 0, 0);
+               ts->pending = 0;
+               spin_unlock_irqrestore(&ts->lock, flags);
+
+       } else {
+               ts->pen_down = 1;
+               spin_unlock_irqrestore(&ts->lock, flags);
+
+               r = spi_async(tsc->spi, &ts->read_msg);
+               if (r)
+                       dev_err(&tsc->spi->dev, "ts: spi_async() failed");
+       }
+}
+
+/*
+ * This interrupt is called when pen is down and first coordinates are
+ * available. That is indicated by a falling edge on DEV line.  IRQ is
+ * disabled here because while the pen is down the coordinates are
+ * read by a timer.
+ */
+static irqreturn_t tsc2046_ts_irq_handler(int irq, void *dev_id)
+{
+       struct tsc2046 *tsc = dev_id;
+       struct tsc2046_ts *ts = tsc->ts;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ts->lock, flags);
+       if (ts->irq_enabled) {
+               ts->irq_enabled = 0;
+               disable_irq(ts->irq);
+               ts->pending = 1;
+               ts->pressure_limit = ts->touch_pressure;
+               ts->sample_cnt = 0;
+               mod_timer(&ts->timer,
+                         jiffies + msecs_to_jiffies(TSC2046_TS_SCAN_TIME));
+       }
+       spin_unlock_irqrestore(&ts->lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+/* Must be called with ts->lock held */
+static void tsc2046_ts_disable(struct tsc2046 *tsc)
+{
+       struct tsc2046_ts *ts = tsc->ts;
+
+       if (ts->disabled)
+               return;
+
+       ts->disabled = 1;
+       if (!ts->pending) {
+               ts->irq_enabled = 0;
+               disable_irq(ts->irq);
+       } else {
+               while (ts->pending) {
+                       spin_unlock_irq(&ts->lock);
+                       msleep(1);
+                       spin_lock_irq(&ts->lock);
+               }
+       }
+}
+
+static void tsc2046_ts_enable(struct tsc2046 *tsc)
+{
+       struct tsc2046_ts *ts = tsc->ts;
+
+       if (!ts->disabled)
+               return;
+
+       ts->disabled = 0;
+       ts->irq_enabled = 1;
+       enable_irq(ts->irq);
+}
+
+#ifdef CONFIG_PM
+static int tsc2046_suspend(struct spi_device *spi, pm_message_t mesg)
+{
+       struct tsc2046 *tsc = dev_get_drvdata(&spi->dev);
+       struct tsc2046_ts *ts = tsc->ts;
+
+       spin_lock_irq(&ts->lock);
+       tsc2046_ts_disable(tsc);
+       spin_unlock_irq(&ts->lock);
+
+       return 0;
+}
+
+static int tsc2046_resume(struct spi_device *spi)
+{
+       struct tsc2046 *tsc = dev_get_drvdata(&spi->dev);
+       struct tsc2046_ts *ts = tsc->ts;
+
+       spin_lock_irq(&ts->lock);
+       tsc2046_ts_enable(tsc);
+       spin_unlock_irq(&ts->lock);
+
+       return 0;
+}
+#endif
+
+static void tsc2046_ts_setup_spi_xfer(struct tsc2046 *tsc)
+{
+       struct tsc2046_ts *ts = tsc->ts;
+       struct spi_message *m = &ts->read_msg;
+       struct spi_transfer *x = &ts->read_xfer[1];
+
+       spi_message_init(m);
+
+       /* read and write data in one transaction */
+       x->tx_buf = &tsc2046_ts_cmd_data;
+       x->rx_buf = &ts->data;
+       x->len    = 10;
+       spi_message_add_tail(x, m);
+
+       /* send another START_BYTE to (re)enable pen interrupts */
+       x++;
+       x->tx_buf = &tsc2046_ts_cmd_data[0];
+       x->len = 2;
+       spi_message_add_tail(x, m);
+
+       m->complete = tsc2046_ts_rx;
+       m->context = tsc;
+}
+
+static ssize_t tsc2046_ts_pen_down_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct tsc2046 *tsc = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%u\n", is_pen_down(tsc->ts));
+}
+
+static DEVICE_ATTR(pen_down, S_IRUGO, tsc2046_ts_pen_down_show, NULL);
+
+static ssize_t tsc2046_ts_disable_show(struct device *dev,
+                                      struct device_attribute *attr, char *buf)
+{
+       struct tsc2046          *tsc = dev_get_drvdata(dev);
+       struct tsc2046_ts       *ts = tsc->ts;
+
+       return sprintf(buf, "%u\n", ts->disabled);
+}
+
+static ssize_t tsc2046_ts_disable_store(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       struct tsc2046          *tsc = dev_get_drvdata(dev);
+       struct tsc2046_ts       *ts = tsc->ts;
+       char *endp;
+       int i;
+
+       i = simple_strtoul(buf, &endp, 10);
+       spin_lock_irq(&ts->lock);
+
+       if (i)
+               tsc2046_ts_disable(tsc);
+       else
+               tsc2046_ts_enable(tsc);
+
+       spin_unlock_irq(&ts->lock);
+
+       return count;
+}
+
+static DEVICE_ATTR(disable_ts, 0664, tsc2046_ts_disable_show,
+                  tsc2046_ts_disable_store);
+
+int __devinit tsc2046_ts_init(struct tsc2046 *tsc,
+                             struct tsc2046_platform_data *pdata)
+{
+       struct tsc2046_ts *ts;
+       struct input_dev *idev;
+       int dav_gpio, r;
+
+       if (pdata->dav_gpio < 0) {
+               dev_err(&tsc->spi->dev, "need DAV GPIO");
+               return -EINVAL;
+       }
+       dav_gpio = pdata->dav_gpio;
+
+       ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+       if (ts == NULL)
+               return -ENOMEM;
+       tsc->ts = ts;
+
+       ts->dav_gpio = dav_gpio;
+#ifdef CONFIG_ARCH_OMAP
+       r = omap_request_gpio(dav_gpio);
+       if (r < 0) {
+               dev_err(&tsc->spi->dev, "unable to get DAV GPIO");
+               goto err1;
+       }
+       omap_set_gpio_direction(dav_gpio, 1);
+       if (pdata->gpio_debounce) {
+               omap_set_gpio_debounce(tsc->gpio, 1);
+               omap_set_gpio_debounce_time(tsc->gpio, pdata->gpio_debounce);
+       }
+
+       ts->irq = OMAP_GPIO_IRQ(dav_gpio);
+#endif
+       setup_timer(&ts->timer, tsc2046_ts_timer, (unsigned long)tsc);
+
+       spin_lock_init(&ts->lock);
+
+       ts->x_plate_ohm = pdata->ts_x_plate_ohm ? : 280;
+       ts->max_pressure = pdata->ts_max_pressure ? : MAX_12BIT;
+       ts->touch_pressure = pdata->ts_touch_pressure ? : ts->max_pressure;
+       ts->ignore_last = pdata->ts_ignore_last;
+
+       idev = input_allocate_device();
+       if (idev == NULL) {
+               r = -ENOMEM;
+               goto err2;
+       }
+       idev->name = "TSC2046 touchscreen";
+       snprintf(ts->phys, sizeof(ts->phys),
+                "%s/input-ts", tsc->spi->dev.bus_id);
+       idev->phys = ts->phys;
+
+       idev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
+       idev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+       ts->idev = idev;
+
+       tsc2046_ts_setup_spi_xfer(tsc);
+
+       /* These parameters should perhaps be configurable? */
+       input_set_abs_params(idev, ABS_X, 0, 4096, 0, 0);
+       input_set_abs_params(idev, ABS_Y, 0, 4096, 0, 0);
+       input_set_abs_params(idev, ABS_PRESSURE, 0, 1024, 0, 0);
+
+       ts->irq_enabled = 1;
+       r = request_irq(ts->irq, tsc2046_ts_irq_handler,
+                       IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_FALLING,
+                       "tsc2046-ts", tsc);
+       if (r < 0) {
+               dev_err(&tsc->spi->dev, "unable to get DAV IRQ");
+               goto err3;
+       }
+       set_irq_wake(ts->irq, 1);
+
+       if (device_create_file(&tsc->spi->dev, &dev_attr_pen_down) < 0)
+               goto err4;
+       if (device_create_file(&tsc->spi->dev, &dev_attr_disable_ts) < 0)
+               goto err5;
+
+       r = input_register_device(idev);
+       if (r < 0) {
+               dev_err(&tsc->spi->dev, "can't register touchscreen device\n");
+               goto err6;
+       }
+
+       /* kick off a transaction to enable pen interrupts */
+       spi_async(tsc->spi, &ts->read_msg);
+
+       return 0;
+err6:
+       device_remove_file(&tsc->spi->dev, &dev_attr_disable_ts);
+err5:
+       device_remove_file(&tsc->spi->dev, &dev_attr_pen_down);
+err4:
+       free_irq(ts->irq, tsc);
+err3:
+       input_free_device(idev);
+err2:
+#ifdef CONFIG_ARCH_OMAP
+       omap_free_gpio(dav_gpio);
+#endif
+err1:
+       kfree(ts);
+       return r;
+}
+EXPORT_SYMBOL(tsc2046_ts_init);
+
+void __devexit tsc2046_ts_exit(struct tsc2046 *tsc)
+{
+       struct tsc2046_ts *ts = tsc->ts;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ts->lock, flags);
+       tsc2046_ts_disable(tsc);
+       spin_unlock_irqrestore(&ts->lock, flags);
+
+       device_remove_file(&tsc->spi->dev, &dev_attr_disable_ts);
+       device_remove_file(&tsc->spi->dev, &dev_attr_pen_down);
+
+       free_irq(ts->irq, tsc);
+       input_unregister_device(ts->idev);
+
+#ifdef CONFIG_ARCH_OMAP
+       omap_free_gpio(ts->dav_gpio);
+#endif
+       kfree(ts);
+}
+EXPORT_SYMBOL(tsc2046_ts_exit);
+
+
+static int __devinit tsc2046_probe(struct spi_device *spi)
+{
+       struct tsc2046                  *tsc;
+       struct tsc2046_platform_data    *pdata = spi->dev.platform_data;
+       int r = -ENODEV;
+
+       dev_dbg(&spi->dev, "%s\n", __FUNCTION__);
+
+       if (!pdata) {
+               dev_dbg(&spi->dev, "no platform data?\n");
+               return -ENODEV;
+       }
+
+       tsc = kzalloc(sizeof(*tsc), GFP_KERNEL);
+       if (tsc == NULL)
+               return -ENOMEM;
+
+       dev_set_drvdata(&spi->dev, tsc);
+       tsc->spi = spi;
+       spi->dev.power.power_state = PMSG_ON;
+
+       spi->mode = SPI_MODE_1;
+       spi->bits_per_word = 16;
+
+       /*
+        * The max speed might've been defined by the board-specific
+        * struct
+        */
+       if (!spi->max_speed_hz)
+               spi->max_speed_hz = TSC2046_HZ;
+       spi_setup(spi);
+
+       r = tsc2046_ts_init(tsc, pdata);
+       if (r)
+               goto err1;
+
+       return 0;
+err1:
+       kfree(tsc);
+       return r;
+}
+
+static int __devexit tsc2046_remove(struct spi_device *spi)
+{
+       struct tsc2046 *tsc = dev_get_drvdata(&spi->dev);
+
+       dev_dbg(&tsc->spi->dev, "%s\n", __FUNCTION__);
+
+       tsc2046_ts_exit(tsc);
+       kfree(tsc);
+
+       return 0;
+}
+
+static struct spi_driver tsc2046_driver = {
+       .driver = {
+                  .name = "tsc2046",
+                  .bus = &spi_bus_type,
+                  .owner = THIS_MODULE,
+       },
+       .probe = tsc2046_probe,
+       .remove = __devexit_p(tsc2046_remove),
+#ifdef CONFIG_PM
+       .suspend = tsc2046_suspend,
+       .resume = tsc2046_resume,
+#endif
+};
+
+static int __init tsc2046_init(void)
+{
+       printk("TSC2046 driver initializing\n");
+
+       return spi_register_driver(&tsc2046_driver);
+}
+module_init(tsc2046_init);
+
+static void __exit tsc2046_exit(void)
+{
+       spi_unregister_driver(&tsc2046_driver);
+}
+module_exit(tsc2046_exit);
+
+MODULE_AUTHOR("Kevin Hilman <khilman@mvista.com>");
+MODULE_LICENSE("GPL");
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");
diff --git a/drivers/input/touchscreen/tsc2301_ts.c b/drivers/input/touchscreen/tsc2301_ts.c
new file mode 100644 (file)
index 0000000..8657b56
--- /dev/null
@@ -0,0 +1,683 @@
+/*
+ * TSC2301 touchscreen driver
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation
+ *
+ * Written by Jarkko Oikarinen, Imre Deak and Juha Yrjola
+ *
+ * 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/module.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+
+#ifdef CONFIG_ARCH_OMAP
+#include <asm/arch/gpio.h>
+#endif
+
+#include <linux/spi/tsc2301.h>
+
+/**
+ * The touchscreen interface operates as follows:
+ *
+ * Initialize:
+ *    Request access to GPIO103 (DAV)
+ *    tsc2301_dav_irq_handler will trigger when DAV line goes down
+ *
+ *  1) Pen is pressed against touchscreeen
+ *  2) TSC2301 performs AD conversion
+ *  3) After the conversion is done TSC2301 drives DAV line down
+ *  4) GPIO IRQ is received and tsc2301_dav_irq_handler is called
+ *  5) tsc2301_dav_irq_handler sets up tsc2301_ts_timer in TSC2301_TS_SCAN_TIME
+ *  6) tsc2301_ts_timer disables the irq and requests spi driver
+ *     to read X, Y, Z1 and Z2
+ *  7) SPI framework calls tsc2301_ts_rx after the coordinates are read
+ *  8) tsc2301_ts_rx reports coordinates to input layer and
+ *     sets up tsc2301_ts_timer to be called after TSC2301_TS_SCAN_TIME
+ *  9) if tsc2301_tx_timer notices that the pen has been lifted, the lift event
+ *     is sent, and irq is again enabled.
+ */
+
+
+#define TSC2301_TOUCHSCREEN_PRODUCT_ID                 0x0052
+#define TSC2301_TOUCHSCREEN_PRODUCT_VERSION            0x0001
+
+#define TSC2301_TS_SCAN_TIME                           1
+
+#define TSC2301_ADCREG_CONVERSION_CTRL_BY_TSC2301      0x8000
+#define TSC2301_ADCREG_CONVERSION_CTRL_BY_HOST         0x0000
+
+#define TSC2301_ADCREG_FUNCTION_NONE                   0x0000
+#define TSC2301_ADCREG_FUNCTION_XY                     0x0400
+#define TSC2301_ADCREG_FUNCTION_XYZ                    0x0800
+#define TSC2301_ADCREG_FUNCTION_X                      0x0C00
+#define TSC2301_ADCREG_FUNCTION_Y                      0x1000
+#define TSC2301_ADCREG_FUNCTION_Z                      0x1400
+#define TSC2301_ADCREG_FUNCTION_DAT1                   0x1800
+#define TSC2301_ADCREG_FUNCTION_DAT2                   0x1C00
+#define TSC2301_ADCREG_FUNCTION_AUX1                   0x2000
+#define TSC2301_ADCREG_FUNCTION_AUX2                   0x2400
+#define TSC2301_ADCREG_FUNCTION_TEMP                   0x2800
+
+#define TSC2301_ADCREG_RESOLUTION_8BIT                 0x0100
+#define TSC2301_ADCREG_RESOLUTION_10BIT                        0x0200
+#define TSC2301_ADCREG_RESOLUTION_12BIT                        0x0300
+
+#define TSC2301_ADCREG_AVERAGING_NONE                  0x0000
+#define TSC2301_ADCREG_AVERAGING_4AVG                  0x0040
+#define TSC2301_ADCREG_AVERAGING_8AVG                  0x0080
+#define TSC2301_ADCREG_AVERAGING_16AVG                 0x00C0
+
+#define TSC2301_ADCREG_CLOCK_8MHZ                      0x0000
+#define TSC2301_ADCREG_CLOCK_4MHZ                      0x0010
+#define TSC2301_ADCREG_CLOCK_2MHZ                      0x0020
+#define TSC2301_ADCREG_CLOCK_1MHZ                      0x0030
+
+#define TSC2301_ADCREG_VOLTAGE_STAB_0US                        0x0000
+#define TSC2301_ADCREG_VOLTAGE_STAB_100US              0x0002
+#define TSC2301_ADCREG_VOLTAGE_STAB_500US              0x0004
+#define TSC2301_ADCREG_VOLTAGE_STAB_1MS                        0x0006
+#define TSC2301_ADCREG_VOLTAGE_STAB_5MS                        0x0008
+#define TSC2301_ADCREG_VOLTAGE_STAB_10MS               0x000A
+#define TSC2301_ADCREG_VOLTAGE_STAB_50MS               0x000C
+#define TSC2301_ADCREG_VOLTAGE_STAB_100MS              0x000E
+
+#define TSC2301_ADCREG_STOP_CONVERSION                 0x4000
+
+#define MAX_12BIT                                      ((1 << 12) - 1)
+
+struct tsc2301_ts {
+       struct input_dev        *idev;
+       char                    phys[32];
+       struct timer_list       timer;
+       spinlock_t              lock;
+
+       struct spi_transfer     read_xfer[2];
+       struct spi_message      read_msg;
+       u16                     data[4];
+
+       int                     hw_avg_max;
+       u16                     x;
+       u16                     y;
+       u16                     p;
+       int                     sample_cnt;
+
+       int                     ignore_last : 1;
+       u16                     x_plate_ohm;
+       int                     stab_time;
+       int                     max_pressure;
+       int                     touch_pressure;
+       int                     pressure_limit;
+
+       u16                     irq_enabled:1;
+       u16                     pen_down:1;
+       u16                     disabled:1;
+       u16                     pending:1;
+
+       int                     hw_flags;
+
+       s16                     dav_gpio;
+       int                     irq;
+};
+
+
+static const u16 tsc2301_ts_read_data = 0x8000 | TSC2301_REG_X;
+
+static int tsc2301_ts_check_config(struct tsc2301_ts *ts, int *hw_flags)
+{
+       int flags;
+
+       flags = 0;
+       switch (ts->hw_avg_max) {
+       case 0:
+               flags |= TSC2301_ADCREG_AVERAGING_NONE;
+               break;
+       case 4:
+               flags |= TSC2301_ADCREG_AVERAGING_4AVG;
+               break;
+       case 8:
+               flags |= TSC2301_ADCREG_AVERAGING_8AVG;
+               break;
+       case 16:
+               flags |= TSC2301_ADCREG_AVERAGING_16AVG;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (ts->stab_time) {
+       case 0:
+               flags |= TSC2301_ADCREG_VOLTAGE_STAB_0US;
+               break;
+       case 100:
+               flags |= TSC2301_ADCREG_VOLTAGE_STAB_100US;
+               break;
+       case 500:
+               flags |= TSC2301_ADCREG_VOLTAGE_STAB_500US;
+               break;
+       case 1000:
+               flags |= TSC2301_ADCREG_VOLTAGE_STAB_1MS;
+               break;
+       case 5000:
+               flags |= TSC2301_ADCREG_VOLTAGE_STAB_5MS;
+               break;
+       case 10000:
+               flags |= TSC2301_ADCREG_VOLTAGE_STAB_10MS;
+               break;
+       case 50000:
+               flags |= TSC2301_ADCREG_VOLTAGE_STAB_50MS;
+               break;
+       case 100000:
+               flags |= TSC2301_ADCREG_VOLTAGE_STAB_100MS;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       *hw_flags = flags;
+       return 0;
+}
+
+/*
+ * This odd three-time initialization is to work around a bug in TSC2301.
+ * See TSC2301 errata for details.
+ */
+static int tsc2301_ts_configure(struct tsc2301 *tsc, int flags)
+{
+       struct spi_transfer xfer[3];
+       struct spi_transfer *x;
+       struct spi_message m;
+       int reg = TSC2301_REG_ADC;
+       u16 val1, val2, val3;
+       u16 data[6];
+
+       val1 = TSC2301_ADCREG_CONVERSION_CTRL_BY_HOST |
+               TSC2301_ADCREG_STOP_CONVERSION |
+               TSC2301_ADCREG_FUNCTION_NONE |
+               TSC2301_ADCREG_RESOLUTION_12BIT |
+               TSC2301_ADCREG_AVERAGING_NONE |
+               TSC2301_ADCREG_CLOCK_2MHZ |
+               TSC2301_ADCREG_VOLTAGE_STAB_100MS;
+
+       val2 = TSC2301_ADCREG_CONVERSION_CTRL_BY_HOST |
+               TSC2301_ADCREG_FUNCTION_XYZ |
+               TSC2301_ADCREG_RESOLUTION_12BIT |
+               TSC2301_ADCREG_AVERAGING_16AVG |
+               TSC2301_ADCREG_CLOCK_1MHZ |
+               TSC2301_ADCREG_VOLTAGE_STAB_100MS;
+
+       /* Averaging and voltage stabilization settings in flags */
+       val3 = TSC2301_ADCREG_CONVERSION_CTRL_BY_TSC2301 |
+               TSC2301_ADCREG_FUNCTION_XYZ |
+               TSC2301_ADCREG_RESOLUTION_12BIT |
+               TSC2301_ADCREG_CLOCK_1MHZ |
+               flags;
+
+       /* Now we prepare the command for transferring */
+       data[0] = reg;
+       data[1] = val1;
+       data[2] = reg;
+       data[3] = val2;
+       data[4] = reg;
+       data[5] = val3;
+
+       spi_message_init(&m);
+       m.spi = tsc->spi;
+
+       memset(xfer, 0, sizeof(xfer));
+       x = &xfer[0];
+
+       x->tx_buf = &data[0];
+       x->len = 4;
+       x->cs_change = 1;
+       spi_message_add_tail(x, &m);
+
+       x++;
+       x->tx_buf = &data[2];
+       x->len = 4;
+       x->cs_change = 1;
+       spi_message_add_tail(x, &m);
+
+       x++;
+       x->tx_buf = &data[4];
+       x->len = 4;
+       spi_message_add_tail(x, &m);
+
+       spi_sync(m.spi, &m);
+
+       return 0;
+}
+
+static void tsc2301_ts_start_scan(struct tsc2301 *tsc)
+{
+       tsc2301_ts_configure(tsc, tsc->ts->hw_flags);
+}
+
+static void tsc2301_ts_stop_scan(struct tsc2301 *tsc)
+{
+       tsc2301_ts_configure(tsc, TSC2301_ADCREG_STOP_CONVERSION);
+}
+
+static int device_suspended(struct device *dev)
+{
+       struct tsc2301 *tsc = dev_get_drvdata(dev);
+       return dev->power.power_state.event != PM_EVENT_ON || tsc->ts->disabled;
+}
+
+static void update_pen_state(struct tsc2301_ts *ts, int x, int y, int pressure)
+{
+       int sync = 0;
+
+       if (pressure) {
+               input_report_abs(ts->idev, ABS_X, x);
+               input_report_abs(ts->idev, ABS_Y, y);
+               input_report_abs(ts->idev, ABS_PRESSURE, pressure);
+               if (!ts->pen_down)
+                       input_report_key(ts->idev, BTN_TOUCH, 1);
+               sync = 1;
+       } else if (ts->pen_down) {
+               input_report_abs(ts->idev, ABS_PRESSURE, 0);
+               input_report_key(ts->idev, BTN_TOUCH, 0);
+               sync = 1;
+       }
+
+       if (sync)
+               input_sync(ts->idev);
+
+       ts->pen_down = pressure ? 1 : 0;
+#ifdef VERBOSE
+       dev_dbg(&tsc->spi->dev, "x %4d y %4d p %4d\n", x, y, pressure);
+#endif
+}
+
+/*
+ * This procedure is called by the SPI framework after the coordinates
+ * have been read from TSC2301
+ */
+static void tsc2301_ts_rx(void *arg)
+{
+       struct tsc2301 *tsc = arg;
+       struct tsc2301_ts *ts = tsc->ts;
+       unsigned int x, y, z1, z2, pressure;
+
+       x  = ts->data[0];
+       y  = ts->data[1];
+       z1 = ts->data[2];
+       z2 = ts->data[3];
+
+       if (z1) {
+               pressure = ts->x_plate_ohm * x;
+               pressure /= 4096;
+               pressure *= z2 - z1;
+               pressure /= z1;
+       } else
+               pressure = 0;
+
+       /* If pressure value is above a preset limit (pen is barely
+        * touching the screen) we can't trust the coordinate values.
+        */
+       if (pressure < ts->pressure_limit && x < MAX_12BIT && y < MAX_12BIT) {
+               ts->pressure_limit = ts->max_pressure;
+               if (ts->ignore_last) {
+                       if (ts->sample_cnt)
+                               update_pen_state(ts, ts->x, ts->y, ts->p);
+                       ts->x = x;
+                       ts->y = y;
+                       ts->p = pressure;
+               } else
+                       update_pen_state(ts, x, y, pressure);
+               ts->sample_cnt++;
+       }
+
+       mod_timer(&ts->timer,
+                 jiffies + msecs_to_jiffies(TSC2301_TS_SCAN_TIME));
+}
+
+static int is_pen_down(struct tsc2301_ts *ts)
+{
+       return ts->pen_down;
+}
+
+/*
+ * Timer is called every TSC2301_TS_SCAN_TIME when the pen is down
+ */
+static void tsc2301_ts_timer(unsigned long arg)
+{
+       struct tsc2301 *tsc = (void *) arg;
+       struct tsc2301_ts *ts = tsc->ts;
+       unsigned long flags;
+       int ndav;
+       int r;
+
+       spin_lock_irqsave(&ts->lock, flags);
+       ndav = omap_get_gpio_datain(ts->dav_gpio);
+       if (ndav || device_suspended(&tsc->spi->dev)) {
+               /* Pen has been lifted */
+               if (!device_suspended(&tsc->spi->dev)) {
+                       ts->irq_enabled = 1;
+                       enable_irq(ts->irq);
+               }
+               update_pen_state(ts, 0, 0, 0);
+               ts->pending = 0;
+               spin_unlock_irqrestore(&ts->lock, flags);
+
+       } else {
+               ts->pen_down = 1;
+               spin_unlock_irqrestore(&ts->lock, flags);
+
+               r = spi_async(tsc->spi, &ts->read_msg);
+               if (r)
+                       dev_err(&tsc->spi->dev, "ts: spi_async() failed");
+       }
+}
+
+/*
+ * This interrupt is called when pen is down and first coordinates are
+ * available. That is indicated by a falling edge on DEV line.  IRQ is
+ * disabled here because while the pen is down the coordinates are
+ * read by a timer.
+ */
+static irqreturn_t tsc2301_ts_irq_handler(int irq, void *dev_id)
+{
+       struct tsc2301 *tsc = dev_id;
+       struct tsc2301_ts *ts = tsc->ts;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ts->lock, flags);
+       if (ts->irq_enabled) {
+               ts->irq_enabled = 0;
+               disable_irq(ts->irq);
+               ts->pending = 1;
+               ts->pressure_limit = ts->touch_pressure;
+               ts->sample_cnt = 0;
+               mod_timer(&ts->timer,
+                         jiffies + msecs_to_jiffies(TSC2301_TS_SCAN_TIME));
+       }
+       spin_unlock_irqrestore(&ts->lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+/* Must be called with ts->lock held */
+static void tsc2301_ts_disable(struct tsc2301 *tsc)
+{
+       struct tsc2301_ts *ts = tsc->ts;
+
+       if (ts->disabled)
+               return;
+
+       ts->disabled = 1;
+       if (!ts->pending) {
+               ts->irq_enabled = 0;
+               disable_irq(ts->irq);
+       } else {
+               while (ts->pending) {
+                       spin_unlock_irq(&ts->lock);
+                       msleep(1);
+                       spin_lock_irq(&ts->lock);
+               }
+       }
+
+       spin_unlock_irq(&ts->lock);
+       tsc2301_ts_stop_scan(tsc);
+       /* Workaround a bug where turning on / off touchscreen scanner
+        * can get the keypad scanner stuck.
+        */
+       tsc2301_kp_restart(tsc);
+       spin_lock_irq(&ts->lock);
+}
+
+static void tsc2301_ts_enable(struct tsc2301 *tsc)
+{
+       struct tsc2301_ts *ts = tsc->ts;
+
+       if (!ts->disabled)
+               return;
+
+       ts->disabled = 0;
+       ts->irq_enabled = 1;
+       enable_irq(ts->irq);
+
+       spin_unlock_irq(&ts->lock);
+       tsc2301_ts_start_scan(tsc);
+       /* Same workaround as above. */
+       tsc2301_kp_restart(tsc);
+       spin_lock_irq(&ts->lock);
+}
+
+#ifdef CONFIG_PM
+int tsc2301_ts_suspend(struct tsc2301 *tsc)
+{
+       struct tsc2301_ts *ts = tsc->ts;
+
+       spin_lock_irq(&ts->lock);
+       tsc2301_ts_disable(tsc);
+       spin_unlock_irq(&ts->lock);
+
+       return 0;
+}
+
+void tsc2301_ts_resume(struct tsc2301 *tsc)
+{
+       struct tsc2301_ts *ts = tsc->ts;
+
+       spin_lock_irq(&ts->lock);
+       tsc2301_ts_enable(tsc);
+       spin_unlock_irq(&ts->lock);
+}
+#endif
+
+static void tsc2301_ts_setup_spi_xfer(struct tsc2301 *tsc)
+{
+       struct tsc2301_ts *ts = tsc->ts;
+       struct spi_message *m = &ts->read_msg;
+       struct spi_transfer *x = &ts->read_xfer[0];
+
+       spi_message_init(m);
+
+       x->tx_buf = &tsc2301_ts_read_data;
+       x->len = 2;
+       spi_message_add_tail(x, m);
+
+       x++;
+       x->rx_buf = &ts->data;
+       x->len = 8;
+       spi_message_add_tail(x, m);
+
+       m->complete = tsc2301_ts_rx;
+       m->context = tsc;
+}
+
+static ssize_t tsc2301_ts_pen_down_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct tsc2301 *tsc = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%u\n", is_pen_down(tsc->ts));
+}
+
+static DEVICE_ATTR(pen_down, S_IRUGO, tsc2301_ts_pen_down_show, NULL);
+
+static ssize_t tsc2301_ts_disable_show(struct device *dev,
+                                      struct device_attribute *attr, char *buf)
+{
+       struct tsc2301          *tsc = dev_get_drvdata(dev);
+       struct tsc2301_ts       *ts = tsc->ts;
+
+       return sprintf(buf, "%u\n", ts->disabled);
+}
+
+static ssize_t tsc2301_ts_disable_store(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       struct tsc2301          *tsc = dev_get_drvdata(dev);
+       struct tsc2301_ts       *ts = tsc->ts;
+       char *endp;
+       int i;
+
+       i = simple_strtoul(buf, &endp, 10);
+       spin_lock_irq(&ts->lock);
+
+       if (i)
+               tsc2301_ts_disable(tsc);
+       else
+               tsc2301_ts_enable(tsc);
+
+       spin_unlock_irq(&ts->lock);
+
+       return count;
+}
+
+static DEVICE_ATTR(disable_ts, 0664, tsc2301_ts_disable_show,
+                  tsc2301_ts_disable_store);
+
+int __devinit tsc2301_ts_init(struct tsc2301 *tsc,
+                             struct tsc2301_platform_data *pdata)
+{
+       struct tsc2301_ts *ts;
+       struct input_dev *idev;
+       int dav_gpio, r;
+
+       if (pdata->dav_gpio < 0) {
+               dev_err(&tsc->spi->dev, "need DAV GPIO");
+               return -EINVAL;
+       }
+       dav_gpio = pdata->dav_gpio;
+
+       ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+       if (ts == NULL)
+               return -ENOMEM;
+       tsc->ts = ts;
+
+       ts->dav_gpio = dav_gpio;
+#ifdef CONFIG_ARCH_OMAP
+       r = omap_request_gpio(dav_gpio);
+       if (r < 0) {
+               dev_err(&tsc->spi->dev, "unable to get DAV GPIO");
+               goto err1;
+       }
+       omap_set_gpio_direction(dav_gpio, 1);
+       ts->irq = OMAP_GPIO_IRQ(dav_gpio);
+#endif
+       init_timer(&ts->timer);
+       ts->timer.data = (unsigned long) tsc;
+       ts->timer.function = tsc2301_ts_timer;
+
+       spin_lock_init(&ts->lock);
+
+       ts->x_plate_ohm = pdata->ts_x_plate_ohm ? : 280;
+       ts->hw_avg_max  = pdata->ts_hw_avg;
+       ts->max_pressure= pdata->ts_max_pressure ? : MAX_12BIT;
+       ts->touch_pressure = pdata->ts_touch_pressure ? : ts->max_pressure;
+       ts->ignore_last = pdata->ts_ignore_last;
+       ts->stab_time   = pdata->ts_stab_time;
+
+       if ((r = tsc2301_ts_check_config(ts, &ts->hw_flags))) {
+               dev_err(&tsc->spi->dev, "invalid configuration\n");
+               goto err2;
+       }
+
+       idev = input_allocate_device();
+       if (idev == NULL) {
+               r = -ENOMEM;
+               goto err2;
+       }
+       idev->name = "TSC2301 touchscreen";
+       snprintf(ts->phys, sizeof(ts->phys),
+                "%s/input-ts", tsc->spi->dev.bus_id);
+       idev->phys = ts->phys;
+
+       idev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
+       idev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+       ts->idev = idev;
+
+       tsc2301_ts_setup_spi_xfer(tsc);
+
+       /* These parameters should perhaps be configurable? */
+       input_set_abs_params(idev, ABS_X, 0, 4096, 0, 0);
+       input_set_abs_params(idev, ABS_Y, 0, 4096, 0, 0);
+       input_set_abs_params(idev, ABS_PRESSURE, 0, 1024, 0, 0);
+
+       tsc2301_ts_start_scan(tsc);
+
+       ts->irq_enabled = 1;
+       r = request_irq(ts->irq, tsc2301_ts_irq_handler,
+                       SA_SAMPLE_RANDOM | SA_TRIGGER_FALLING,
+                       "tsc2301-ts", tsc);
+       if (r < 0) {
+               dev_err(&tsc->spi->dev, "unable to get DAV IRQ");
+               goto err3;
+       }
+       set_irq_wake(ts->irq, 1);
+
+       if (device_create_file(&tsc->spi->dev, &dev_attr_pen_down) < 0)
+               goto err4;
+       if (device_create_file(&tsc->spi->dev, &dev_attr_disable_ts) < 0)
+               goto err5;
+
+       r = input_register_device(idev);
+       if (r < 0) {
+               dev_err(&tsc->spi->dev, "can't register touchscreen device\n");
+               goto err6;
+       }
+
+       return 0;
+err6:
+       device_remove_file(&tsc->spi->dev, &dev_attr_disable_ts);
+err5:
+       device_remove_file(&tsc->spi->dev, &dev_attr_pen_down);
+err4:
+       free_irq(ts->irq, tsc);
+err3:
+       tsc2301_ts_stop_scan(tsc);
+       input_free_device(idev);
+err2:
+#ifdef CONFIG_ARCH_OMAP
+       omap_free_gpio(dav_gpio);
+#endif
+err1:
+       kfree(ts);
+       return r;
+}
+
+void __devexit tsc2301_ts_exit(struct tsc2301 *tsc)
+{
+       struct tsc2301_ts *ts = tsc->ts;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ts->lock, flags);
+       tsc2301_ts_disable(tsc);
+       spin_unlock_irqrestore(&ts->lock, flags);
+
+       device_remove_file(&tsc->spi->dev, &dev_attr_disable_ts);
+       device_remove_file(&tsc->spi->dev, &dev_attr_pen_down);
+
+       free_irq(ts->irq, tsc);
+       input_unregister_device(ts->idev);
+
+#ifdef CONFIG_ARCH_OMAP
+       omap_free_gpio(ts->dav_gpio);
+#endif
+       kfree(ts);
+}
+MODULE_AUTHOR("Jarkko Oikarinen <jarkko.oikarinen@nokia.com>");
+MODULE_LICENSE("GPL");
index 80acd08f0e97bd3b9cf940e5a25ccb2d31fce312..ca1e845d0e12a7225783292a064ef5af39384062 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.
+
 config LEDS_H1940
        tristate "LED Support for iPAQ H1940 device"
        depends LEDS_CLASS && ARCH_H1940
index aa2c18efa5b2f150dffbfbf81a96669bb9d4fb45..dc6985d9468803d3a5cab3328c969382bdfb66d3 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
 obj-$(CONFIG_LEDS_H1940)               += leds-h1940.o
 obj-$(CONFIG_LEDS_COBALT)              += leds-cobalt.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 af66a5d5ecd8b484af9ad661f59071c4714f8d5b..0ec4451c4c64cd57902df879ff0819f0e54c9e72 100644 (file)
@@ -317,6 +317,21 @@ config RADIO_ZOLTRIX_PORT
        help
          Enter the I/O port of your Zoltrix radio card.
 
+config RADIO_TEA5761
+       tristate "Philips Semiconductors TEA5761 I2C FM Radio"
+       select I2C
+       select VIDEO_V4L2
+       help
+         Choose Y here if you have one of these AM/FM radio cards.
+
+         In order to control your radio card, you will need to use programs
+         that are compatible with the Video For Linux 2 API.  Information on
+         this API and pointers to "v4l" programs may be found at
+         <file:Documentation/video4linux/API.html>.
+
+         To compile this driver as a module, choose M here: the
+         module will be called radio-tea5761.
+
 config USB_DSBR
        tristate "D-Link USB FM radio support (EXPERIMENTAL)"
        depends on USB && VIDEO_V4L2 && EXPERIMENTAL
index cf55a18e3ddf94bcd0c20a2d834db3a980f62d67..f3555fad9798681259b8ae4107ce70439be2ea95 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
 obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o
 obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
 obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
+obj-$(CONFIG_RADIO_TEA5761) += radio-tea5761.o
 obj-$(CONFIG_USB_DSBR) += dsbr100.o
 
 EXTRA_CFLAGS += -Isound
diff --git a/drivers/media/radio/radio-tea5761.c b/drivers/media/radio/radio-tea5761.c
new file mode 100644 (file)
index 0000000..74fe99e
--- /dev/null
@@ -0,0 +1,636 @@
+/*
+ * drivers/media/radio/radio-tea5761.c
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ *
+ * 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/version.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <media/v4l2-common.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/board.h>
+
+#define DRIVER_NAME "tea5761"
+
+#define TEA5761_VERSION                KERNEL_VERSION(0, 0, 1)
+
+#define TEA5761_I2C_ADDR       0x10
+
+#define TEA5761_MANID          0x002b
+#define TEA5761_CHIPID         0x5761
+
+#define TEA5761_INTREG_BLMSK   0x0001
+#define TEA5761_INTREG_FRRMSK  0x0002
+#define TEA5761_INTREG_LEVMSK  0x0008
+#define TEA5761_INTREG_IFMSK   0x0010
+#define TEA5761_INTREG_BLMFLAG 0x0100
+#define TEA5761_INTREG_FRRFLAG 0x0200
+#define TEA5761_INTREG_LEVFLAG 0x0800
+#define TEA5761_INTREG_IFFLAG  0x1000
+
+#define TEA5761_FRQSET_SUD     0x8000
+#define TEA5761_FRQSET_SM      0x4000
+
+#define TEA5761_TNCTRL_PUPD0   0x4000
+#define TEA5761_TNCTRL_BLIM    0x2000
+#define TEA5761_TNCTRL_SWPM    0x1000
+#define TEA5761_TNCTRL_IFCTC   0x0800
+#define TEA5761_TNCTRL_AFM     0x0400
+#define TEA5761_TNCTRL_SMUTE   0x0200
+#define TEA5761_TNCTRL_SNC     0x0100
+#define TEA5761_TNCTRL_MU      0x0080
+#define TEA5761_TNCTRL_SSL1    0x0040
+#define TEA5761_TNCTRL_SSL0    0x0020
+#define TEA5761_TNCTRL_HLSI    0x0010
+#define TEA5761_TNCTRL_MST     0x0008
+#define TEA5761_TNCTRL_SWP     0x0004
+#define TEA5761_TNCTRL_DTC     0x0002
+#define TEA5761_TNCTRL_AHLSI   0x0001
+
+#define TEA5761_TUNCHK_LEVEL(x)        (((x) & 0x00F0) >> 4)
+#define TEA5761_TUNCHK_IFCNT(x) (((x) & 0xFE00) >> 9)
+#define TEA5761_TUNCHK_TUNTO   0x0100
+#define TEA5761_TUNCHK_LD      0x0008
+#define TEA5761_TUNCHK_STEREO  0x0004
+
+#define TEA5761_TESTREG_TRIGFR 0x0800
+
+#define TEA5761_FREQ_LOW       87500
+#define TEA5761_FREQ_HIGH      108000
+
+/* Probe for TEA5761 twice since the version N4B seems to be
+ * broken and needs two probes to be found */
+static unsigned short normal_i2c[] = {
+       TEA5761_I2C_ADDR, TEA5761_I2C_ADDR, I2C_CLIENT_END
+};
+
+I2C_CLIENT_INSMOD;
+
+struct tea5761_regs {
+       u16 intreg;
+       u16 frqset;
+       u16 tnctrl;
+       u16 frqchk;
+       u16 tunchk;
+       u16 testreg;
+       u16 manid;
+       u16 chipid;
+} __attribute__ ((packed));
+
+struct tea5761_write_regs {
+       u8 intreg;
+       u16 frqset;
+       u16 tnctrl;
+       u16 testreg;
+} __attribute__ ((packed));
+
+struct tea5761_device {
+       struct video_device     *video_dev;
+       struct i2c_client       *i2c_dev;
+       struct tea5761_regs     regs;
+       struct mutex            mutex;
+       int                     users;
+};
+
+static struct tea5761_device tea5761;
+
+static struct i2c_driver       tea5761_driver;
+static int radio_nr = -1;
+
+static int tea5761_read_regs(struct tea5761_device *tea)
+{
+       int rc, i;
+       u16 *p = (u16 *) &tea->regs;
+       struct i2c_client *client = tea->i2c_dev;
+
+       rc = i2c_master_recv(client, (void*) &tea->regs, sizeof(tea->regs));
+       for (i = 0; i < 8; i++) {
+               p[i] = __be16_to_cpu(p[i]);
+       }
+
+       dev_dbg(&client->dev,
+               "chip state: %04x %04x %04x %04x %04x %04x %04x %04x\n",
+               p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
+
+       if (rc < 0)
+               dev_err(&client->dev, "read\n");
+
+       return rc;
+}
+
+static void tea5761_write_regs(struct tea5761_device *tea)
+{
+       struct tea5761_write_regs wr;
+       struct tea5761_regs *r = &tea->regs;
+       struct i2c_client *client = tea->i2c_dev;
+#ifdef DEBUG
+       u8 *p = (u8 *) r;
+#endif
+
+       wr.intreg = r->intreg & 0xff;
+       wr.frqset = __cpu_to_be16(r->frqset);
+       wr.tnctrl = __cpu_to_be16(r->tnctrl);
+       wr.testreg = __cpu_to_be16(r->testreg);
+
+       dev_dbg(&client->dev,
+               "writing state: %02x %02x %02x %02x %02x %02x %02x\n",
+               p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
+       if (i2c_master_send(client, (void *) &wr, sizeof(wr)) < 0)
+               dev_err(&client->dev, "write\n");
+}
+
+static void tea5761_power_up(struct tea5761_device *tea)
+{
+       struct tea5761_regs *r = &tea->regs;
+
+       if (!(r->tnctrl & TEA5761_TNCTRL_PUPD0)) {
+               r->tnctrl &= ~(TEA5761_TNCTRL_AFM | TEA5761_TNCTRL_MU |
+                              TEA5761_TNCTRL_HLSI);
+               r->testreg |= TEA5761_TESTREG_TRIGFR;
+               r->tnctrl |= TEA5761_TNCTRL_PUPD0;
+               return tea5761_write_regs(tea);
+       }
+}
+
+static void tea5761_power_down(struct tea5761_device *tea)
+{
+       struct tea5761_regs *r = &tea->regs;
+
+       if (r->tnctrl & TEA5761_TNCTRL_PUPD0) {
+               r->tnctrl &= ~TEA5761_TNCTRL_PUPD0;
+               return tea5761_write_regs(tea);
+       }
+}
+
+static void tea5761_set_freq(struct tea5761_device *tea, int freq)
+{
+       struct tea5761_regs *r = &tea->regs;
+
+       if (r->tnctrl & TEA5761_TNCTRL_HLSI)
+               r->frqset = (freq + 225000) / 8192;
+       else
+               r->frqset = (freq - 225000) / 8192;
+}
+
+static int tea5761_get_freq(struct tea5761_device *tea)
+{
+       struct tea5761_regs *r = &tea->regs;
+
+       if (r->tnctrl & TEA5761_TNCTRL_HLSI)
+               return (r->frqchk * 8192) - 225000;
+       else
+               return (r->frqchk * 8192) + 225000;
+}
+
+static void tea5761_tune(struct tea5761_device *tea, int freq)
+{
+       tea5761_set_freq(tea, freq);
+       tea5761_write_regs(tea);
+}
+
+static void tea5761_set_audout_mode(struct tea5761_device *tea, int audmode)
+{
+       struct tea5761_regs *r = &tea->regs;
+       int tnctrl = r->tnctrl;
+
+       if (audmode == V4L2_TUNER_MODE_MONO)
+               r->tnctrl |= TEA5761_TNCTRL_MST;
+       else
+               r->tnctrl &= ~TEA5761_TNCTRL_MST;
+       if (tnctrl != r->tnctrl)
+               tea5761_write_regs(tea);
+}
+
+static int tea5761_get_audout_mode(struct tea5761_device *tea)
+{
+       struct tea5761_regs *r = &tea->regs;
+
+       if (r->tnctrl & TEA5761_TNCTRL_MST)
+               return V4L2_TUNER_MODE_MONO;
+       else
+               return V4L2_TUNER_MODE_STEREO;
+}
+
+static void tea5761_mute(struct tea5761_device *tea, int on)
+{
+       struct tea5761_regs *r = &tea->regs;
+       int tnctrl = r->tnctrl;
+
+       if (on)
+               r->tnctrl |= TEA5761_TNCTRL_MU;
+       else
+               r->tnctrl &= ~TEA5761_TNCTRL_MU;
+       if (tnctrl != r->tnctrl)
+               tea5761_write_regs(tea);
+}
+
+static int tea5761_is_muted(struct tea5761_device *tea)
+{
+       return tea->regs.tnctrl & TEA5761_TNCTRL_MU;
+}
+
+static int tea5761_do_ioctl(struct inode *inode, struct file *file,
+                           unsigned int cmd, void *arg)
+{
+       struct tea5761_device *tea = file->private_data;
+       struct video_device *dev = tea->video_dev;
+       struct i2c_client *client = tea->i2c_dev;
+       struct tea5761_regs *r = &tea->regs;
+
+       union {
+               struct v4l2_capability c;
+               struct v4l2_tuner t;
+               struct v4l2_frequency f;
+               struct v4l2_queryctrl qc;
+               struct v4l2_control ct;
+       } *u = arg;
+
+       tea5761_read_regs(tea);
+
+       switch (cmd) {
+       case VIDIOC_QUERYCAP:
+               dev_dbg(&client->dev, "VIDIOC_QUERYCAP\n");
+               memset(&u->c, 0, sizeof(u->c));
+               strlcpy(u->c.driver, dev->dev->driver->name,
+                       sizeof(u->c.driver));
+               strlcpy(u->c.card, dev->name, sizeof(u->c.card));
+               snprintf(u->c.bus_info, sizeof(u->c.bus_info), "I2C:%s",
+                        dev->dev->bus_id);
+               u->c.version = TEA5761_VERSION;
+               u->c.capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+               break;
+
+       case VIDIOC_G_TUNER:
+               /* Only one tuner chip */
+               dev_dbg(&client->dev, "VIDIOC_G_TUNER\n");
+               if (u->t.index != 0)
+                       return -EINVAL;
+
+               memset(&u->t, 0, sizeof(u->t));
+               u->t.type = V4L2_TUNER_RADIO;
+               strlcpy(u->t.name, "FM", sizeof(u->t.name));
+               /* Freq in 62.5Hz units */
+               u->t.rangelow = TEA5761_FREQ_LOW * 16;
+               u->t.rangehigh = TEA5761_FREQ_HIGH * 16;
+               u->t.capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+               if (r->tunchk & TEA5761_TUNCHK_STEREO)
+                       u->t.rxsubchans = V4L2_TUNER_SUB_STEREO;
+               u->t.audmode = tea5761_get_audout_mode(tea);
+               u->t.signal = TEA5761_TUNCHK_LEVEL(r->tunchk) * 0xffff / 0xf;
+               u->t.afc = TEA5761_TUNCHK_IFCNT(r->tunchk);
+               break;
+
+       case VIDIOC_S_TUNER:
+               /* Only tuner nro 0 can be selected. */
+               dev_dbg(&client->dev, "VIDIOC_S_TUNER\n");
+               if (u->t.index != 0)
+                       return -EINVAL;
+               tea5761_set_audout_mode(tea, u->t.audmode);
+               break;
+
+       case VIDIOC_G_FREQUENCY:
+               dev_dbg(&client->dev, "VIDIOC_G_FREQUENCY\n");
+               memset(&u->f, 0, sizeof(u->f));
+               u->f.type = V4L2_TUNER_RADIO;
+               if (r->tnctrl & TEA5761_TNCTRL_PUPD0)
+                       u->f.frequency = (tea5761_get_freq(tea) * 2) / 125;
+               else
+                       u->f.frequency = 0;
+               break;
+
+       case VIDIOC_S_FREQUENCY:
+               dev_dbg(&client->dev, "VIDIOC_S_FREQUENCY %u\n",
+                       u->f.frequency);
+               if (u->f.tuner != 0)
+                       return -EINVAL;
+               if (u->f.frequency == 0) {
+                       /* We special case this as a power down
+                        * control. */
+                       tea5761_power_down(tea);
+                       break;
+               }
+               if (u->f.frequency < 16 * TEA5761_FREQ_LOW)
+                       return -EINVAL;
+               if (u->f.frequency > 16 * TEA5761_FREQ_HIGH)
+                       return -EINVAL;
+
+               tea5761_power_up(tea);
+               tea5761_tune(tea, (u->f.frequency * 125) / 2);
+               break;
+
+       case VIDIOC_QUERYCTRL:
+               dev_dbg(&client->dev, "VIDIOC_QUERYCTRL %d\n", u->qc.id);
+               if (u->qc.id != V4L2_CID_AUDIO_MUTE)
+                       return -EINVAL;
+               strlcpy(u->qc.name, "Mute", sizeof(u->qc.name));
+               u->qc.minimum = 0;
+               u->qc.maximum = 1;
+               u->qc.step = 1;
+               u->qc.default_value = 0;
+               u->qc.type = V4L2_CTRL_TYPE_BOOLEAN;
+               break;
+
+       case VIDIOC_G_CTRL:
+               dev_dbg(&client->dev, "VIDIOC_G_CTRL %d\n", u->ct.id);
+               if (u->ct.id != V4L2_CID_AUDIO_MUTE)
+                       return -EINVAL;
+               if (r->tnctrl & TEA5761_TNCTRL_PUPD0)
+                       u->ct.value = tea5761_is_muted(tea) ? 1 : 0;
+               else
+                       u->ct.value = 0;
+               break;
+
+       case VIDIOC_S_CTRL:
+               dev_dbg(&client->dev, "VIDIOC_S_CTRL %d\n", u->ct.id);
+               if (u->ct.id != V4L2_CID_AUDIO_MUTE)
+                       return -EINVAL;
+               tea5761_mute(tea, u->ct.value);
+               break;
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+
+       return 0;
+}
+
+static int tea5761_ioctl(struct inode *inode, struct file *file,
+                        unsigned int cmd, unsigned long arg)
+{
+       return video_usercopy(inode, file, cmd, arg, tea5761_do_ioctl);
+}
+
+static int tea5761_open(struct inode *inode, struct file *file)
+{
+       int minor = iminor(file->f_dentry->d_inode);
+       /* Currently we support only one device */
+       struct tea5761_device *tea = &tea5761;
+
+       if (tea->video_dev->minor != minor)
+               return -ENODEV;
+
+       mutex_lock(&tea->mutex);
+       /* Only exclusive access */
+       if (tea->users) {
+               mutex_unlock(&tea->mutex);
+               return -EBUSY;
+       }
+       tea->users++;
+       mutex_unlock(&tea->mutex);
+
+       file->private_data = tea;
+       return 0;
+}
+
+static int tea5761_release(struct inode *inode, struct file *file)
+{
+       struct tea5761_device *tea = file->private_data;
+
+       mutex_lock(&tea->mutex);
+       tea->users--;
+       mutex_unlock(&tea->mutex);
+
+       return 0;
+}
+
+static struct file_operations tea5761_fops = {
+       .owner          = THIS_MODULE,
+       .open           = tea5761_open,
+       .release        = tea5761_release,
+       .ioctl          = tea5761_ioctl,
+       .llseek         = no_llseek,
+};
+
+static struct video_device tea5761_video_device = {
+       .owner         = THIS_MODULE,
+       .name          = "TEA5761 FM-Radio",
+       .type          = VID_TYPE_TUNER,
+       .hardware      = 40 /* VID_HARDWARE_TEA5761UK */,
+       .fops          = &tea5761_fops,
+       .release       = video_device_release
+};
+
+static int tea5761_probe(struct i2c_adapter *adapter, int address,
+                         int kind)
+{
+       struct i2c_client *client;
+       struct video_device *video_dev;
+       int err = 0;
+       static const char *client_name = "TEA5761 FM-Radio";
+       struct tea5761_device *tea = &tea5761;
+       struct tea5761_regs   *r = &tea->regs;
+
+       mutex_init(&tea->mutex);
+        /* I2C detection and initialization */
+       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+       if (client == NULL) {
+               dev_err(&adapter->dev, DRIVER_NAME
+                       ": couldn't allocate memory\n");
+               return -ENOMEM;
+       }
+       tea->i2c_dev = client;
+
+       client->addr = address;
+       client->adapter = adapter;
+       client->driver = &tea5761_driver;
+       client->dev.driver = &tea5761_driver.driver;
+       client->flags = 0;
+       strlcpy(client->name, client_name, I2C_NAME_SIZE);
+
+       if (kind < 0) {
+               if (tea5761_read_regs(tea) < 0) {
+                       dev_info(&client->dev,
+                                "chip read failed for %d-%04x\n",
+                                adapter->nr, address);
+                       goto err_tea_dev;
+               }
+               if (r->chipid != TEA5761_CHIPID) {
+                       dev_info(&client->dev,
+                                "bad chipid (0x%04x) at %d-%04x\n",
+                                r->chipid, adapter->nr, address);
+                       goto err_tea_dev;
+               }
+               if ((r->manid & 0x0fff) != TEA5761_MANID) {
+                       dev_info(&client->dev,
+                                "bad manid (0x%04x) at %d-%04x\n",
+                                r->manid, adapter->nr, address);
+                       goto err_tea_dev;
+               }
+       }
+
+       err = i2c_attach_client(client);
+       if (err) {
+               dev_err(&client->dev, "couldn't attach to address %d-%04x\n",
+                       adapter->nr, address);
+               goto err_tea_dev;
+       }
+
+       /* V4L initialization */
+       video_dev = video_device_alloc();
+       if (video_dev == NULL) {
+               dev_err(&client->dev, "couldn't allocate memory\n");
+               err = -ENOMEM;
+               goto err_i2c_attach;
+       }
+       tea->video_dev = video_dev;
+
+       *video_dev = tea5761_video_device;
+       video_dev->dev = &client->dev;
+       i2c_set_clientdata(client, video_dev);
+
+       /* initialize and power off the chip */
+       tea5761_read_regs(tea);
+       tea5761_set_audout_mode(tea, V4L2_TUNER_MODE_STEREO);
+       tea5761_mute(tea, 0);
+       tea5761_power_down(tea);
+
+       tea5761.video_dev = video_dev;
+       tea5761.i2c_dev = client;
+
+       err = video_register_device(video_dev, VFL_TYPE_RADIO, radio_nr);
+       if (err) {
+               dev_err(&client->dev, "couldn't register video device\n");
+               goto err_video_alloc;
+       }
+
+       dev_info(&client->dev, "tea5761 (version %d) detected at %d-%04x\n",
+               (tea->regs.manid >> 12) & 0xf, adapter->nr, address);
+
+       return 0;
+
+err_video_alloc:
+       video_device_release(video_dev);
+err_i2c_attach:
+       i2c_detach_client(client);
+err_tea_dev:
+       kfree(client);
+       return err;
+}
+
+static int tea5761_attach_adapter(struct i2c_adapter *adapter)
+{
+       if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+               return -EINVAL;
+
+       return i2c_probe(adapter, &addr_data, tea5761_probe);
+}
+
+static int tea5761_detach_client(struct i2c_client *client)
+{
+       struct video_device *vd = i2c_get_clientdata(client);
+
+       i2c_detach_client(client);
+       video_unregister_device(vd);
+       kfree(client);
+
+       return 0;
+}
+
+static struct i2c_driver tea5761_driver = {
+       .id             = I2C_DRIVERID_TUNER,
+       .driver = {
+               .name   = DRIVER_NAME,
+       },
+       .attach_adapter = tea5761_attach_adapter,
+       .detach_client  = tea5761_detach_client,
+};
+
+#if CONFIG_ARCH_OMAP
+/* No way to pass platform device data. Enable here all the TEA5761
+ * devices, since I2C address scanning will need them to respond.
+ */
+static int enable_gpio;
+
+static int __init tea5761_dev_init(void)
+{
+       const struct omap_tea5761_config *info;
+
+       info = omap_get_config(OMAP_TAG_TEA5761, struct omap_tea5761_config);
+       if (info) {
+               enable_gpio = info->enable_gpio;
+       }
+
+       if (enable_gpio) {
+               pr_debug(DRIVER_NAME ": enabling tea5761 at GPIO %d\n",
+                        enable_gpio);
+
+               if (omap_request_gpio(enable_gpio) < 0) {
+                       printk(KERN_ERR DRIVER_NAME ": can't request GPIO %d\n",
+                              enable_gpio);
+                       return -ENODEV;
+               }
+
+               omap_set_gpio_direction(enable_gpio, 0);
+               udelay(50);
+               omap_set_gpio_dataout(enable_gpio, 1);
+       }
+
+       return 0;
+}
+
+static void __exit tea5761_dev_exit(void)
+{
+       if (enable_gpio) {
+               omap_set_gpio_dataout(enable_gpio, 0);
+               omap_free_gpio(enable_gpio);
+       }
+}
+#else
+static int __init tea5761_dev_init(void)
+{
+}
+
+static void __exit tea5761_dev_exit(void)
+{
+}
+#endif
+
+static int __init tea5761_init(void)
+{
+       int res;
+
+       if ((res = tea5761_dev_init()) < 0)
+               return res;
+
+       if ((res = i2c_add_driver(&tea5761_driver))) {
+               printk(KERN_ERR DRIVER_NAME ": driver registration failed\n");
+               return res;
+       }
+
+       return 0;
+}
+
+static void __exit tea5761_exit(void)
+{
+       int res;
+
+       if ((res = i2c_del_driver(&tea5761_driver)))
+               printk(KERN_ERR DRIVER_NAME ": i2c driver removal failed\n");
+       tea5761_dev_exit();
+}
+
+MODULE_AUTHOR("Timo Teräs");
+MODULE_DESCRIPTION("I2C interface for TEA5761.");
+MODULE_LICENSE("GPL");
+
+module_param(radio_nr, int, 0);
+MODULE_PARM_DESC(nr_radio, "video4linux device number to use");
+
+module_init(tea5761_init)
+module_exit(tea5761_exit)
index bc773781993a5b75113388a623f12f64fa697556..653842ccd47cb05b355fbf87f1648dfd68c40d45 100644 (file)
@@ -777,4 +777,6 @@ config USB_ZR364XX
 
 endmenu # V4L USB devices
 
+source drivers/media/video/omap/Kconfig
+
 endmenu
index 9c2de501612f4c1c199702d0f96c80f077f06416..60d2da0265f928818937fe81300fd168bfdd271b 100644 (file)
@@ -86,6 +86,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 1914e65d4db120202389bfbb5761784e4782ab1c..383bd54b34b524a77c8c9355affae3f5faa72c9d 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/timer.h>
+#include <linux/mmc/mmc.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
 #include <linux/clk.h>
@@ -36,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
@@ -586,9 +588,8 @@ static void mmc_omap_switch_timer(unsigned long arg)
 static void mmc_omap_switch_handler(struct work_struct *work)
 {
        struct mmc_omap_host *host = container_of(work, struct mmc_omap_host, switch_work);
-       struct mmc_card *card;
        static int complained = 0;
-       int cards = 0, cover_open;
+       int cover_open;
 
        if (host->switch_pin == -1)
                return;
@@ -598,10 +599,6 @@ static void mmc_omap_switch_handler(struct work_struct *work)
                host->switch_last_state = cover_open;
        }
        mmc_detect_change(host->mmc, 0);
-       list_for_each_entry(card, &host->mmc->cards, node) {
-               if (mmc_card_present(card))
-                       cards++;
-       }
        if (mmc_omap_cover_is_open(host)) {
                if (!complained) {
                        dev_info(mmc_dev(host->mmc), "cover is open\n");
@@ -906,7 +903,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 f1d60b6f048e6f08aa855e19fed1337a292cfe79..295a56876cb1b8c82912dd546fc9bdba22c13796 100644 (file)
@@ -69,6 +69,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 && BROKEN
index edba1db14bfad6581260b822b60a260063fc542c..f9a1f6b084188d660ed7bd200525462632eca9d9 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
 obj-$(CONFIG_MTD_NAND_CM_X270)         += cmx270_nand.o
 obj-$(CONFIG_MTD_NAND_BASLER_EXCITE)   += excite_nandflash.o
diff --git a/drivers/mtd/nand/omap-hw.c b/drivers/mtd/nand/omap-hw.c
new file mode 100644 (file)
index 0000000..330a9dc
--- /dev/null
@@ -0,0 +1,868 @@
+/*
+ *  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;
+               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..1fc8c31
--- /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_reset_mac_header(skb);
+               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 */
+       skb_copy_from_linear_data(skb, omap_ir->tx_buf_dma_virt, 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 278a22cea5bf78c42b1bc76afd62688f0a3a73a9..b67612b4b3833951381cad1f8dd827a8d5638a6b 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 8065f2b537019209be2bbdbe31f4569861905cf7..47b3584f772840328e189b814484c7dda3b60f42 100644 (file)
@@ -176,10 +176,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 b394e63894d2e21c50ba15265fd7433838c1c91d..15772541c0ecefe9ed51825ae6aaf3a787c8b674 100644 (file)
@@ -2662,7 +2662,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 5cfa3d1c4413ff3d920cde36b2efceac7a585887..f71e06cb2b8f0f955117c6e648fe4f4e7d97d72c 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..8aecd7a
--- /dev/null
@@ -0,0 +1,191 @@
+/******************************************************************
+ * 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
+
+#ifdef CONFIG_USB_TUSB_OMAP_DMA
+#define tusb_dma_omap()                        1
+#else
+#define tusb_dma_omap()                        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..aad53fd
--- /dev/null
@@ -0,0 +1,973 @@
+/******************************************************************
+ * 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 *musb,
+       const struct usb_ctrlrequest *pControlRequest)
+{
+       void __iomem    *pBase = musb->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] = musb->is_self_powered << USB_DEVICE_SELF_POWERED;
+               bResult[0] |= musb->may_wakeup << USB_DEVICE_REMOTE_WAKEUP;
+#ifdef CONFIG_USB_MUSB_OTG
+               if (musb->g.is_otg) {
+                       bResult[0] |= musb->g.b_hnp_enable
+                               << USB_DEVICE_B_HNP_ENABLE;
+                       bResult[0] |= musb->g.a_alt_hnp_support
+                               << USB_DEVICE_A_ALT_HNP_SUPPORT;
+                       bResult[0] |= musb->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 = &musb->aLocalEnd[bEnd].ep_in;
+               } else {
+                       ep = &musb->aLocalEnd[bEnd].ep_out;
+               }
+               regs = musb->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(&musb->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 *musb,
+               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(musb,
+                                       pControlRequest);
+                       break;
+
+               /* case USB_REQ_SYNC_FRAME: */
+
+               default:
+                       break;
+               }
+       }
+       return handled;
+}
+
+/*
+ * Context:  caller holds controller lock
+ */
+static void musb_g_ep0_giveback(struct musb *musb, struct usb_request *req)
+{
+       musb->ep0_state = MGC_END0_STAGE_SETUP;
+       musb_g_giveback(&musb->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 *musb,
+               struct usb_ctrlrequest *pControlRequest)
+__releases(musb->Lock)
+__acquires(musb->Lock)
+{
+       int handled = -EINVAL;
+       void __iomem *pBase = musb->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 */
+                       musb->bSetAddress = TRUE;
+                       musb->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;
+                               musb->may_wakeup = 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 = &musb->aLocalEnd[bEnd].ep_in;
+                               else
+                                       pEnd = &musb->aLocalEnd[bEnd].ep_out;
+                               if (!pEnd->desc)
+                                       break;
+
+                               /* REVISIT do it directly, no locking games */
+                               spin_unlock(&musb->Lock);
+                               musb_gadget_set_halt(&pEnd->end_point, 0);
+                               spin_lock(&musb->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:
+                                       musb->may_wakeup = 1;
+                                       break;
+                               case USB_DEVICE_TEST_MODE:
+                                       if (musb->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 */
+                                               musb->bTestModeValue =
+                                                       MGC_M_TEST_J;
+                                               break;
+                                       case 2:
+                                               /* TEST_K */
+                                               pr_debug("TEST_K\n");
+                                               musb->bTestModeValue =
+                                                       MGC_M_TEST_K;
+                                               break;
+                                       case 3:
+                                               /* TEST_SE0_NAK */
+                                               pr_debug("TEST_SE0_NAK\n");
+                                               musb->bTestModeValue =
+                                                       MGC_M_TEST_SE0_NAK;
+                                               break;
+                                       case 4:
+                                               /* TEST_PACKET */
+                                               pr_debug("TEST_PACKET\n");
+                                               musb->bTestModeValue =
+                                                       MGC_M_TEST_PACKET;
+                                               break;
+                                       default:
+                                               goto stall;
+                                       }
+
+                                       /* enter test mode after irq */
+                                       if (handled > 0)
+                                               musb->bTestMode = TRUE;
+                                       break;
+#ifdef CONFIG_USB_MUSB_OTG
+                               case USB_DEVICE_B_HNP_ENABLE:
+                                       if (!musb->g.is_otg)
+                                               goto stall;
+                                       { u8 devctl;
+                                       musb->g.b_hnp_enable = 1;
+                                       devctl = musb_readb(pBase,
+                                                       MGC_O_HDRC_DEVCTL);
+                                       /* NOTE:  at least DaVinci doesn't
+                                        * like to set HR ...
+                                        */
+                                       DBG(1, "set HR\n");
+                                       musb_writeb(pBase, MGC_O_HDRC_DEVCTL,
+                                               devctl | MGC_M_DEVCTL_HR);
+                                       }
+                                       break;
+                               case USB_DEVICE_A_HNP_SUPPORT:
+                                       if (!musb->g.is_otg)
+                                               goto stall;
+                                       musb->g.a_hnp_support = 1;
+                                       break;
+                               case USB_DEVICE_A_ALT_HNP_SUPPORT:
+                                       if (!musb->g.is_otg)
+                                               goto stall;
+                                       musb->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 = musb->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 *musb)
+{
+       void __iomem            *regs = musb->control_ep->regs;
+       struct usb_request      *pRequest = next_ep0_request(musb);
+       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(&musb->aLocalEnd[0], wFifoCount, pFifoSource);
+       pRequest->actual += wFifoCount;
+
+       /* update the flags */
+       if (wFifoCount < MUSB_MAX_END0_PACKET
+                       || pRequest->actual == pRequest->length) {
+               musb->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(musb, 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 *musb, struct usb_ctrlrequest *req)
+{
+       struct usb_request      *r;
+       void __iomem            *regs = musb->control_ep->regs;
+
+       musb_read_fifo(&musb->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(musb);
+       if (r)
+               musb_g_ep0_giveback(musb, 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...
+        */
+       musb->bSetAddress = FALSE;
+       musb->ackpend = MGC_M_CSR0_P_SVDRXPKTRDY;
+       if (req->wLength == 0) {
+               if (req->bRequestType & USB_DIR_IN)
+                       musb->ackpend |= MGC_M_CSR0_TXPKTRDY;
+               musb->ep0_state = MGC_END0_STAGE_ACKWAIT;
+       } else if (req->bRequestType & USB_DIR_IN) {
+               musb->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();
+               musb->ackpend = 0;
+       } else
+               musb->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
+ *
+ * Context: irq handler; we won't re-enter the driver that way.
+ */
+irqreturn_t musb_g_ep0_irq(struct musb *musb)
+{
+       u16             wCsrVal;
+       u16             wCount;
+       void __iomem    *pBase = musb->pRegs;
+       void __iomem    *regs = musb->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(musb->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;
+               musb->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;
+               musb->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 (musb->ep0_state) {
+
+       case MGC_END0_STAGE_TX:
+               /* irq on clearing txpktrdy */
+               if ((wCsrVal & MGC_M_CSR0_TXPKTRDY) == 0) {
+                       ep0_txstate(musb);
+                       retval = IRQ_HANDLED;
+               }
+               break;
+
+       case MGC_END0_STAGE_RX:
+               /* irq on set rxpktrdy */
+               if (wCsrVal & MGC_M_CSR0_RXPKTRDY) {
+                       ep0_rxstate(musb);
+                       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 (musb->bSetAddress) {
+                       musb->bSetAddress = FALSE;
+                       musb_writeb(pBase, MGC_O_HDRC_FADDR, musb->bAddress);
+               }
+
+               /* enter test mode if needed (exit by reset) */
+               else if (musb->bTestMode) {
+                       DBG(1, "entering TESTMODE\n");
+
+                       if (MGC_M_TEST_PACKET == musb->bTestModeValue)
+                               musb_load_testpacket(musb);
+
+                       musb_writeb(pBase, MGC_O_HDRC_TESTMODE,
+                                       musb->bTestModeValue);
+               }
+               /* FALLTHROUGH */
+
+       case MGC_END0_STAGE_STATUSOUT:
+               /* end of sequence #1: write to host (TX state) */
+               {
+                       struct usb_request      *req;
+
+                       req = next_ep0_request(musb);
+                       if (req)
+                               musb_g_ep0_giveback(musb, req);
+               }
+               retval = IRQ_HANDLED;
+               musb->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(musb, &setup);
+                       retval = IRQ_HANDLED;
+
+                       /* sometimes the RESET won't be reported */
+                       if (unlikely(musb->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);
+                               musb->g.speed = (power & MGC_M_POWER_HSMODE)
+                                       ? USB_SPEED_HIGH : USB_SPEED_FULL;
+
+                       }
+
+                       switch (musb->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(
+                                               musb, &setup);
+
+                               /* status stage might be immediate */
+                               if (handled > 0) {
+                                       musb->ackpend |= MGC_M_CSR0_P_DATAEND;
+                                       musb->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(musb, &setup);
+                               if (handled > 0) {
+                                       musb->ackpend = MGC_M_CSR0_TXPKTRDY
+                                               | MGC_M_CSR0_P_DATAEND;
+                                       musb->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(musb->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(musb, &setup);
+                       if (handled < 0) {
+                               MGC_SelectEnd(pBase, 0);
+stall:
+                               DBG(3, "stall (%d)\n", handled);
+                               musb->ackpend |= MGC_M_CSR0_P_SENDSTALL;
+                               musb->ep0_state = MGC_END0_STAGE_SETUP;
+finish:
+                               musb_writew(regs, MGC_O_HDRC_CSR0,
+                                               musb->ackpend);
+                               musb->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);
+               musb->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..0626aa5
--- /dev/null
@@ -0,0 +1,2040 @@
+/******************************************************************
+ * 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 *musb, struct musb_ep *ep)
+{
+       if (can_bulk_split(musb, 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 *musb, struct musb_request *req)
+{
+       u8                      bEnd = req->bEnd;
+       struct musb_ep          *pEnd;
+       void __iomem            *epio = musb->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(musb, 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 = musb->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 *musb, u8 bEnd)
+{
+       u16                     wCsrVal;
+       struct usb_request      *pRequest;
+       u8 __iomem              *pBase = musb->pRegs;
+       struct musb_ep          *pEnd = &musb->aLocalEnd[bEnd].ep_in;
+       void __iomem            *epio = musb->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;
+                               musb->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(musb, 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 *musb, struct musb_request *req)
+{
+       u16                     wCsrVal = 0;
+       const u8                bEnd = req->bEnd;
+       struct usb_request      *pRequest = &req->request;
+       struct musb_ep          *pEnd = &musb->aLocalEnd[bEnd].ep_out;
+       void __iomem            *epio = musb->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 = musb->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 = musb->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 = musb->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
+ */
+void musb_g_rx(struct musb *musb, u8 bEnd)
+{
+       u16                     wCsrVal;
+       struct usb_request      *pRequest;
+       void __iomem            *pBase = musb->pRegs;
+       struct musb_ep          *pEnd = &musb->aLocalEnd[bEnd].ep_out;
+       void __iomem            *epio = musb->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) musb->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(musb, 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             *musb;
+       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;
+       musb = pEnd->pThis;
+       pBase = musb->pRegs;
+       bEnd = pEnd->bEndNumber;
+
+       spin_lock_irqsave(&musb->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() && musb->pDmaController) {
+               struct dma_controller   *c = musb->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(&musb->irq_work);
+
+fail:
+       spin_unlock_irqrestore(&musb->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     *musb;
+       u8              bEnd;
+       struct musb_ep  *pEnd;
+       void __iomem    *epio;
+       int             status = 0;
+
+       pEnd = to_musb_ep(ep);
+       musb = pEnd->pThis;
+       bEnd = pEnd->bEndNumber;
+       epio = musb->aLocalEnd[bEnd].regs;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+       MGC_SelectEnd(musb->pRegs, bEnd);
+
+       /* zero the endpoint sizes */
+       if (pEnd->is_in) {
+               u16 wIntrTxE = musb_readw(musb->pRegs, MGC_O_HDRC_INTRTXE);
+               wIntrTxE &= ~(1 << bEnd);
+               musb_writew(musb->pRegs, MGC_O_HDRC_INTRTXE, wIntrTxE);
+               musb_writew(epio, MGC_O_HDRC_TXMAXP, 0);
+       } else {
+               u16 wIntrRxE = musb_readw(musb->pRegs, MGC_O_HDRC_INTRRXE);
+               wIntrRxE &= ~(1 << bEnd);
+               musb_writew(musb->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(&musb->irq_work);
+
+       spin_unlock_irqrestore(&(musb->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 *musb, 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(musb->pRegs, req->bEnd);
+       if (req->bTx)
+               txstate(musb, req);
+       else
+               rxstate(musb, 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;
+       struct musb             *musb = pEnd->pThis;
+
+       if (!ep || !pRequest || to_musb_request(pRequest)->ep != pEnd)
+               return -EINVAL;
+
+       spin_lock_irqsave(&musb->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 = musb->pDmaController;
+
+               MGC_SelectEnd(musb->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(&musb->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             *musb = pEnd->pThis;
+       void __iomem            *epio = musb->aLocalEnd[bEnd].regs;
+       void __iomem            *pBase;
+       unsigned long           flags;
+       u16                     wCsr;
+       struct musb_request     *pRequest = NULL;
+       int                     status = 0;
+
+       pBase = musb->pRegs;
+
+       spin_lock_irqsave(&musb->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(&musb->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(musb, pRequest);
+       }
+
+       spin_unlock_irqrestore(&musb->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     *musb = gadget_to_musb(gadget);
+
+       return (int)musb_readw(musb->pRegs, MGC_O_HDRC_FRAME);
+}
+
+static int musb_gadget_wakeup(struct usb_gadget *gadget)
+{
+       struct musb     *musb = gadget_to_musb(gadget);
+       void __iomem    *mregs = musb->pRegs;
+       unsigned long   flags;
+       int             status = -EINVAL;
+       u8              power, devctl;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+
+       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->may_wakeup && musb->is_suspended)
+                       break;
+               goto done;
+       case OTG_STATE_B_IDLE:
+               /* Start SRP ... OTG not required. */
+               devctl = musb_readb(mregs, MGC_O_HDRC_DEVCTL);
+               devctl |= MGC_M_DEVCTL_SESSION;
+               musb_writeb(mregs, MGC_O_HDRC_DEVCTL, devctl);
+               DBG(2, "SRP\n");
+               status = 0;
+               goto done;
+       default:
+               goto done;
+       }
+
+       status = 0;
+
+       power = musb_readb(mregs, MGC_O_HDRC_POWER);
+       power |= MGC_M_POWER_RESUME;
+       musb_writeb(mregs, MGC_O_HDRC_POWER, power);
+       DBG(2, "issue wakeup\n");
+
+       /* FIXME do this next chunk in a timer callback, no udelay */
+       mdelay(2);
+
+       power = musb_readb(mregs, MGC_O_HDRC_POWER);
+       power &= ~MGC_M_POWER_RESUME;
+       musb_writeb(mregs, MGC_O_HDRC_POWER, power);
+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     *musb = gadget_to_musb(gadget);
+
+       musb->is_self_powered = !!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 *musb)
+{
+       u8                      bEnd;
+       struct musb_hw_ep       *hw_ep;
+       unsigned                count = 0;
+
+       /* intialize endpoint list just once */
+       INIT_LIST_HEAD(&(musb->g.ep_list));
+
+       for (bEnd = 0, hw_ep = musb->aLocalEnd;
+                       bEnd < musb->bEndCount;
+                       bEnd++, hw_ep++) {
+               if (hw_ep->bIsSharedFifo /* || !bEnd */) {
+                       init_peripheral_ep(musb, &hw_ep->ep_in, bEnd, 0);
+                       count++;
+               } else {
+                       if (hw_ep->wMaxPacketSizeTx) {
+                               init_peripheral_ep(musb, &hw_ep->ep_in,
+                                                       bEnd, 1);
+                               count++;
+                       }
+                       if (hw_ep->wMaxPacketSizeRx) {
+                               init_peripheral_ep(musb, &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 *musb = the_gadget;
+
+       if (!driver
+                       || driver->speed != USB_SPEED_HIGH
+                       || !driver->bind
+                       || !driver->setup)
+               return -EINVAL;
+
+       /* driver must be initialized to support peripheral mode */
+       if (!musb || !(musb->board_mode == MUSB_OTG
+                               || musb->board_mode != MUSB_OTG)) {
+               DBG(1,"%s, no dev??\n", __FUNCTION__);
+               return -ENODEV;
+       }
+
+       DBG(3, "registering driver %s\n", driver->function);
+       spin_lock_irqsave(&musb->Lock, flags);
+
+       if (musb->pGadgetDriver) {
+               DBG(1, "%s is already bound to %s\n",
+                               musb_driver_name,
+                               musb->pGadgetDriver->driver.name);
+               retval = -EBUSY;
+       } else {
+               musb->pGadgetDriver = driver;
+               musb->g.dev.driver = &driver->driver;
+               driver->driver.bus = NULL;
+               musb->softconnect = 1;
+               retval = 0;
+       }
+
+       spin_unlock_irqrestore(&musb->Lock, flags);
+
+       if (retval == 0)
+               retval = driver->bind(&musb->g);
+       if (retval != 0) {
+               DBG(3, "bind to driver %s failed --> %d\n",
+                       driver->driver.name, retval);
+               musb->pGadgetDriver = NULL;
+               musb->g.dev.driver = NULL;
+       }
+
+       /* start peripheral and/or OTG engines */
+       if (retval == 0) {
+               spin_lock_irqsave(&musb->Lock, flags);
+
+               /* REVISIT always use otg_set_peripheral(), handling
+                * issues including the root hub one below ...
+                */
+               musb->xceiv.gadget = &musb->g;
+               musb->xceiv.state = OTG_STATE_B_IDLE;
+               musb->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(musb))
+                       musb_start(musb);
+
+               spin_unlock_irqrestore(&musb->Lock, flags);
+
+               if (is_otg_enabled(musb)) {
+                       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(musb), -1, 0);
+                       if (retval < 0) {
+                               DBG(1, "add_hcd failed, %d\n", retval);
+                               spin_lock_irqsave(&musb->Lock, flags);
+                               musb->xceiv.gadget = NULL;
+                               musb->xceiv.state = OTG_STATE_UNDEFINED;
+                               musb->pGadgetDriver = NULL;
+                               musb->g.dev.driver = NULL;
+                               spin_unlock_irqrestore(&musb->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 *musb)
+{
+       musb->is_suspended = 0;
+       switch (musb->xceiv.state) {
+       case OTG_STATE_B_IDLE:
+               break;
+       case OTG_STATE_B_WAIT_ACON:
+       case OTG_STATE_B_PERIPHERAL:
+               musb->is_active = 1;
+               if (musb->pGadgetDriver && musb->pGadgetDriver->resume) {
+                       spin_unlock(&musb->Lock);
+                       musb->pGadgetDriver->resume(&musb->g);
+                       spin_lock(&musb->Lock);
+               }
+               break;
+       default:
+               WARN("unhandled RESUME transition (%s)\n",
+                               otg_state_string(musb));
+       }
+}
+
+/* called when SOF packets stop for 3+ msec */
+void musb_g_suspend(struct musb *musb)
+{
+       u8      devctl;
+
+       devctl = musb_readb(musb->pRegs, MGC_O_HDRC_DEVCTL);
+       DBG(3, "devctl %02x\n", devctl);
+
+       switch (musb->xceiv.state) {
+       case OTG_STATE_B_IDLE:
+               if ((devctl & MGC_M_DEVCTL_VBUS) == MGC_M_DEVCTL_VBUS)
+                       musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
+               break;
+       case OTG_STATE_B_PERIPHERAL:
+               musb->is_suspended = 1;
+               if (musb->pGadgetDriver && musb->pGadgetDriver->suspend) {
+                       spin_unlock(&musb->Lock);
+                       musb->pGadgetDriver->suspend(&musb->g);
+                       spin_lock(&musb->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(musb));
+       }
+}
+
+/* called when VBUS drops below session threshold, and in other cases */
+void musb_g_disconnect(struct musb *musb)
+{
+       void __iomem    *mregs = musb->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(&musb->g, 0);
+
+       musb->g.speed = USB_SPEED_UNKNOWN;
+       if (musb->pGadgetDriver && musb->pGadgetDriver->disconnect) {
+               spin_unlock(&musb->Lock);
+               musb->pGadgetDriver->disconnect(&musb->g);
+               spin_lock(&musb->Lock);
+       }
+
+       switch (musb->xceiv.state) {
+       default:
+#ifdef CONFIG_USB_MUSB_OTG
+               musb->xceiv.state = OTG_STATE_A_IDLE;
+               break;
+       case OTG_STATE_B_WAIT_ACON:
+       case OTG_STATE_B_HOST:
+#endif
+       case OTG_STATE_B_PERIPHERAL:
+               musb->xceiv.state = OTG_STATE_B_IDLE;
+               break;
+       case OTG_STATE_B_SRP_INIT:
+               break;
+       }
+
+       musb->is_active = 0;
+}
+
+void musb_g_reset(struct musb *musb)
+__releases(musb->Lock)
+__acquires(musb->Lock)
+{
+       void __iomem    *pBase = musb->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),
+                       musb->pGadgetDriver
+                               ? musb->pGadgetDriver->driver.name
+                               : NULL
+                       );
+
+       /* report disconnect, if we didn't already (flushing EP state) */
+       if (musb->g.speed != USB_SPEED_UNKNOWN)
+               musb_g_disconnect(musb);
+
+       /* 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);
+       musb->g.speed = (power & MGC_M_POWER_HSMODE)
+                       ? USB_SPEED_HIGH : USB_SPEED_FULL;
+
+       /* start in USB_STATE_DEFAULT */
+       musb->is_active = 1;
+       musb->is_suspended = 0;
+       MUSB_DEV_MODE(musb);
+       musb->bAddress = 0;
+       musb->ep0_state = MGC_END0_STAGE_SETUP;
+
+       musb->may_wakeup = 0;
+       musb->g.b_hnp_enable = 0;
+       musb->g.a_alt_hnp_support = 0;
+       musb->g.a_hnp_support = 0;
+
+       /* Normal reset, as B-Device;
+        * or else after HNP, as A-Device
+        */
+       if (devctl & MGC_M_DEVCTL_BDEVICE) {
+               musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
+               musb->g.is_a_peripheral = 0;
+       } else if (is_otg_enabled(musb)) {
+               musb->xceiv.state = OTG_STATE_A_PERIPHERAL;
+               musb->g.is_a_peripheral = 1;
+       } else
+               WARN_ON(1);
+
+       /* start with default limits on VBUS power draw */
+       (void) musb_gadget_vbus_draw(&musb->g,
+                       is_otg_enabled(musb) ? 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..82ece3b
--- /dev/null
@@ -0,0 +1,2199 @@
+/******************************************************************
+ * 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);
+
+/*
+ * Clear TX fifo. Needed to avoid BABBLE errors.
+ */
+static inline void musb_h_tx_flush_fifo(struct musb_hw_ep *ep)
+{
+       void __iomem    *epio = ep->regs;
+       u16             csr;
+       int             retries = 1000;
+
+       csr = musb_readw(epio, MGC_O_HDRC_TXCSR);
+       while (csr & MGC_M_TXCSR_FIFONOTEMPTY) {
+               DBG(5, "Host TX FIFONOTEMPTY csr: %02x\n", csr);
+               csr |= MGC_M_TXCSR_FLUSHFIFO;
+               musb_writew(epio, MGC_O_HDRC_TXCSR, csr);
+               csr = musb_readw(epio, MGC_O_HDRC_TXCSR);
+               if (retries-- < 1) {
+                       ERR("Could not flush host TX fifo: csr: %04x\n", csr);
+                       return;
+               }
+               mdelay(1);
+       }
+}
+
+/*
+ * 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() || tusb_dma_omap())
+                       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) {
+                       musb_h_tx_flush_fifo(ep);
+                       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 */
+                       musb_h_tx_flush_fifo(pEnd);
+                       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_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() || tusb_dma_omap()) && 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() || tusb_dma_omap()) && pDmaChannel) {
+                       /* 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 until it's time to start the status stage.
+ */
+static int musb_h_ep0_continue(struct musb *pThis,
+                               u16 wCount, struct urb *pUrb)
+{
+       int                      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;
+
+       switch (pThis->bEnd0Stage) {
+       case MGC_END0_IN:
+               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.
+                        */
+               } else if (pUrb->actual_length <
+                               pUrb->transfer_buffer_length)
+                       bMore = TRUE;
+               break;
+       case MGC_END0_START:
+               pRequest = (struct usb_ctrlrequest *) pUrb->setup_packet;
+
+               if (!pRequest->wLength) {
+                       DBG(4, "start no-DATA\n");
+                       break;
+               } else if (pRequest->bRequestType & USB_DIR_IN) {
+                       DBG(4, "start IN-DATA\n");
+                       pThis->bEnd0Stage = MGC_END0_IN;
+                       bMore = TRUE;
+                       break;
+               } else {
+                       DBG(4, "start OUT-DATA\n");
+                       pThis->bEnd0Stage = MGC_END0_OUT;
+                       bMore = TRUE;
+               }
+               /* FALLTHROUGH */
+       case MGC_END0_OUT:
+               wFifoCount = min(qh->maxpacket, ((u16)
+                               (pUrb->transfer_buffer_length
+                               - pUrb->actual_length)));
+
+               if (wFifoCount) {
+                       pFifoDest = (u8 *) (pUrb->transfer_buffer
+                                       + pUrb->actual_length);
+                       DBG(3, "Sending %d bytes to %p\n",
+                                       wFifoCount, pFifoDest);
+                       musb_write_fifo(pEnd, wFifoCount, pFifoDest);
+
+                       pUrb->actual_length += wFifoCount;
+                       bMore = TRUE;
+               }
+               break;
+       default:
+               ERR("bogus ep0 stage %d\n", pThis->bEnd0Stage);
+               break;
+       }
+
+       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 = (wCsrVal & MGC_M_CSR0_RXPKTRDY)
+                       ? musb_readb(epio, MGC_O_HDRC_COUNT0)
+                       : 0;
+
+       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 */
+                       if (usb_pipeout(pUrb->pipe)
+                                       || !pUrb->transfer_buffer_length)
+                               wCsrVal = MGC_M_CSR0_H_STATUSPKT
+                                       | MGC_M_CSR0_H_REQPKT;
+                       else
+                               wCsrVal = MGC_M_CSR0_H_STATUSPKT
+                                       | 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;
+       } else
+               pThis->bEnd0Stage = MGC_END0_IDLE;
+
+       /* 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.
+                */
+               musb_h_tx_flush_fifo(pEnd);
+               wTxCsrVal &= ~(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 {
+               musb_h_tx_flush_fifo(ep);
+               csr = musb_readw(epio, MGC_O_HDRC_TXCSR);
+               csr &= ~( MGC_M_TXCSR_AUTOSET
+                       | MGC_M_TXCSR_DMAENAB
+                       | MGC_M_TXCSR_H_RXSTALL
+                       | MGC_M_TXCSR_H_NAKTIMEOUT
+                       | MGC_M_TXCSR_H_ERROR
+                       );
+               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);
+
+       /* already completed */
+       if (!qh) {
+               status = 0;
+               goto done;
+       }
+
+       /* still queued but not found on the list */
+       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)
+{
+       struct musb     *musb = hcd_to_musb(hcd);
+
+       /* NOTE: musb_start() is called when the hub driver turns
+        * on port power, or when (OTG) peripheral starts.
+        */
+       hcd->state = HC_STATE_RUNNING;
+       musb->port1_status = 0;
+       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);
+
+       if (is_host_active(musb) && musb->is_active)
+               return -EBUSY;
+       else
+               return 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..5bddf30
--- /dev/null
@@ -0,0 +1,855 @@
+/******************************************************************
+ * 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_GADGET_MUSB_HDRC
+       code = sprintf(buffer, "Peripheral address: %02x\n",
+                       musb_readb(pThis, MGC_O_HDRC_FADDR));
+       if (code <= 0)
+               goto done;
+       buffer += code;
+       count += code;
+#endif
+
+#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; */
+
+       if (unlikely(copy_from_user(&cmd, buffer, 1)))
+               return -EFAULT;
+
+       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);
+
+                               if (copy_from_user(&digits, &buffer[1], len))
+                                       return -EFAULT;
+
+                               /* 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..a64e2ed
--- /dev/null
@@ -0,0 +1,541 @@
+/******************************************************************
+ * 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/clk.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 */
+enum musb_h_ep0_state {
+       MGC_END0_IDLE,
+       MGC_END0_START,                 /* expect ack of setup */
+       MGC_END0_IN,                    /* expect IN DATA */
+       MGC_END0_OUT,                   /* expect ack of OUT DATA */
+       MGC_END0_STATUS,                /* expect ack of STATUS */
+} __attribute__ ((packed));
+
+/* 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_OMAP2430)
+/* 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;
+       void __iomem            *fifo_sync_va;
+#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;
+
+       enum musb_h_ep0_state   bEnd0Stage;
+
+       /* 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;
+       void __iomem            *sync_va;
+#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);
+
+       int                     (*set_clock)(struct clk *clk, int is_active);
+
+       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
+       /* is_suspended means USB B_PERIPHERAL suspend */
+       unsigned                is_suspended:1;
+
+       /* may_wakeup means remote wakeup is enabled */
+       unsigned                may_wakeup:1;
+
+       /* is_self_powered is reported in device status and the
+        * config descriptor.  is_bus_powered means B_PERIPHERAL
+        * draws some VBUS current; both can be true.
+        */
+       unsigned                is_self_powered:1;
+       unsigned                is_bus_powered: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);
+extern void musb_platform_set_mode(struct musb *musb, u8 musb_mode);
+#else
+#define musb_platform_try_idle(x)              do {} while (0)
+#define musb_platform_get_vbus_status(x)       0
+#define musb_platform_set_mode(x, y)           do {} while (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..5cf0f04
--- /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_OMAP2430 */
+
+#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..856075f
--- /dev/null
@@ -0,0 +1,2049 @@
+/*****************************************************************
+ * 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 <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 |=
+                                               (USB_PORT_STAT_C_SUSPEND << 16)
+                                               | MUSB_PORT_STAT_RESUME;
+                                       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:
+                               /* disconnect while suspended?  we may
+                                * not get a disconnect irq...
+                                */
+                               if ((devctl & MGC_M_DEVCTL_VBUS)
+                                               != (3 << MGC_S_DEVCTL_VBUS)) {
+                                       pThis->int_usb |= MGC_M_INTR_DISCONNECT;
+                                       pThis->int_usb &= ~MGC_M_INTR_SUSPEND;
+                                       break;
+                               }
+                               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) {
+                       /*
+                        * BABBLE is an error condition, so the solution is
+                        * to avoid babble in the first place and fix whatever
+                        * causes BABBLE. When BABBLE happens we can only stop
+                        * the session.
+                        */
+                       ERR("Stopping host session because of babble\n");
+                       musb_writeb(pBase, MGC_O_HDRC_DEVCTL, 0);
+               } 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 power %02x\n",
+                               otg_state_string(pThis), devctl, power);
+               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);
+       if (musb->clock) {
+               clk_put(musb->clock);
+               musb->clock = NULL;
+       }
+       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);
+               hw_ep->fifo_sync_va =
+                       pThis->sync_va + 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_OMAP2430
+
+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 ssize_t
+musb_mode_store(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t n)
+{
+       struct musb     *musb = dev_to_musb(dev);
+       unsigned long   flags;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+       if (!strncmp(buf, "host", 4))
+               musb_platform_set_mode(musb, MUSB_HOST);
+       if (!strncmp(buf, "peripheral", 10))
+               musb_platform_set_mode(musb, MUSB_PERIPHERAL);
+       if (!strncmp(buf, "otg", 3))
+               musb_platform_set_mode(musb, MUSB_OTG);
+       spin_unlock_irqrestore(&musb->Lock, flags);
+
+       return n;
+}
+static DEVICE_ATTR(mode, 0644, musb_mode_show, musb_mode_store);
+
+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->set_clock = plat->set_clock;
+       pThis->min_power = plat->min_power;
+
+       /* Clock usage is chip-specific ... functional clock (DaVinci,
+        * OMAP2430), or PHY ref (some TUSB6010 boards).  All this core
+        * code does is make sure a clock handle is available; platform
+        * code manages it during start/stop and suspend/resume.
+        */
+       if (plat->clock) {
+               pThis->clock = clk_get(dev, plat->clock);
+               if (IS_ERR(pThis->clock)) {
+                       status = PTR_ERR(pThis->clock);
+                       pThis->clock = NULL;
+                       goto fail;
+               }
+       }
+
+       /* 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:
+               if (pThis->clock)
+                       clk_put(pThis->clock);
+               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..48c3ab3
--- /dev/null
@@ -0,0 +1,986 @@
+/*
+ * 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.
+ */
+
+static inline void
+tusb_fifo_write_unaligned(void __iomem *fifo, const u8 *buf, u16 len)
+{
+       u32             val;
+       int             i;
+
+       if (len > 4) {
+               for (i = 0; i < (len >> 2); i++) {
+                       memcpy(&val, buf, 4);
+                       musb_writel(fifo, 0, val);
+                       buf += 4;
+               }
+               len %= 4;
+       }
+       if (len > 0) {
+               /* Write the rest 1 - 3 bytes to FIFO */
+               memcpy(&val, buf, len);
+               musb_writel(fifo, 0, val);
+       }
+}
+
+static inline void tusb_fifo_read_unaligned(void __iomem *fifo,
+                                               void __iomem *buf, u16 len)
+{
+       u32             val;
+       int             i;
+
+       if (len > 4) {
+               for (i = 0; i < (len >> 2); i++) {
+                       val = musb_readl(fifo, 0);
+                       memcpy(buf, &val, 4);
+                       buf += 4;
+               }
+               len %= 4;
+       }
+       if (len > 0) {
+               /* Read the rest 1 - 3 bytes from FIFO */
+               val = musb_readl(fifo, 0);
+               memcpy(buf, &val, len);
+       }
+}
+
+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;
+
+       prefetch(buf);
+
+       DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
+                       'T', epnum, fifo, len, buf);
+
+       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));
+
+       if (likely((0x01 & (unsigned long) buf) == 0)) {
+
+               /* Best case is 32bit-aligned destination address */
+               if ((0x02 & (unsigned long) buf) == 0) {
+                       if (len >= 4) {
+                               writesl(fifo, buf, len >> 2);
+                               buf += (len & ~0x03);
+                               len &= 0x03;
+                       }
+               } else {
+                       if (len >= 2) {
+                               u32 val;
+                               int i;
+
+                               /* Cannot use writesw, fifo is 32-bit */
+                               for (i = 0; i < (len >> 2); i++) {
+                                       val = (u32)(*(u16 *)buf);
+                                       buf += 2;
+                                       val |= (*(u16 *)buf) << 16;
+                                       buf += 2;
+                                       musb_writel(fifo, 0, val);
+                               }
+                               len &= 0x03;
+                       }
+               }
+       }
+
+       if (len > 0)
+               tusb_fifo_write_unaligned(fifo, buf, len);
+}
+
+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;
+
+       DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
+                       'R', epnum, fifo, len, buf);
+
+       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));
+
+       if (likely((0x01 & (unsigned long) buf) == 0)) {
+
+               /* Best case is 32bit-aligned destination address */
+               if ((0x02 & (unsigned long) buf) == 0) {
+                       if (len >= 4) {
+                               readsl(fifo, buf, len >> 2);
+                               buf += (len & ~0x03);
+                               len &= 0x03;
+                       }
+               } else {
+                       if (len >= 2) {
+                               u32 val;
+                               int i;
+
+                               /* Cannot use readsw, fifo is 32-bit */
+                               for (i = 0; i < (len >> 2); i++) {
+                                       val = musb_readl(fifo, 0);
+                                       *(u16 *)buf = (u16)(val & 0xffff);
+                                       buf += 2;
+                                       *(u16 *)buf = (u16)(val >> 16);
+                                       buf += 2;
+                               }
+                               len &= 0x03;
+                       }
+               }
+       }
+
+       if (len > 0)
+               tusb_fifo_read_unaligned(fifo, buf, len);
+}
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+
+/* 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_draw_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.
+        *
+        * Boards sharing the CPU clock with CLKIN will need to prevent
+        * certain idle sleep states while the USB link is active.
+        *
+        * 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) {
+               if (musb->set_clock)
+                       musb->set_clock(musb->clock, 1);
+               musb->is_bus_powered = 1;
+               reg |= TUSB_PRCM_MNGMT_15_SW_EN | TUSB_PRCM_MNGMT_33_SW_EN;
+       } else {
+               musb->is_bus_powered = 0;
+               reg &= ~(TUSB_PRCM_MNGMT_15_SW_EN | TUSB_PRCM_MNGMT_33_SW_EN);
+               if (musb->set_clock)
+                       musb->set_clock(musb->clock, 0);
+       }
+       musb_writel(base, TUSB_PRCM_MNGMT, reg);
+
+       DBG(2, "draw max %d mA VBUS\n", mA);
+       return 0;
+}
+
+#else
+#define tusb_draw_power        NULL
+#endif
+
+/* 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 = what?
+        */
+       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(6, "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_source_power(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);
+}
+
+/*
+ * Sets the mode to OTG, peripheral or host by changing the ID detection.
+ * Caller must take care of locking.
+ *
+ * Note that if a mini-A cable is plugged in the ID line will stay down as
+ * the weak ID pull-up is not able to pull the ID up.
+ *
+ * REVISIT: It would be possible to add support for changing between host
+ * and peripheral modes in non-OTG configurations by reconfiguring hardware
+ * and then setting musb->board_mode. For now, only support OTG mode.
+ */
+void musb_platform_set_mode(struct musb *musb, u8 musb_mode)
+{
+       void __iomem    *base = musb->ctrl_base;
+       u32             otg_stat, phy_otg_ena, phy_otg_ctrl, dev_conf;
+       int             vbus = 0;
+
+       if (musb->board_mode != MUSB_OTG) {
+               ERR("Changing mode currently only supported in OTG mode\n");
+               return;
+       }
+
+       otg_stat = musb_readl(base, TUSB_DEV_OTG_STAT);
+       phy_otg_ena = musb_readl(base, TUSB_PHY_OTG_CTRL_ENABLE);
+       phy_otg_ctrl = musb_readl(base, TUSB_PHY_OTG_CTRL);
+       dev_conf = musb_readl(base, TUSB_DEV_CONF);
+
+       switch (musb_mode) {
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       case MUSB_HOST:         /* Disable PHY ID detect, ground ID */
+               if (!(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS)) {
+                       ERR("Already in host mode otg_stat: %08x\n", otg_stat);
+                       return;
+               }
+               phy_otg_ena |= TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP;
+               phy_otg_ctrl &= ~TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP;
+               dev_conf |= TUSB_DEV_CONF_ID_SEL;
+               dev_conf &= ~TUSB_DEV_CONF_SOFT_ID;
+               vbus = 1;
+               break;
+#endif
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+       case MUSB_PERIPHERAL:   /* Disable PHY ID detect, keep ID pull-up on */
+               if (otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS) {
+                       ERR("Already in peripheral mode otg_stat: %08x\n",
+                               otg_stat);
+                       return;
+               }
+               phy_otg_ena |= TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP;
+               phy_otg_ctrl |= TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP;
+               dev_conf |= (TUSB_DEV_CONF_ID_SEL | TUSB_DEV_CONF_SOFT_ID);
+               break;
+#endif
+
+#ifdef CONFIG_USB_MUSB_OTG
+       case MUSB_OTG:          /* Use PHY ID detection */
+               phy_otg_ena &= ~TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP;
+               phy_otg_ctrl &= ~TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP;
+               dev_conf &= ~(TUSB_DEV_CONF_ID_SEL | TUSB_DEV_CONF_SOFT_ID);
+               break;
+#endif
+
+       default:
+               DBG(2, "Trying to set unknown mode %i\n", musb_mode);
+       }
+
+       musb_writel(base, TUSB_PHY_OTG_CTRL_ENABLE,
+                       TUSB_PHY_OTG_CTRL_WRPROTECT | phy_otg_ena);
+       musb_writel(base, TUSB_PHY_OTG_CTRL,
+                       TUSB_PHY_OTG_CTRL_WRPROTECT | phy_otg_ctrl);
+       musb_writel(base, TUSB_DEV_CONF, dev_conf);
+
+       msleep(1);
+       otg_stat = musb_readl(base, TUSB_DEV_OTG_STAT);
+       if ((musb_mode == MUSB_PERIPHERAL) &&
+               !(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS))
+                       ERR("Cannot be peripheral with mini-A cable "
+                       "otg_stat: %08x\n", otg_stat);
+}
+
+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_source_power(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_source_power(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_source_power(musb, 0);
+                       }
+                       break;
+               case OTG_STATE_A_WAIT_BCON:
+                       if (OTG_TIME_A_WAIT_BCON)
+                               tusb_source_power(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(6, "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;
+       void __iomem            *sync;
+       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;
+
+       sync = ioremap(mem->start, mem->end - mem->start + 1);
+       if (!sync) {
+               pr_debug("ioremap for sync failed\n");
+               return -ENOMEM;
+       }
+       musb->sync_va = sync;
+
+       /* 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_source_power;
+       if (is_peripheral_enabled(musb))
+               musb->xceiv.set_power = tusb_draw_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);
+
+       iounmap(musb->sync_va);
+
+       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..ce5d9c5
--- /dev/null
@@ -0,0 +1,715 @@
+/*
+ * 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, pio;
+       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);
+
+       /* HW issue #10: XFR_SIZE may get corrupt on async DMA */
+       if (unlikely(remaining > chdat->transfer_len)) {
+               WARN("Corrupt XFR_SIZE with async DMA: %lu\n", remaining);
+               remaining = 0;
+       }
+
+       channel->dwActualLength = chdat->transfer_len - remaining;
+       pio = chdat->len - channel->dwActualLength;
+
+       DBG(2, "DMA remaining %lu/%u\n", remaining, chdat->transfer_len);
+
+       /* Transfer remaining 1 - 31 bytes */
+       if (pio > 0 && pio < 32) {
+               u8      *buf;
+
+               DBG(2, "Using PIO for remaining %lu bytes\n", pio);
+               buf = phys_to_virt((u32)chdat->dma_addr) + chdat->transfer_len;
+               if (chdat->tx) {
+                       consistent_sync(phys_to_virt((u32)chdat->dma_addr),
+                                       chdat->transfer_len, DMA_TO_DEVICE);
+                       musb_write_fifo(hw_ep, pio, buf);
+               } else {
+                       musb_read_fifo(hw_ep, pio, buf);
+                       consistent_sync(phys_to_virt((u32)chdat->dma_addr),
+                                       chdat->transfer_len, DMA_FROM_DEVICE);
+               }
+               channel->dwActualLength += pio;
+       }
+
+       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 must 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) || (len < 32) || (len > packet_sz))
+               return FALSE;
+
+       /*
+        * HW issue #10: Async dma will eventually corrupt the XFR_SIZE
+        * register which will cause missed DMA interrupt. We could try to
+        * use a timer for the callback, but it is unsafe as the XFR_SIZE
+        * register is corrupt, and we won't know if the DMA worked.
+        */
+       if (dma_addr & 0x2)
+               return FALSE;
+
+       chdat->transfer_len = len & ~0x1f;
+
+       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..6a65f4f
--- /dev/null
@@ -0,0 +1,386 @@
+/*****************************************************************
+ * 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 <asm/unaligned.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;
+               }
+
+               put_unaligned(cpu_to_le32(musb->port1_status & ~MUSB_PORT_STAT_RESUME),
+                               (__le32 *) buf);
+
+               /* port change status is more interesting */
+               DBG(get_unaligned((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 fbef663fc0571988001fa848a11b460020035972..33d71c10545f81bc665fc8500ea2fe85fa7241c3 100644 (file)
@@ -56,6 +56,15 @@ 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.
+
 config BACKLIGHT_PROGEAR
        tristate "Frontpath ProGear Backlight Driver"
        depends on BACKLIGHT_CLASS_DEVICE && PCI && X86
index c6e2266f63e2d6d7f728f196d31b65864d8699f5..4180388076f892052229f8bbe1a2f9e2c21daf74 100644 (file)
@@ -5,5 +5,6 @@ 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
 obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o
 obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.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 e02c15d158fc978d72e0b0647c87391a446af76b..e1bf4707aa7a244cc030486ff02a9be15221482d 100644 (file)
@@ -1,2 +1,3 @@
 arch
+asm-offsets.h
 mach-types.h
diff --git a/include/asm-arm/arch-omap/dsp.h b/include/asm-arm/arch-omap/dsp.h
new file mode 100644 (file)
index 0000000..ae71eb8
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * 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 __ARCH_OMAP_DSP_H
+#define __ARCH_OMAP_DSP_H
+
+/*
+ * 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
+#define MEM_IOCTL_MMUITACK     7
+#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
+
+#endif /* __ARCH_OMAP_DSP_H */
index 5a4c831926fa3ae04e9af8c61d78830d35f5568c..6662cb02bafc81cfda77a8d206188b98dbbf06ab 100644 (file)
@@ -48,14 +48,14 @@ enum eac_mclk_src {
 enum eac_codec_mode {
        EAC_CODEC_PCM,
        EAC_CODEC_AC97,
-       EAC_CODEC_I2S,
+       EAC_CODEC_I2S_MASTER, /* codec port, I.e. EAC is the master */
+       EAC_CODEC_I2S_SLAVE,
 };
 
 /* configuration structure for I2S mode */
 struct eac_i2s_conf {
-       /* it seems according to TRM that the polarity-changed I2S mode is not
-        * only that frame sync polarity (EAC.AC_FS) is changed but also direction
-        * of it and interface serial clock (EAC.AC_SCLK) */
+       /* if enabled, then first data slot (left channel) is signaled as
+        * positive level of frame sync EAC.AC_FS */
        unsigned        polarity_changed_mode:1;
        /* if enabled, then serial data starts one clock cycle after the
         * of EAC.AC_FS for first audio slot */
index 127cf880d5cf57097f4d01de3f971bdf218007f2..bb782943a524952fc841897a0d783acc473352af 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 2003-2005 Nokia Corporation
  *
- * Written by Juha Yrjölä <juha.yrjola@nokia.com>
+ * 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 as published by
@@ -78,6 +78,11 @@ extern int omap_get_gpio_datain(int gpio);
 extern void omap2_gpio_prepare_for_retention(void);
 extern void omap2_gpio_resume_after_retention(void);
 
+#ifdef CONFIG_ARCH_OMAP24XX
+extern void omap_set_gpio_debounce(int gpio, int enable);
+extern void omap_set_gpio_debounce_time(int gpio, int enable);
+#endif
+
 /*-------------------------------------------------------------------------*/
 
 /* wrappers for "new style" GPIO calls. the old OMAP-specfic ones should
index 6a8e07ffc2d03431b5da8b43b6a67122a212c071..e6e132244aa01f085b84caf137a276e70e03ef8f 100644 (file)
@@ -11,6 +11,9 @@
 #ifndef __OMAP2_GPMC_H
 #define __OMAP2_GPMC_H
 
+/* Maximum Number of Chip Selects */
+#define GPMC_CS_NUM            8
+
 #define GPMC_CS_CONFIG1                0x00
 #define GPMC_CS_CONFIG2                0x04
 #define GPMC_CS_CONFIG3                0x08
@@ -22,6 +25,9 @@
 #define GPMC_CS_NAND_ADDRESS   0x20
 #define GPMC_CS_NAND_DATA      0x24
 
+#define GPMC_CONFIG            0x50
+#define GPMC_STATUS            0x54
+
 #define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
 #define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
 #define GPMC_CONFIG1_READTYPE_ASYNC     (0 << 29)
index 3ede58b51db28f36688e451d173b51b1fffc12ab..08421cfdd5fbaa8a3d741058cfd48614a0d94903 100644 (file)
 #define INT_UART2              (15 + IH2_BASE)
 #define INT_BT_MCSI1TX         (16 + IH2_BASE)
 #define INT_BT_MCSI1RX         (17 + IH2_BASE)
+#define INT_SOSSI_MATCH                (19 + IH2_BASE)
 #define INT_USB_W2FC           (20 + IH2_BASE)
 #define INT_1WIRE              (21 + IH2_BASE)
 #define INT_OS_TIMER           (22 + IH2_BASE)
index 1b0e5392f5c99fcd13f94b1883eb7f06e8a5106c..b70e37b6124244ee8e8142f965bd85f03827fb45 100644 (file)
@@ -13,7 +13,6 @@
 
 #include <linux/types.h>
 #include <linux/device.h>
-#include <linux/mmc/protocol.h>
 #include <linux/mmc/host.h>
 
 #define OMAP_MMC_MAX_SLOTS     2
diff --git a/include/asm-arm/arch-omap/mmu.h b/include/asm-arm/arch-omap/mmu.h
new file mode 100644 (file)
index 0000000..bff433b
--- /dev/null
@@ -0,0 +1,215 @@
+#ifndef __ARCH_OMAP_MMU_H
+#define __ARCH_OMAP_MMU_H
+
+#include <linux/device.h>
+#include <linux/workqueue.h>
+
+#define MMU_REVISION           0x00
+#define MMU_SYSCONFIG          0x10
+#define MMU_SYSSTATUS          0x14
+#define MMU_IRQSTATUS          0x18
+#define MMU_IRQENABLE          0x1c
+#define MMU_WALKING_ST         0x40
+#define MMU_CNTL               0x44
+#define MMU_FAULT_AD           0x48
+#define MMU_TTB                        0x4c
+#define MMU_LOCK               0x50
+#define MMU_LD_TLB             0x54
+#define MMU_CAM                        0x58
+#define MMU_RAM                        0x5c
+#define MMU_GFLUSH             0x60
+#define MMU_FLUSH_ENTRY                0x64
+#define MMU_READ_CAM           0x68
+#define MMU_READ_RAM           0x6c
+#define MMU_EMU_FAULT_AD       0x70
+
+enum exmap_type {
+       EXMAP_TYPE_MEM,
+       EXMAP_TYPE_FB
+};
+
+enum omap_mmu_type {
+       OMAP_MMU_DSP,
+       OMAP_MMU_IVA1,
+       OMAP_MMU_CAMERA,
+};
+
+struct exmap_tbl {
+       unsigned int valid:1;
+       unsigned int prsvd:1;
+       int usecount;           /* reference count by mmap */
+       enum exmap_type 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 */
+};
+
+struct cam_ram_regset {
+       union {
+               struct {
+                       u16 cam_l;
+                       u16 cam_h;
+               };
+
+               u32 cam;
+       };
+
+       union {
+               struct {
+                       u16 ram_l;
+                       u16 ram_h;
+               };
+
+               u32 ram;
+       };
+};
+
+struct omap_mmu_tlb_lock {
+       int base;
+       int victim;
+};
+
+struct omap_mmu;
+struct omap_mmu_tlb_entry;
+
+struct omap_mmu_ops {
+       int (*startup)(struct omap_mmu *mmu);
+       void (*shutdown)(struct omap_mmu *mmu);
+
+       /* TLB operations */
+       void (*read_tlb)(struct omap_mmu *, struct cam_ram_regset *);
+       void (*load_tlb)(struct omap_mmu *, struct cam_ram_regset *);
+       ssize_t (*show)(struct omap_mmu *, char *, struct omap_mmu_tlb_lock *);
+
+       /* CAM / RAM operations */
+       struct cam_ram_regset *(*cam_ram_alloc)(struct omap_mmu_tlb_entry *);
+       int (*cam_ram_valid)(struct cam_ram_regset *);
+       unsigned long (*cam_va)(struct cam_ram_regset *);
+
+       /* Memory operations */
+       int (*mem_enable)(struct omap_mmu *, void *);
+       int (*mem_disable)(struct omap_mmu *, void *);
+
+       void (*interrupt)(struct omap_mmu *);
+
+       /* PTE attribute operations */
+       pgprot_t (*pte_get_attr)(struct omap_mmu_tlb_entry *);
+};
+
+struct omap_mmu {
+       const char *name;
+       unsigned long base;
+       struct clk *clk;
+
+       unsigned long membase, memsize;
+       struct clk *memclk;
+
+       enum omap_mmu_type type;
+
+       struct device dev;
+
+       struct rw_semaphore exmap_sem;
+       struct exmap_tbl *exmap_tbl;
+
+       unsigned int nr_tlb_entries;
+       unsigned int nr_exmap_preserved;
+
+       struct mm_struct *twl_mm;
+
+       /* Size of virtual address space, in bits */
+       unsigned int addrspace;
+
+       /* Interrupt */
+       unsigned int irq;
+       unsigned long fault_address;
+       struct work_struct irq_work;
+
+       struct omap_mmu_ops *ops;
+};
+
+#define omap_mmu_internal_memory(mmu, addr)                                    \
+       (likely(mmu->membase) && (((unsigned long)(addr) >= mmu->membase) &&    \
+                ((unsigned long)(addr) < mmu->membase + mmu->memsize)))
+
+#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 omap_mmu_to_virt(mmu, db)      ((void *)((mmu)->membase + (db)))
+#define virt_to_omap_mmu(mmu, va) \
+       (((unsigned long)(va) - (mmu)->membase))
+
+/* arch/arm/plat-omap/mmu.c */
+int omap_mmu_register(struct omap_mmu *mmu);
+void omap_mmu_unregister(struct omap_mmu *mmu);
+
+void omap_mmu_enable(struct omap_mmu *mmu, int reset);
+void omap_mmu_disable(struct omap_mmu *mmu);
+
+int omap_mmu_mem_enable(struct omap_mmu *mmu, void *addr);
+void omap_mmu_mem_disable(struct omap_mmu *mmu, void *addr);
+
+void omap_mmu_read_tlb(struct omap_mmu *mmu, struct omap_mmu_tlb_lock *lock,
+                      struct cam_ram_regset *cr);
+
+int omap_mmu_load_tlb_entry(struct omap_mmu *, struct omap_mmu_tlb_entry *);
+int omap_mmu_clear_tlb_entry(struct omap_mmu *, unsigned long vadr);
+
+int omap_mmu_load_pte_entry(struct omap_mmu *mmu,
+                           struct omap_mmu_tlb_entry *entry);
+int omap_mmu_clear_pte_entry(struct omap_mmu *mmu, unsigned long vadr);
+
+int omap_mmu_kmem_reserve(struct omap_mmu *mmu, unsigned long size);
+void omap_mmu_kmem_release(void);
+
+unsigned long omap_mmu_virt_to_phys(struct omap_mmu *mmu, void *vadr,
+                                   size_t *len);
+
+int omap_mmu_exmap(struct omap_mmu *mmu, unsigned long dspadr,
+                  unsigned long padr, unsigned long size,
+                  enum exmap_type type);
+int omap_mmu_exunmap(struct omap_mmu *mmu, unsigned long dspadr);
+void omap_mmu_exmap_flush(struct omap_mmu *mmu);
+void omap_mmu_exmap_use(struct omap_mmu *mmu, void *vadr, size_t len);
+void omap_mmu_exmap_unuse(struct omap_mmu *mmu, void *vadr, size_t len);
+
+int exmap_set_armmmu(unsigned long virt, unsigned long phys, unsigned long size);
+void exmap_clear_armmmu(unsigned long virt, unsigned long size);
+void exmap_setup_preserved_mem_page(struct omap_mmu *mmu, void *buf,
+                                   unsigned long dspadr, int index);
+void exmap_clear_mem_page(struct omap_mmu *mmu, unsigned long dspadr);
+int exmap_valid(struct omap_mmu *mmu, void *vadr, size_t len);
+
+/* To be obsolete for backward compatibility */
+ssize_t __omap_mmu_mem_read(struct omap_mmu *mmu, char *buf, loff_t offset, size_t count);
+ssize_t __omap_mmu_mem_write(struct omap_mmu *mmu, char *buf, loff_t offset, size_t count);
+
+#endif /* __ARCH_OMAP_MMU_H */
index fcaf44c14714c8f36f2c9d75eec216bb01027f41..7817124a7dd62d10807cedf05cd8a645adb3a9aa 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)
 
index 764329c73e578d75c638eb9ce520402a4a1a1fd4..2f806b391311e3bf11b8bf029b1d5d92d690f248 100644 (file)
 #define OMAP24XX_IVA_INTC_BASE 0x40000000
 #define IRQ_SIR_IRQ            0x0040
 
+#define OMAP24XX_CONTROL_STATUS        (L4_24XX_BASE + 0x2f8)
+
 #ifdef CONFIG_ARCH_OMAP2420
 #define OMAP24XX_32KSYNCT_BASE (L4_24XX_BASE + 0x4000)
 #define OMAP24XX_PRCM_BASE     (L4_24XX_BASE + 0x8000)
 #define OMAP24XX_SDRC_BASE     (L3_24XX_BASE + 0x9000)
-#define OMAP242X_CONTROL_STATUS        (L4_24XX_BASE + 0x2f8)
 #endif
 
 #ifdef CONFIG_ARCH_OMAP2430
 #define OMAP24XX_32KSYNCT_BASE (L4_WK_243X_BASE + 0x20000)
 #define OMAP24XX_PRCM_BASE     (L4_WK_243X_BASE + 0x6000)
-#define OMAP242X_CONTROL_STATUS        (L4_24XX_BASE + 0x2f8)
 #define OMAP243X_SMS_BASE      0x6C000000
 #define OMAP24XX_SDRC_BASE     0x6D000000
 #define OMAP243X_GPMC_BASE     0x6E000000
 #endif
 
 /* DSP SS */
+#ifdef CONFIG_ARCH_OMAP2420
 #define OMAP24XX_DSP_BASE      0x58000000
 #define OMAP24XX_DSP_MEM_BASE  (OMAP24XX_DSP_BASE + 0x0)
 #define OMAP24XX_DSP_IPI_BASE  (OMAP24XX_DSP_BASE + 0x1000000)
 #define OMAP24XX_DSP_MMU_BASE  (OMAP24XX_DSP_BASE + 0x2000000)
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2430
+#define OMAP24XX_DSP_BASE      0x5C000000
+#define OMAP24XX_DSP_MEM_BASE  (OMAP24XX_DSP_BASE + 0x0)
+#define OMAP24XX_DSP_MMU_BASE  (OMAP24XX_DSP_BASE + 0x1000000)
+#endif
 
 /* Mailbox */
 #define OMAP24XX_MAILBOX_BASE  (L4_24XX_BASE + 0x94000)
index 3e8ab2f49c9fc37ef22a421fc9b92ed99f01c8bd..6c959d0ce470931d7fbffd3877e869030c9db35a 100644 (file)
@@ -17,4 +17,5 @@ struct omap_onenand_platform_data {
        struct mtd_partition    *parts;
        int                     nr_parts;
        int                     (*onenand_setup)(void __iomem *);
+       int                     dma_channel;
 };
index 34f971bf3bf6de2cdbbfc73726744591dedaa8d1..297590308d18b7161038ccbeb73d3ef8ccb0f33e 100644 (file)
 
 #include <linux/clk.h>
 
-extern struct subsystem power_subsys;
+extern struct kset power_subsys;
 
 extern void prevent_idle_sleep(void);
 extern void allow_idle_sleep(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 b00ff3fb20de9ec84c0d20a892f0d898ec951a0d..449045841f66e71d6a41f9190b7278a06fdb19fb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *
- * TI TSC2101 Audio CODEC and TS control registers definition
- *
+ * TI TSC2101 Audio CODEC and TS control registers definition 
+ *          
  *
  * Copyright 2003 MontaVista Software Inc.
  * Author: MontaVista Software, Inc.
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 21dec9f258d822d081a0e7da9251de908f5e0462..8e401fb5246a28d6f7ee25d143cedf5272426f4c 100644 (file)
@@ -295,6 +295,7 @@ PTE_BIT_FUNC(mkyoung,   |= L_PTE_YOUNG);
 #define pmd_none(pmd)          (!pmd_val(pmd))
 #define pmd_present(pmd)       (pmd_val(pmd))
 #define pmd_bad(pmd)           (pmd_val(pmd) & 2)
+#define pmd_table(pmd)         ((pmd_val(pmd) & PMD_TYPE_MASK) == PMD_TYPE_TABLE)
 
 #define copy_pmd(pmdpd,pmdps)          \
        do {                            \
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 be2bf3a2b0313aaa3293855ca69680d655168f47..a6315593a0d818384c70f9811a4257d1ed966543 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
diff --git a/include/linux/spi/tsc2046.h b/include/linux/spi/tsc2046.h
new file mode 100644 (file)
index 0000000..aca712f
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef _LINUX_SPI_TSC2046_H
+#define _LINUX_SPI_TSC2046_H
+
+#include <linux/types.h>
+#include <linux/timer.h>
+
+struct tsc2046_platform_data {
+       s16     dav_gpio;
+       s16     gpio_debounce;
+       u16     ts_x_plate_ohm;
+       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;
+
+};
+
+struct tsc2046_ts;
+
+struct tsc2046 {
+       struct spi_device       *spi;
+       int                     gpio;
+
+       struct tsc2046_ts       *ts;
+};
+
+/* The TSC2046 operates at a maximum speed of 2MHz */
+#define TSC2046_HZ     2000000
+
+#define TSC2046_DECL_MOD(module)                                       \
+extern int  tsc2046_##module##_init(struct tsc2046 *tsc,               \
+                          struct tsc2046_platform_data *pdata);        \
+extern void tsc2046_##module##_exit(struct tsc2046 *tsc);              \
+extern int  tsc2046_##module##_suspend(struct tsc2046 *tsc);           \
+extern void tsc2046_##module##_resume(struct tsc2046 *tsc);
+
+#define TSC2046_DECL_EMPTY_MOD(module)                                 \
+static inline int tsc2046_##module##_init(struct tsc2046 *tsc,         \
+                          struct tsc2046_platform_data *pdata)         \
+{                                                                      \
+       return 0;                                                       \
+}                                                                      \
+static inline void tsc2046_##module##_exit(struct tsc2046 *tsc) {}     \
+static inline int  tsc2046_##module##_suspend(struct tsc2046 *tsc)     \
+{                                                                      \
+       return 0;                                                       \
+}                                                                      \
+static inline void tsc2046_##module##_resume(struct tsc2046 *tsc) {}
+
+#if defined(CONFIG_TOUCHSCREEN_TSC2046) || \
+    defined(CONFIG_TOUCHSCREEN_TSC2046_MODULE)
+TSC2046_DECL_MOD(ts)
+#else
+TSC2046_DECL_EMPTY_MOD(ts)
+#endif
+
+#endif
diff --git a/include/linux/usb/musb.h b/include/linux/usb/musb.h
new file mode 100644 (file)
index 0000000..da34a61
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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 clk;
+
+struct musb_hdrc_platform_data {
+       /* MUSB_HOST, MUSB_PERIPHERAL, or MUSB_OTG */
+       u8              mode;
+
+       /* for clk_get() */
+       const char      *clock;
+
+       /* (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);
+
+       /* Turn device clock on or off */
+       int             (*set_clock)(struct clk *clock, int is_on);
+};
+
+
+/* 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 0bbdeac2810cb53c4960cb303f4b396d29cbb341..889a2d7c91bf83d48f1a5848b455cdd90ff414d0 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 */
 
@@ -444,12 +448,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)
 {
@@ -461,6 +476,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();
@@ -536,6 +553,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 93b9fc76a18530fd1c860061f8eeb3e164368104..ede368afea1a6ace1de8e77c39645886ea8c1763 100644 (file)
@@ -248,6 +248,9 @@ config IP_NF_TARGET_IDLETIMER
 
          To compile it as a module, choose M here.  If unsure, say N.
 
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
 config NF_NAT_SNMP_BASIC
        tristate "Basic SNMP-ALG support (EXPERIMENTAL)"
        depends on EXPERIMENTAL && NF_NAT
index 460e5c9cf496c725b830d8f34bc8dcf0bd8bff56..873adfc84de376f64d4db1b54a6ce04776a82b25 100644 (file)
@@ -93,6 +93,14 @@ config SECURITY_ROOTPLUG
          
          If you are unsure how to answer this question, answer N.
 
+config SECURITY_LOWMEM
+       tristate "Low memory watermark support"
+       depends on SECURITY
+       help
+         Implements low memory watermark support.
+
+         If you are unsure how to answer this question, answer N.
+
 source security/selinux/Kconfig
 
 endmenu
index ef87df2f50a454ac0f9c5aedeb235b347a2706b4..9d5b0aade3d73444ab566f8af429391bde13fcbf 100644 (file)
@@ -16,3 +16,4 @@ obj-$(CONFIG_SECURITY)                        += security.o dummy.o inode.o
 obj-$(CONFIG_SECURITY_SELINUX)         += selinux/built-in.o
 obj-$(CONFIG_SECURITY_CAPABILITIES)    += commoncap.o capability.o
 obj-$(CONFIG_SECURITY_ROOTPLUG)                += commoncap.o root_plug.o
+obj-$(CONFIG_SECURITY_LOWMEM)          += commoncap.o lowmem.o
diff --git a/security/lowmem.c b/security/lowmem.c
new file mode 100644 (file)
index 0000000..a627d51
--- /dev/null
@@ -0,0 +1,334 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mman.h>
+#include <linux/init.h>
+#include <linux/security.h>
+#include <linux/sysctl.h>
+#include <linux/swap.h>
+#include <linux/kobject.h>
+#include <linux/pagemap.h>
+#include <linux/hugetlb.h>
+#include <linux/sysfs.h>
+
+#define MY_NAME "lowmem"
+
+#define LOWMEM_MAX_UIDS 8
+
+enum {
+       VM_LOWMEM_DENY = 1,
+       VM_LOWMEM_LEVEL1_NOTIFY,
+       VM_LOWMEM_LEVEL2_NOTIFY,
+       VM_LOWMEM_NR_DECAY_PAGES,
+       VM_LOWMEM_ALLOWED_UIDS,
+       VM_LOWMEM_ALLOWED_PAGES,
+       VM_LOWMEM_USED_PAGES,
+};
+
+static unsigned int deny_percentage;
+static unsigned int l1_notify, l2_notify;
+static unsigned int nr_decay_pages;
+static unsigned long allowed_pages;
+static long used_pages;
+static unsigned int allowed_uids[LOWMEM_MAX_UIDS];
+static unsigned int minuid = 1;
+static unsigned int maxuid = 65535;
+
+static ctl_table lowmem_table[] = {
+       {
+               .ctl_name = VM_LOWMEM_DENY,
+               .procname = "lowmem_deny_watermark",
+               .data = &deny_percentage,
+               .maxlen = sizeof(unsigned int),
+               .mode = 0644,
+               .child = NULL,
+               .proc_handler = &proc_dointvec,
+               .strategy = &sysctl_intvec,
+       }, {
+               .ctl_name = VM_LOWMEM_LEVEL1_NOTIFY,
+               .procname = "lowmem_notify_low",
+               .data = &l1_notify,
+               .maxlen = sizeof(unsigned int),
+               .mode = 0644,
+               .child = NULL,
+               .proc_handler = &proc_dointvec,
+               .strategy = &sysctl_intvec,
+       }, {
+               .ctl_name = VM_LOWMEM_LEVEL2_NOTIFY,
+               .procname = "lowmem_notify_high",
+               .data = &l2_notify,
+               .maxlen = sizeof(unsigned int),
+               .mode = 0644,
+               .child = NULL,
+               .proc_handler = &proc_dointvec,
+               .strategy = &sysctl_intvec,
+       }, {
+               .ctl_name = VM_LOWMEM_NR_DECAY_PAGES,
+               .procname = "lowmem_nr_decay_pages",
+               .data = &nr_decay_pages,
+               .maxlen = sizeof(unsigned int),
+               .mode = 0644,
+               .child = NULL,
+               .proc_handler = &proc_dointvec_minmax,
+               .strategy = &sysctl_intvec,
+       }, {
+               .ctl_name = VM_LOWMEM_ALLOWED_UIDS,
+               .procname = "lowmem_allowed_uids",
+               .data = &allowed_uids,
+               .maxlen = LOWMEM_MAX_UIDS * sizeof(unsigned int),
+               .mode = 0644,
+               .child = NULL,
+               .proc_handler = &proc_dointvec_minmax,
+               .strategy = &sysctl_intvec,
+               .extra1 = &minuid,
+               .extra2 = &maxuid,
+       }, {
+               .ctl_name = VM_LOWMEM_ALLOWED_PAGES,
+               .procname = "lowmem_allowed_pages",
+               .data = &allowed_pages,
+               .maxlen = sizeof(unsigned long),
+               .mode = 0444,
+               .child = NULL,
+               .proc_handler = &proc_dointvec_minmax,
+               .strategy = &sysctl_intvec,
+       }, {
+               .ctl_name = VM_LOWMEM_USED_PAGES,
+               .procname = "lowmem_used_pages",
+               .data = &used_pages,
+               .maxlen = sizeof(long),
+               .mode = 0444,
+               .child = NULL,
+               .proc_handler = &proc_dointvec_minmax,
+               .strategy = &sysctl_intvec,
+       }, {
+               .ctl_name = 0
+       }
+};
+
+static ctl_table lowmem_root_table[] = {
+       {
+               .ctl_name = CTL_VM,
+               .procname = "vm",
+               .mode = 0555,
+               .child = lowmem_table,
+       }, {
+               .ctl_name = 0
+       }
+};
+
+#define KERNEL_ATTR_RO(_name) \
+static struct subsys_attribute _name##_attr = __ATTR_RO(_name)
+
+static int low_watermark_reached, high_watermark_reached;
+
+static ssize_t low_watermark_show(struct subsystem *subsys, char *page)
+{
+       return sprintf(page, "%u\n", low_watermark_reached);
+}
+
+static ssize_t high_watermark_show(struct subsystem *subsys, char *page)
+{
+       return sprintf(page, "%u\n", high_watermark_reached);
+}
+
+KERNEL_ATTR_RO(low_watermark);
+KERNEL_ATTR_RO(high_watermark);
+
+static void low_watermark_state(int new_state)
+{
+       int changed = 0;
+
+       if (low_watermark_reached != new_state) {
+               low_watermark_reached = new_state;
+               changed = 1;
+       }
+
+       if (changed)
+               sysfs_notify(&kernel_subsys.kset.kobj, NULL, "low_watermark");
+}
+
+static void high_watermark_state(int new_state)
+{
+       int changed = 0;
+
+       if (high_watermark_reached != new_state) {
+               high_watermark_reached = new_state;
+               changed = 1;
+       }
+
+       if (changed)
+               sysfs_notify(&kernel_subsys.kset.kobj, NULL, "high_watermark");
+}
+
+static int low_vm_enough_memory(long pages)
+{
+       unsigned long free, allowed;
+       long deny_threshold, level1, level2, used;
+       int cap_sys_admin = 0, notify;
+
+       if (cap_capable(current, CAP_SYS_ADMIN) == 0)
+               cap_sys_admin = 1;
+
+       /* We activate ourselves only after both parameters have been
+        * configured. */
+       if (deny_percentage == 0 || l1_notify == 0 || l2_notify == 0)
+               return __vm_enough_memory(pages, cap_sys_admin);
+
+       allowed = totalram_pages - hugetlb_total_pages();
+       deny_threshold = allowed * deny_percentage / 100;
+       level1 = allowed * l1_notify / 100;
+       level2 = allowed * l2_notify / 100;
+
+       vm_acct_memory(pages);
+
+       /* Easily freed pages when under VM pressure or direct reclaim */
+       free = global_page_state(NR_FILE_PAGES);
+       free += nr_swap_pages;
+       free += global_page_state(NR_SLAB_RECLAIMABLE);
+
+       used = allowed - free;
+       if (unlikely(used < 0))
+               used = 0;
+
+       /* The hot path, plenty of memory */
+       if (likely(used < level1))
+               goto enough_memory;
+
+       /* No luck, lets make it more expensive and try again.. */
+       used -= nr_free_pages();
+
+       if (used >= deny_threshold) {
+               int i;
+
+               allowed_pages = allowed;
+               used_pages = used;
+               low_watermark_state(1);
+               high_watermark_state(1);
+               /* Memory allocations by root are always allowed */
+               if (cap_sys_admin)
+                       return 0;
+
+               /* uids from allowed_uids vector are also allowed no matter what */
+               for (i = 0; i < LOWMEM_MAX_UIDS && allowed_uids[i]; i++)
+                       if (current->uid == allowed_uids[i])
+                               return 0;
+
+               vm_unacct_memory(pages);
+               if (printk_ratelimit()) {
+                       printk(MY_NAME ": denying memory allocation to process %d (%s)\n",
+                              current->pid, current->comm);
+               }
+               return -ENOMEM;
+       }
+
+enough_memory:
+       /* See if we need to notify level 1 */
+       low_watermark_state(used >= level1);
+
+       /*
+        * In the level 2 notification case things are more complicated,
+        * as the level that we drop the state and send a notification
+        * should be lower than when it is first triggered. Having this
+        * on the same watermark level ends up bouncing back and forth
+        * when applications are being stupid.
+        */
+       notify = used >= level2;
+       if (notify || used + nr_decay_pages < level2)
+               high_watermark_state(notify);
+
+       /* We have plenty of memory */
+       allowed_pages = allowed;
+       used_pages = used;
+       return 0;
+}
+
+static struct security_operations lowmem_security_ops = {
+       /* Use the capability functions for some of the hooks */
+       .ptrace = cap_ptrace,
+       .capget = cap_capget,
+       .capset_check = cap_capset_check,
+       .capset_set = cap_capset_set,
+       .capable = cap_capable,
+
+       .bprm_apply_creds = cap_bprm_apply_creds,
+       .bprm_set_security = cap_bprm_set_security,
+
+       .task_post_setuid = cap_task_post_setuid,
+       .task_reparent_to_init = cap_task_reparent_to_init,
+       .vm_enough_memory = low_vm_enough_memory,
+};
+
+static struct ctl_table_header *lowmem_table_header;
+/* flag to keep track of how we were registered */
+static int secondary;
+
+static struct attribute *lowmem_attrs[] = {
+       &low_watermark_attr.attr,
+       &high_watermark_attr.attr,
+       NULL,
+};
+
+static struct attribute_group lowmem_attr_group = {
+       .attrs  = lowmem_attrs,
+};
+
+static int __init lowmem_init(void)
+{
+       int r;
+
+       /* register ourselves with the security framework */
+       if (register_security(&lowmem_security_ops)) {
+               printk(KERN_ERR MY_NAME ": Failure registering with the kernel\n");
+               /* try registering with primary module */
+               if (mod_reg_security(MY_NAME, &lowmem_security_ops)) {
+                       printk(KERN_ERR ": Failure registering with the primary"
+                              "security module.\n");
+                       return -EINVAL;
+               }
+               secondary = 1;
+       }
+
+       /* initialize the uids vector */
+       memset(allowed_uids, 0, sizeof(allowed_uids));
+
+       lowmem_table_header = register_sysctl_table(lowmem_root_table);
+       if (unlikely(!lowmem_table_header))
+               return -EPERM;
+
+       kernel_subsys.kset.kobj.kset = &kernel_subsys.kset;
+
+       r = sysfs_create_group(&kernel_subsys.kset.kobj,
+                              &lowmem_attr_group);
+       if (unlikely(r))
+               return r;
+
+       printk(KERN_INFO MY_NAME ": Module initialized.\n");
+
+       return 0;
+}
+
+static void __exit lowmem_exit(void)
+{
+       /* remove ourselves from the security framework */
+       if (secondary) {
+               if (mod_unreg_security(MY_NAME, &lowmem_security_ops))
+                       printk(KERN_ERR MY_NAME ": Failure unregistering "
+                              "with the primary security module.\n");
+       } else {
+               if (unregister_security(&lowmem_security_ops)) {
+                       printk(KERN_ERR MY_NAME ": Failure unregistering "
+                              "with the kernel.\n");
+               }
+       }
+
+       unregister_sysctl_table(lowmem_table_header);
+
+       sysfs_remove_group(&kernel_subsys.kset.kobj, &lowmem_attr_group);
+
+       printk(KERN_INFO MY_NAME ": Module removed.\n");
+}
+
+module_init(lowmem_init);
+module_exit(lowmem_exit);
+
+MODULE_DESCRIPTION("Low watermark LSM module");
+MODULE_LICENSE("GPL");
index 2e4a5e0d16db3726755dea8c8930f35138927395..3646307669121fccb0b529a771f68b9f9887cea1 100644 (file)
@@ -33,4 +33,71 @@ 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 SPI_TSC2101
+        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 SPI_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.
+
+config SND_OMAP24XX_EAC
+       tristate "Audio driver for OMAP24xx EAC"
+       depends on SND
+       help
+         Audio driver for Enhanced Audio Controller found in TI's OMAP24xx
+         processors.
+
+         Currently contains only low-level support functions for
+         initializing EAC HW, creating ALSA sound card instance for it
+         and registering mixer controls implemented by a codec driver.
+         PCM stream is expected to be under DSP co-processor control.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-omap24xx-eac.
+
 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..2f004d7
--- /dev/null
@@ -0,0 +1,18 @@
+#
+## 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
+
+obj-$(CONFIG_SND_OMAP24XX_EAC) += snd-omap24xx-eac.o
+snd-omap24xx-eac-objs := eac.o
diff --git a/sound/arm/omap/eac.c b/sound/arm/omap/eac.c
new file mode 100644 (file)
index 0000000..c4bbf61
--- /dev/null
@@ -0,0 +1,802 @@
+/*
+ * linux/sound/arm/omap/omap-alsa-eac.c
+ *
+ * OMAP24xx Enhanced Audio Controller sound driver
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ *
+ * Contact: Jarkko Nikula <jarkko.nikula@nokia.com>
+ *          Juha Yrjölä
+ *
+ * Definitions:
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * 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
+ *
+ */
+
+#define DEBUG
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/arch/eac.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+
+
+#define EAC_CPCFR1             0x0000
+#define EAC_CPCFR2             0x0004
+#define EAC_CPCFR3             0x0008
+#define EAC_CPCFR4             0x000C
+#define EAC_CPTCTL             0x0010
+#define EAC_CPTTADR            0x0014
+#define EAC_CPTDATL            0x0018
+#define EAC_CPTDATH            0x001C
+#define EAC_CPTVSLL            0x0020
+#define EAC_CPTVSLH            0x0024
+#define EAC_MPCTR              0x0040
+#define EAC_MPMCCFR            0x0044
+#define EAC_BPCTR              0x0060
+#define EAC_BPMCCFR            0x0064
+#define EAC_AMSCFR             0x0080
+#define EAC_AMVCTR             0x0084
+#define EAC_AM1VCTR            0x0088
+#define EAC_AM2VCTR            0x008C
+#define EAC_AM3VCTR            0x0090
+#define EAC_ASTCTR             0x0094
+#define EAC_APD1LCR            0x0098
+#define EAC_APD1RCR            0x009C
+#define EAC_APD2LCR            0x00A0
+#define EAC_APD2RCR            0x00A4
+#define EAC_APD3LCR            0x00A8
+#define EAC_APD3RCR            0x00AC
+#define EAC_APD4R              0x00B0
+#define EAC_ADWR               0x00B4
+#define EAC_ADRDR              0x00B8
+#define EAC_AGCFR              0x00BC
+#define EAC_AGCTR              0x00C0
+#define EAC_AGCFR2             0x00C4
+#define EAC_AGCFR3             0x00C8
+#define EAC_MBPDMACTR          0x00CC
+#define EAC_MPDDMARR           0x00D0
+#define EAC_MPDDMAWR           0x00D4
+#define EAC_MPUDMARR           0x00D8
+#define EAC_MPUDMAWR           0x00E0
+#define EAC_BPDDMARR           0x00E4
+#define EAC_BPDDMAWR           0x00E8
+#define EAC_BPUDMARR           0x00EC
+#define EAC_BPUDMAWR           0x00F0
+#define EAC_VERSION            0x0100
+#define EAC_SYSCONFIG          0x0104
+#define EAC_SYSSTATUS          0x0108
+
+/* CPTCTL */
+#define CPTCTL_RXF             (1 << 7)        /* receive data register full */
+#define CPTCTL_RXIE            (1 << 6)        /* receive interrupt enable */
+#define CPTCTL_TXE             (1 << 5)        /* transmit register empty */
+#define CPTCTL_TXIE            (1 << 4)        /* transmit interrupt enable */
+#define CPTCTL_CPEN            (1 << 3)        /* codec port enable */
+#define CPTCTL_CRST            (1 << 0)        /* external codec reset */
+
+/* CPCFR1 */
+#define CPCFR1_MTSL(val)       ((val & 0x1f) << 3)     /* number of time slots per frame */
+#define CPCFR1_MTSL_BITS       (0x1f << 3)
+#define CPCFR1_MODE(val)       ((val & 0x7) << 0)      /* codec port interface mode */
+#define CPCFR1_MODE_BITS       (0x7 << 0)
+
+/* CPCFR2 */
+#define CPCFR2_TSLOL(val)      ((val & 0x3) << 6)      /* time slot 0 length in number of serial clock (CLK_BIT) cycles */
+#define CPCFR2_TSLOL_BITS      (0x3 << 6)
+#define CPCFR2_BPTSL(val)      ((val & 0x7) << 3)      /* number of data bits per audio time slot */
+#define CPCFR2_BPTSL_BITS      (0x7 << 3)
+#define CPCFR2_TSLL(val)       ((val & 0x7) << 0)      /* time slot lenght (except slot 0) in number of serial clock cycles */
+#define CPCFR2_TSLL_BITS       (0x7 << 0)
+
+/* CPCFR3 */
+#define CPCFR3_DDLY            (1 << 7)        /* data delay: data bits start according to SYNC signal leading edge */
+#define CPCFR3_TRSEN           (1 << 6)        /* 3-state enable: data serial output state during nonvalid audio frames */
+#define CPCFR3_CLKBP           (1 << 5)        /* clock polarity */
+#define CPCFR3_CSYNCP          (1 << 4)        /* cp_sync(synchro) polarity */
+#define CPCFR3_CSYNCL          (1 << 3)        /* csync length */
+/* bit 2 reserved */
+#define CPCFR3_CSCLKD          (1 << 1)        /* cp_sclk port (serial clock) direction */
+#define CPCFR3_CSYNCD          (1 << 0)        /* cp_sync (synchro) direction */
+
+/* CPCFR4 */
+#define CPCFR4_ATSL(val)       ((val & 0xf) << 4)      /* audio time slots for secondary communication address and data values */
+#define CPCFR4_ATSL_BITS       (0xf << 4)
+#define CPCFR4_CLKS            (1 << 3)                /* clock source */
+#define CPCFR4_DIVB(val)       ((val & 0x7) << 0)      /* cp_sclk driver value */
+#define CPCFR4_DIVB_BITS       (0x7 << 0)
+
+/* AGCFR */
+#define AGCFR_MN_ST            (1 << 10)       /* mono/stereo audio file */
+#define AGCFR_B8_16            (1 << 9)        /* 8 bits/16 bits audio file */
+#define AGCFR_LI_BI            (1 << 8)        /* audio file endianism */
+#define AGCFR_FSINT(val)       ((val & 0x3) << 6) /* intermediate sample frequency for DMA read and write operations */
+#define AGCFR_FINST_BITS       (0x3 << 6)
+
+#define AGCFR_FSINT_8000       (0)             /* 8000  Hz */
+#define AGCFR_FSINT_11025      (1)             /* 11025 Hz */
+#define AGCFR_FSINT_22050      (2)             /* 22050 Hz */
+#define AGCFR_FSINT_44100      (3)             /* 44100 Hz */
+
+#define AGCFR_AUD_CKSRC(val)((val & 0x3) << 4) /* audio processing clock source */
+#define AGCFR_AUD_CKSRC_BITS   (0x3 << 4)
+#define AGCFR_M_CKSRC          (1 << 3)        /* modem interface clock source */
+#define AGCFR_MCLK_OUT         (1 << 1)
+#define AGCFR_MCLK             (1 << 0)
+
+
+/* AGCTR */
+#define AGCTR_AUDRD            (1 << 15)       /* audio ready */
+#define AGCTR_AUDRDI           (1 << 14)       /* audio ready interrupt status */
+#define AGCTR_AUDRDIEN         (1 << 13)       /* audio ready interrupt enable */
+#define AGCTR_DMAREN           (1 << 12)       /* audio files play operation */
+#define AGCTR_DMAWEN           (1 << 11)       /* audio file record operation */
+/* bits 10:4 reserved */
+#define AGCTR_MCLK_EN          (1 << 3)        /* internal MCLK enable */
+#define AGCTR_OSCMCLK_EN       (1 << 2)        /* OSCMCLK_EN output for MCLK oscillator control */
+#define AGCTR_AUDEN            (1 << 1)        /* audio processing enable/disable */
+#define AGCTR_EACPWD           (1 << 0)        /* EAC operation */
+
+/* AGCFR2 */
+#define AGCFR2_BT_MD_WIDEBAND  (1 << 5)        /* the BT device and modem AuSPIs wide-band mode */
+#define AGCFR2_MCLK_I2S_N11M_12M (1 << 4)      /* MCLK freq indicator for audio operations */
+#define AGCFR2_I2S_N44K_48K    (1 << 3)        /* Frame sample frecuency of I2S codec port, does not generate value */
+#define AGCFR2_FSINT2(val)     ((val & 0x7) << 0) /* intermediate sample frequency for DMA channel read and write operations */
+#define AGCFR2_FSINT2_BITS     (0x7 << 0)
+
+#define AGCFR2_FSINT2_8000     (0)             /* 8000  Hz */
+#define AGCFR2_FSINT2_11025    (1)             /* 11025 Hz */
+#define AGCFR2_FSINT2_22050    (2)             /* 22050 Hz */
+#define AGCFR2_FSINT2_44100    (3)             /* 44100 Hz */
+#define AGCFR2_FSINT2_48000    (4)             /* 48000 Hz */
+#define AGCFR2_FSINT2_FSINT    (7)             /* based on AGCFR/FSINT */
+
+
+/* AGCFR3 */
+#define AGCFR3_CP_TR_DMA       (1 << 15)       /* codec port transparent DMA (to audio DMAs) */
+#define AGCFR3_BT_TR_DMA       (1 << 14)       /* BT transparent DMA (to BT UL write & DL read DMAs */     
+#define AGCFR3_MD_TR_DMA       (1 << 13)       /* modem transparent DMA (to modem UL write and DL read DMAs) */
+#define AGCFR3_FSINT(val)      ((val & 0xf) << 9) /* FSINT */
+#define AGCFR3_FSINT_BITS      (0xf << 9)
+
+#define AGCFR3_FSINT_8000      (0)             /* 8000  Hz */
+#define AGCFR3_FSINT_11025     (1)             /* 11025 Hz */
+#define AGCFR3_FSINT_16000     (2)             /* 16000 Hz */
+#define AGCFR3_FSINT_22050     (3)             /* 22050 Hz */
+#define AGCFR3_FSINT_24000     (4)             /* 24000 Hz */
+#define AGCFR3_FSINT_32000     (5)             /* 32000 Hz */
+#define AGCFR3_FSINT_44100     (6)             /* 44100 Hz */
+#define AGCFR3_FSINT_48000     (7)             /* 48000 Hz */
+#define AGCFR3_FSINT_FSINT     (15)            /* based on AGCFR2/AGCFR */
+
+
+#define AGCFR3_BT_CKSRC(val)   ((val & 0x3) << 7)      /* BT port clock selection */
+#define AGCFR3_BT_CKSRC_BITS   (0x3 << 7)
+#define AGCFR3_MD_CKSRC(val)   ((val & 0x3) << 5)      /* modem port clock source */
+#define AGCFR3_MD_CKSRC_BITS   (0x3 << 5)
+#define AGCFR3_AUD_CKSRC(val)  ((val & 0x7) << 2)      /* audio and codec port clock source */
+#define AGCFR3_AUD_CKSRC_BITS  (0x7 << 2)
+#define AGCFR3_CLK12MINT_SEL   (1 << 1)                /* internal 12MHz clock source */
+#define AGCFR3_MCLKINT_SEL     (1 << 0)                /* internal codec master clock source */
+
+/* AMSCFR */
+#define AMSCFR_K12             (1 << 11)               /* K12 switch open/close */
+#define AMSCFR_K11             (1 << 10)
+#define AMSCFR_K10             (1 << 9)
+#define AMSCFR_K9              (1 << 8)
+#define AMSCFR_K8              (1 << 7)
+#define AMSCFR_K7              (1 << 6)
+#define AMSCFR_K6              (1 << 5)
+#define AMSCFR_K5              (1 << 4)
+#define AMSCFR_K4              (1 << 3)
+#define AMSCFR_K3              (1 << 2)
+#define AMSCFR_K2              (1 << 1)
+#define AMSCFR_K1              (1 << 0)
+
+/* AMVCTR */
+#define AMVCTR_GWO_BITS                (0xff << 8)
+#define AMVCTR_GWO(val)                ((val & 0xff) << 8)     /* Gain on write DMA operation */
+#define AMVCTR_GRO_BITS                (0xff << 0)
+#define AMVCTR_GRO(val)                ((val & 0xff) << 0)     /* Gain on read DMA operation */
+
+/* AM1VCTR */
+#define AM1VCTR_MUTE           (1 << 15)               /* mute/no mute on mixer output */
+#define AM1VCTR_GINB(val)      ((val & 0x7f) << 8)     /* gain on input B */
+#define AM1VCTR_GINB_BITS      (0x7f << 8)
+#define AM1VCTR_GINA(val)      ((val & 0x7f) << 0)     /* gain on input A */
+#define AM1VCTR_GINA_BITS      (0x7f << 0)
+
+/* AM2VCTR */
+#define AM2VCTR_MUTE           (1 << 15)               /* mute/no mute on mixer output */
+#define AM2VCTR_GINB(val)      ((val & 0x7f) << 8)     /* gain on input B */
+#define AM2VCTR_GINB_BITS      (0x7f << 8)
+#define AM2VCTR_GINA(val)      ((val & 0x7f) << 0)     /* gain on input A */
+#define AM2VCTR_GINA_BITS      (0x7f << 0)
+
+/* AM3VCTR */
+#define AM3VCTR_MUTE           (1 << 15)               /* mute/no mute */
+#define AM3VCTR_GINB(val)      ((val & 0x7f) << 8)     /* gain on input B */
+#define AM3VCTR_GINB_BITS      (0x7f << 8)
+#define AM3VCTR_GINA(val)      ((val & 0x7f) << 0)     /* gain on input A */
+#define AM3VCTR_GINA_BITS      (0x7f << 0)
+
+/* ASTCTR */
+#define ASTCTR_ATT(val)                ((val & 0x7f) << 1)     /* Attenuation of side tone */
+#define ASTCTR_ATT_BITS                (0x7f << 1)
+#define ASTCTR_ATTEN           (1 << 0)                /* side tone enabled/disabled */
+
+
+/* internal structure of the EAC driver */
+struct omap_eac {
+       struct mutex                    mutex;
+       void __iomem *                  base;
+       struct platform_device *        pdev;
+       struct eac_platform_data *      pdata;
+       struct snd_card *               card;
+       struct clk *                    fck;
+       struct clk *                    ick;
+       struct eac_codec *              codec;
+
+       unsigned                        clocks_enabled:1;
+};
+
+static char *id = SNDRV_DEFAULT_STR1;
+module_param(id, charp, 0444);
+MODULE_PARM_DESC(id, "ID string for OMAP24xx EAC");
+
+
+#define MOD_REG_BIT(val, mask, set) do { \
+       if (set) \
+               val |= mask; \
+       else \
+               val &= ~mask; \
+} while(0)
+
+static inline void eac_write_reg(struct omap_eac *eac, int idx, u16 val)
+{
+       __raw_writew(val, eac->base + idx);
+}
+
+static inline u16 eac_read_reg(struct omap_eac *eac, int idx)
+{
+       return __raw_readw(eac->base + idx);
+}
+
+static int eac_get_clocks(struct omap_eac *eac)
+{
+       eac->ick = clk_get(NULL, "eac_ick");
+       if (IS_ERR(eac->ick)) {
+               dev_err(&eac->pdev->dev, "Could not get eac_ick");
+               return -ENODEV;
+       }
+
+       eac->fck = clk_get(NULL, "eac_fck");
+       if (IS_ERR(eac->fck)) {
+               dev_err(&eac->pdev->dev, "Could not get eac_fck");
+               clk_put(eac->ick);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void eac_put_clocks(struct omap_eac *eac)
+{
+       clk_put(eac->fck);
+       clk_put(eac->ick);
+}
+
+static int eac_enable_clocks(struct omap_eac *eac)
+{
+       int err = 0;
+
+       if (eac->clocks_enabled)
+               return 0;
+
+       if (eac->pdata != NULL && eac->pdata->enable_ext_clocks != NULL) {
+               if ((err = eac->pdata->enable_ext_clocks(&eac->pdev->dev)) != 0)
+                       return err;
+       }
+       clk_enable(eac->ick);
+       clk_enable(eac->fck);
+       eac->clocks_enabled = 1;
+
+       return 0;
+}
+
+static void eac_disable_clocks(struct omap_eac *eac)
+{
+       if (!eac->clocks_enabled)
+               return;
+       eac->clocks_enabled = 0;
+
+       clk_disable(eac->fck);
+       clk_disable(eac->ick);
+       if (eac->pdata != NULL && eac->pdata->disable_ext_clocks != NULL)
+               eac->pdata->disable_ext_clocks(&eac->pdev->dev);
+}
+
+static int eac_reset(struct omap_eac *eac)
+{
+       int i;
+
+       /* step 1 (see TRM) */
+       /* first, let's reset the EAC */
+       eac_write_reg(eac, EAC_SYSCONFIG, 0x2);
+       /* step 2 (see TRM) */
+       eac_write_reg(eac, EAC_AGCTR, AGCTR_MCLK_EN | AGCTR_AUDEN);
+       /* step 3 (see TRM) */
+       /* wait until reset done */
+       i = 10000;
+       while (!(eac_read_reg(eac, EAC_SYSSTATUS) & 1)) {
+               if (--i == 0)
+                       return -ENODEV;
+               udelay(1);
+       }
+
+       return 0;
+}
+
+static int eac_calc_agcfr3_fsint(int rate)
+{
+       int fsint;
+
+       if (rate >= 48000)
+               fsint = AGCFR3_FSINT_48000;
+       else if (rate >= 44100)
+               fsint = AGCFR3_FSINT_44100;
+       else if (rate >= 32000)
+               fsint = AGCFR3_FSINT_32000;
+       else if (rate >= 24000)
+               fsint = AGCFR3_FSINT_24000;
+       else if (rate >= 22050)
+               fsint = AGCFR3_FSINT_22050;
+       else if (rate >= 16000)
+               fsint = AGCFR3_FSINT_16000;
+       else if (rate >= 11025)
+               fsint = AGCFR3_FSINT_11025;
+       else
+               fsint = AGCFR3_FSINT_8000;
+
+       return fsint;
+}
+
+static int eac_configure_pcm(struct omap_eac *eac, struct eac_codec *conf)
+{
+       dev_err(&eac->pdev->dev,
+               "EAC codec port configuration for PCM not implemented\n");
+
+       return -ENODEV;
+}
+
+static int eac_configure_ac97(struct omap_eac *eac, struct eac_codec *conf)
+{
+       dev_err(&eac->pdev->dev,
+               "EAC codec port configuration for AC97 not implemented\n");
+
+       return -ENODEV;
+}
+
+static int eac_configure_i2s(struct omap_eac *eac, struct eac_codec *conf)
+{
+       u16 cpcfr1, cpcfr2, cpcfr3, cpcfr4;
+
+       cpcfr1 = eac_read_reg(eac, EAC_CPCFR1);
+       cpcfr2 = eac_read_reg(eac, EAC_CPCFR2);
+       cpcfr3 = eac_read_reg(eac, EAC_CPCFR3);
+       cpcfr4 = eac_read_reg(eac, EAC_CPCFR4);
+
+       cpcfr1 &= ~(CPCFR1_MODE_BITS | CPCFR1_MTSL_BITS);
+       cpcfr1 |= CPCFR1_MTSL(1); /* 2 timeslots per frame (I2S default) */
+
+       /* audio time slot configuration for I2S mode */
+       cpcfr2 &= ~(CPCFR2_TSLL_BITS | CPCFR2_BPTSL_BITS | CPCFR2_TSLOL_BITS);
+       cpcfr2 |= CPCFR2_TSLOL(0); /* time slot 0 length same as TSLL */
+       cpcfr2 |= CPCFR2_BPTSL(1); /* 16 data bits per time slot */
+       cpcfr2 |= CPCFR2_TSLL(1); /* time slot length 16 serial clock cycles */
+
+       /* I2S link configuration */
+       MOD_REG_BIT(cpcfr3, CPCFR3_DDLY,
+               conf->codec_conf.i2s.sync_delay_enable); /* 0/1 clk delay */
+       /* data serial output enabled during nonvalid audio frames, clock
+        * polarity = falling edge, CSYNC lenght equal to time slot0 length */
+       MOD_REG_BIT(cpcfr3, CPCFR3_TRSEN, 1);
+       MOD_REG_BIT(cpcfr3, CPCFR3_CLKBP, 1);
+       MOD_REG_BIT(cpcfr3, CPCFR3_CSYNCL, 1);
+
+       cpcfr4 &= ~(CPCFR4_DIVB_BITS | CPCFR4_ATSL_BITS);
+       cpcfr4 |= CPCFR4_DIVB(7); /* CP_SCLK = MCLK / 8 */
+
+       /* configuration for normal I2S or polarity-changed I2S */
+       if (!conf->codec_conf.i2s.polarity_changed_mode) {
+               cpcfr1 |= CPCFR1_MODE(4); /* I2S mode */
+               MOD_REG_BIT(cpcfr3, CPCFR3_CSYNCP, 0); /* CP_SYNC active low */
+               /* audio time slots configuration for I2S */
+               cpcfr4 |= CPCFR4_ATSL(0);
+       } else {
+               cpcfr1 |= CPCFR1_MODE(1); /* PCM mode/polarity-changed I2S */
+               MOD_REG_BIT(cpcfr3, CPCFR3_CSYNCP, 1); /* CP_SYNC active
+                                                         high */
+               /* audio time slots configuration for polarity-changed I2S */
+               cpcfr4 |= CPCFR4_ATSL(0xf);
+       };
+
+       /* master/slave configuration */
+       if (conf->codec_mode == EAC_CODEC_I2S_MASTER) {
+               /* EAC is master. Set CP_SCLK and CP_SYNC as outputs */
+               MOD_REG_BIT(cpcfr3, CPCFR3_CSCLKD, 0);
+               MOD_REG_BIT(cpcfr3, CPCFR3_CSYNCD, 0);
+       } else {
+               /* EAC is slave. Set CP_SCLK and CP_SYNC as inputs */
+               MOD_REG_BIT(cpcfr3, CPCFR3_CSCLKD, 1);
+               MOD_REG_BIT(cpcfr3, CPCFR3_CSYNCD, 1);
+       }
+
+       eac_write_reg(eac, EAC_CPCFR1, cpcfr1);
+       eac_write_reg(eac, EAC_CPCFR2, cpcfr2);
+       eac_write_reg(eac, EAC_CPCFR3, cpcfr3);
+       eac_write_reg(eac, EAC_CPCFR4, cpcfr4);
+
+       return 0;
+}
+
+static int eac_codec_port_init(struct omap_eac *eac, struct eac_codec *conf)
+{
+       u16 agcfr, agcfr2, agcfr3, agctr;
+       u16 cpctl, reg;
+       int err = 0, i;
+
+       /* use internal MCLK gating before doing full configuration for it.
+        * Partial or misconfigured MCLK will cause that access to some of the
+        * EAC registers causes "external abort on linefetch". Same happens
+        * also when using external clock as a MCLK source and if that clock is
+        * either missing or not having a right rate (e.g. half of it) */
+       agcfr3 = eac_read_reg(eac, EAC_AGCFR3);
+       MOD_REG_BIT(agcfr3, AGCFR3_MCLKINT_SEL, 1); /* 96 Mhz / 8.5 */
+       eac_write_reg(eac, EAC_AGCFR3, agcfr3);
+
+       /* disable codec port, enable access to config registers */
+       cpctl = eac_read_reg(eac, EAC_CPTCTL);
+       MOD_REG_BIT(cpctl, CPTCTL_CPEN, 0);
+       eac_write_reg(eac, EAC_CPTCTL, cpctl);
+
+       agcfr = eac_read_reg(eac, EAC_AGCFR);
+       agctr = eac_read_reg(eac, EAC_AGCTR);
+       agcfr2 = eac_read_reg(eac, EAC_AGCFR2);
+
+       /* MCLK source and frequency configuration */
+       MOD_REG_BIT(agcfr, AGCFR_MCLK, 0);
+       switch (conf->mclk_src) {
+       case EAC_MCLK_EXT_2x11289600:
+               MOD_REG_BIT(agcfr, AGCFR_MCLK, 1); /* div by 2 path */
+               MOD_REG_BIT(agcfr, AGCFR_MCLK_OUT, 1); /* div by 2 */
+       case EAC_MCLK_EXT_11289600:
+               MOD_REG_BIT(agcfr, AGCFR_MCLK, 1);
+               MOD_REG_BIT(agcfr2, AGCFR2_I2S_N44K_48K, 0); /* 44.1 kHz */
+               MOD_REG_BIT(agcfr2, AGCFR2_MCLK_I2S_N11M_12M, 0); /* 11.2896 */
+               MOD_REG_BIT(agcfr3, AGCFR3_MCLKINT_SEL, 0);
+               break;
+
+       case EAC_MCLK_EXT_2x12288000:
+               MOD_REG_BIT(agcfr, AGCFR_MCLK, 1); /* div by 2 path */
+               MOD_REG_BIT(agcfr, AGCFR_MCLK_OUT, 1); /* div by 2 */
+       case EAC_MCLK_EXT_12288000:
+               MOD_REG_BIT(agcfr2, AGCFR2_I2S_N44K_48K, 1); /* 48 kHz */
+               MOD_REG_BIT(agcfr2, AGCFR2_MCLK_I2S_N11M_12M, 1); /* 12.288 */
+               MOD_REG_BIT(agcfr3, AGCFR3_MCLKINT_SEL, 0);
+               break;
+
+       default:
+               /* internal MCLK gating */
+               break;
+       }
+       MOD_REG_BIT(agctr, AGCTR_MCLK_EN, 1);
+       MOD_REG_BIT(agctr, AGCTR_OSCMCLK_EN, 1); /* oscillator enabled? */
+       /* use MCLK just configured above as audio & codec port clock source */
+       agcfr3 &= ~AGCFR3_AUD_CKSRC_BITS;
+       agcfr3 |= AGCFR3_AUD_CKSRC(0);
+
+       /* audio data format */
+       MOD_REG_BIT(agcfr, AGCFR_MN_ST, 1);     /* stereo file */
+       MOD_REG_BIT(agcfr, AGCFR_B8_16, 1);     /* 16 bit audio file */
+       MOD_REG_BIT(agcfr, AGCFR_LI_BI, 0);     /* little endian stream */
+
+       /* there are FSINT configuration bits in AGCFR, AGCFR2 and AGCFR3
+        * registers but it seems that it is just enough to set in AGCFR3
+        * only */
+       agcfr3 &= ~AGCFR3_FSINT_BITS;
+       agcfr3 |= AGCFR3_FSINT(eac_calc_agcfr3_fsint(conf->default_rate));
+
+       /* transparent DMA enable bits */
+       MOD_REG_BIT(agcfr3, AGCFR3_MD_TR_DMA, 1); /* modem */
+       MOD_REG_BIT(agcfr3, AGCFR3_BT_TR_DMA, 1); /* BT */
+       if (conf->codec_mode != EAC_CODEC_I2S_SLAVE)
+               MOD_REG_BIT(agcfr3, AGCFR3_CP_TR_DMA, 0);
+       else
+               MOD_REG_BIT(agcfr3, AGCFR3_CP_TR_DMA, 1);
+
+       /* step 4 (see TRM) */
+       eac_write_reg(eac, EAC_AGCFR3, agcfr3);
+       /* pre-write AGCTR now (finally in step 10) in order to get MCLK
+        * settings effective (especially when using external MCLK) */
+       eac_write_reg(eac, EAC_AGCTR, agctr);
+       eac_write_reg(eac, EAC_AGCFR2, agcfr2);
+
+       /* step 5 (see TRM) */
+       eac_write_reg(eac, EAC_AGCFR, agcfr);
+
+       /* step 6 (see TRM) */
+       /* wait until audio reset done */
+       i = 10000;
+       while (!(eac_read_reg(eac, EAC_SYSSTATUS) & (1 << 3))) {
+               if (--i == 0)
+                       return -ETIMEDOUT;
+               udelay(1);
+       }
+
+       /* step 7 (see TRM) */
+       reg = eac_read_reg(eac, EAC_AMSCFR);
+       MOD_REG_BIT(reg, AMSCFR_K1, 1);         /* K1 switch closed */
+       MOD_REG_BIT(reg, AMSCFR_K5, 1);         /* K5 switch closed */
+       MOD_REG_BIT(reg, AMSCFR_K2, 0);         /* K2 switch open */
+       MOD_REG_BIT(reg, AMSCFR_K6, 0);         /* K6 switch open */
+       eac_write_reg(eac, EAC_AMSCFR, reg);
+
+       /* step 8 (see TRM) */
+       switch (conf->codec_mode) {
+       case EAC_CODEC_PCM:
+               err = eac_configure_pcm(eac, conf);
+               break;
+       case EAC_CODEC_AC97:
+               err = eac_configure_ac97(eac, conf);
+               break;
+       default:
+               err = eac_configure_i2s(eac, conf);
+               break;
+       }
+
+       /* step 9 (see TRM) */
+       MOD_REG_BIT(cpctl, CPTCTL_CPEN, 1);     /* codec port enable */
+       MOD_REG_BIT(cpctl, CPTCTL_RXIE, 1);     /* receive int enable */
+       MOD_REG_BIT(cpctl, CPTCTL_TXIE, 1);     /* transmit int enable */
+       eac_write_reg(eac, EAC_CPTCTL, cpctl);
+
+       /* step 10 (see TRM) */
+       /* enable playing & recording */
+       MOD_REG_BIT(agctr, AGCTR_DMAREN, 1);    /* playing enabled (DMA R) */
+       MOD_REG_BIT(agctr, AGCTR_DMAWEN, 1);    /* recording enabled (DMA W) */
+       MOD_REG_BIT(agctr, AGCTR_AUDEN, 1);     /* audio processing enabled */
+       eac_write_reg(eac, EAC_AGCTR, agctr);
+
+       /* audio mixer1, no mute on mixer output, gain = 0 dB */
+       reg = eac_read_reg(eac, EAC_AM1VCTR);
+       MOD_REG_BIT(reg, AM1VCTR_MUTE, 0);
+       reg = ((reg & ~AM1VCTR_GINB_BITS) | (AM1VCTR_GINB(0x67)));
+       eac_write_reg(eac, EAC_AM1VCTR, reg);
+
+       /* audio mixer3, no mute on mixer output, gain = 0 dB */
+       reg = eac_read_reg(eac, EAC_AM3VCTR);
+       MOD_REG_BIT(reg, AM3VCTR_MUTE, 0);
+       reg = ((reg & ~AM3VCTR_GINB_BITS) | (AM3VCTR_GINB(0x67)));
+       eac_write_reg(eac, EAC_AM3VCTR, reg);
+
+       /* audio side tone disabled */
+       eac_write_reg(eac, EAC_ASTCTR, 0x0);
+
+       return 0;
+}
+
+int eac_set_mode(struct device *dev, int play, int rec)
+{
+       struct omap_eac *eac = dev_get_drvdata(dev);
+
+#ifdef DEBUG
+       printk(KERN_DEBUG "EAC mode: play %s, rec %s\n",
+              play ? "enabled" : "disabled",
+              rec  ? "enabled" : "disabled");
+#endif
+       BUG_ON(eac == NULL);
+       mutex_lock(&eac->mutex);
+       if (play || rec) {
+               /* activate clocks */
+               eac_enable_clocks(eac);
+
+               /* power-up codec */
+               if (eac->codec != NULL && eac->codec->set_power != NULL)
+                       eac->codec->set_power(eac->codec->private_data,
+                               play, rec);
+       } else {
+               /* shutdown codec */
+               if (eac->codec != NULL && eac->codec->set_power != NULL)
+                       eac->codec->set_power(eac->codec->private_data, 0, 0);
+
+               /* de-activate clocks */
+               eac_disable_clocks(eac);
+       }
+       mutex_unlock(&eac->mutex);
+
+       return 0;
+}
+
+int eac_register_codec(struct device *dev, struct eac_codec *codec)
+{
+       struct omap_eac *eac = dev_get_drvdata(dev);
+       struct snd_card *card = eac->card;
+       int err;
+
+       BUG_ON(eac->codec != NULL);
+
+       mutex_lock(&eac->mutex);
+       eac->codec = codec;
+       eac_enable_clocks(eac);
+       err = eac_codec_port_init(eac, codec);
+       eac_disable_clocks(eac);
+       mutex_unlock(&eac->mutex);
+       if (err)
+               return err;
+
+       /* register mixer controls implemented by a codec driver */
+       if (codec->register_controls != NULL) {
+               err = codec->register_controls(codec->private_data, card);
+               if (err)
+                       return err;
+       }
+
+       if (codec->short_name != NULL) {
+               sprintf(card->longname, "%s with codec %s", card->shortname,
+                       codec->short_name);
+               strcpy(card->mixername, codec->short_name);
+       }
+
+       err = snd_card_register(card);
+       return err;
+}
+
+void eac_unregister_codec(struct device *dev)
+{
+       struct omap_eac *eac = dev_get_drvdata(dev);
+
+       BUG_ON(eac->codec == NULL);
+       eac_set_mode(dev, 0, 0);
+       snd_card_disconnect(eac->card);
+       eac->codec = NULL;
+}
+
+static int __devinit eac_probe(struct platform_device *pdev)
+{
+       struct eac_platform_data *pdata = pdev->dev.platform_data;
+       struct snd_card *card;
+       struct omap_eac *eac;
+       struct resource *res;
+       int err;
+
+       eac = kzalloc(sizeof(*eac), GFP_KERNEL);
+       if (!eac)
+               return -ENOMEM;
+
+       mutex_init(&eac->mutex);
+       eac->pdev = pdev;
+       platform_set_drvdata(pdev, eac);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               err = -ENODEV;
+               goto err1;
+       }
+       eac->base = (void __iomem *)io_p2v(res->start);
+       eac->pdata = pdata;
+
+       /* pre-initialize EAC hw */
+       err = eac_get_clocks(eac);
+       if (err)
+               goto err1;
+       err = eac_enable_clocks(eac);
+       if (err)
+               goto err2;
+
+       err = eac_reset(eac);
+       if (err)
+               goto err3;
+
+       dev_info(&pdev->dev, "EAC version: %d.%d\n",
+                eac_read_reg(eac, EAC_VERSION) >> 4,
+                eac_read_reg(eac, EAC_VERSION) & 0x0f);
+       eac_disable_clocks(eac);
+
+       /* create soundcard instance */
+       card = snd_card_new(-1, id, THIS_MODULE, 0);
+       if (card == NULL) {
+               err = -ENOMEM;
+               goto err3;
+       }
+       eac->card = card;
+       strcpy(card->driver, "EAC");
+       strcpy(card->shortname, "OMAP24xx EAC");
+
+       sprintf(card->longname, "%s", card->shortname);
+       strcpy(card->mixername, "EAC Mixer");
+
+       if (eac->pdata->init) {
+               err = eac->pdata->init(&pdev->dev);
+               if (err < 0) {
+                       printk("init %d\n", err);
+                       goto err4;
+               }
+       }
+
+       return 0;
+
+err4:
+       snd_card_free(card);
+err3:
+       eac_disable_clocks(eac);
+err2:
+       eac_put_clocks(eac);
+err1:
+       kfree(eac);
+       return err;
+}
+
+static int __devexit eac_remove(struct platform_device *pdev)
+{
+       struct omap_eac *eac = platform_get_drvdata(pdev);
+       struct snd_card *card = eac->card;
+
+       snd_card_free(card);
+
+       eac_disable_clocks(eac);
+       eac_put_clocks(eac);
+
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver eac_driver = {
+       .driver = {
+               .name           = "omap24xx-eac",
+               .bus            = &platform_bus_type,
+       },
+       .probe          = eac_probe,
+       .remove         = eac_remove,
+};
+
+int __init eac_init(void)
+{
+       return platform_driver_register(&eac_driver);
+}
+
+void __exit eac_exit(void)
+{
+       platform_driver_unregister(&eac_driver);
+}
+
+module_init(eac_init);
+module_exit(eac_exit);
+MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>");
+MODULE_LICENSE("GPL");
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..726302a
--- /dev/null
@@ -0,0 +1,498 @@
+/*
+ * 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(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 snd_omap_get_bool(struct snd_kcontrol * kcontrol,
+                            struct snd_ctl_elem_value * 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(struct snd_kcontrol * kcontrol,
+                            struct snd_ctl_elem_value * 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(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_info * 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(struct snd_kcontrol * kcontrol,
+                           struct snd_ctl_elem_value * 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(struct snd_kcontrol * kcontrol,
+                           struct snd_ctl_elem_value * 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(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info * 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(struct snd_kcontrol * kcontrol,
+                              struct snd_ctl_elem_value * 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(struct snd_kcontrol * kcontrol,
+                              struct snd_ctl_elem_value * 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(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info * 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(struct snd_kcontrol * kcontrol,
+                              struct snd_ctl_elem_value * 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(struct snd_kcontrol * kcontrol,
+                              struct snd_ctl_elem_value * 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 struct snd_kcontrol_new 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)
+{
+       struct snd_card *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..1e8a101
--- /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 struct snd_pcm_hw_constraint_list aic23_hw_constraints_rates = {
+       .count = ARRAY_SIZE(rates),
+       .list = rates,
+       .mask = 0,
+};
+
+static struct snd_pcm_hardware 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 struct snd_pcm_hardware 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..8faba95
--- /dev/null
@@ -0,0 +1,1122 @@
+/*
+ * 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(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     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(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *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(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *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(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *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(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *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(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *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(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       return dac_gain_control_unmute(ucontrol->value.integer.value[0], 
+                                       ucontrol->value.integer.value[1]);
+}
+
+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        = 100;
+       return 0;
+}
+
+static int __headset_playback_volume_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *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(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       return set_mixer_volume_as_headset_gain_control_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;
+}
+
+/* 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(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *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(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *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(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        = 100;
+       return 0;
+}
+
+static int __handset_playback_volume_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *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(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       return set_mixer_volume_as_handset_gain_control_volume(ucontrol->value.integer.value[0]);       
+}
+
+static int __handset_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;
+}
+
+/* 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(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *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(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *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(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;
+}
+
+/* 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(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *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(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+                               TSC2101_BUZZER_GAIN_CTRL,
+                               15);    
+}
+
+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;
+}
+
+/* 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(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *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(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+                               TSC2101_BUZZER_GAIN_CTRL,
+                               6);     
+}
+
+static struct snd_kcontrol_new 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..26fabfb
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * sound/arm/omap/omap-alsa-tsc2101-mixer.h
+ * 
+ * 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..24b0cc6
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+ * sound/arm/omap/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 struct snd_pcm_hw_constraint_list 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 struct snd_pcm_hardware 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..6cb2db3
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * sound/arm/omap/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..d1c8b65
--- /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(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *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(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *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(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *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(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *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(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *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(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *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(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_deemphasis_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = filter[0];
+       return 0;
+}
+
+static int __pcm_playback_deemphasis_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol) 
+{
+       filter[0] = (ucontrol->value.integer.value[0] > 0);
+
+       tsc2102_set_deemphasis(filter[0]);
+       return 1;
+}
+
+static int __pcm_playback_bassboost_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_bassboost_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = filter[1];
+       return 0;
+}
+
+static int __pcm_playback_bassboost_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol) 
+{
+       filter[1] = (ucontrol->value.integer.value[0] > 0);
+
+       tsc2102_set_bassboost(filter[1]);
+       return 1;
+}
+
+static struct snd_kcontrol_new tsc2102_controls[] __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_controls); i ++) {
+               err = snd_ctl_add(tsc2102->card,
+                               snd_ctl_new1(&tsc2102_controls[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..2e1643a
--- /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 struct snd_pcm_hw_constraint_list tsc2102_hw_constraints_rates = {
+       .count = ARRAY_SIZE(rates),
+       .list = rates,
+       .mask = 0,
+};
+
+static struct snd_pcm_hardware 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..8d0f394
--- /dev/null
@@ -0,0 +1,581 @@
+/*
+ * 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 <sound/pcm.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)
+{
+       struct snd_pcm_substream *substream = s->stream;
+       struct snd_pcm_runtime *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)
+{
+       struct snd_pcm_substream *substream = s->stream;
+       struct snd_pcm_runtime *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(struct snd_pcm_substream * 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(struct snd_pcm_substream * substream)
+{
+       struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *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(struct snd_pcm_substream *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(struct snd_pcm_substream * substream)
+{
+       struct snd_card_omap_codec *chip =
+           snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *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(struct snd_pcm_substream * 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(struct snd_pcm_substream * substream,
+                                  struct snd_pcm_hw_params * hw_params)
+{
+       return snd_pcm_lib_malloc_pages(substream,
+                                       params_buffer_bytes(hw_params));
+}
+
+static int snd_omap_alsa_hw_free(struct snd_pcm_substream * substream)
+{
+       return snd_pcm_lib_free_pages(substream);
+}
+
+/* pcm operations */
+static struct snd_pcm_ops 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 struct snd_pcm_ops 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)
+{
+       struct snd_pcm *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;
+       struct snd_card *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;
+       struct snd_card *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(struct snd_card * 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;
+       struct snd_card *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)
+{
+       struct snd_card *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 */