--- /dev/null
+
+ 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://sourceforge.net/projects/uboot/
+
+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 BitKeeper tree, or by
+applying patches. The BitKeeper tree has the most up to date sources
+and is the recommended one.
+
+- Using BitKeeper:
+
+You need to download the bk tool from:
+
+http://www.bitmover.com/
+
+Download the dynamic one (x86-glibc22-linux) instead of the static
+(x86-static-linux). Some users reported problems with the static version.
+
+After bk tool is installed, to learn more about bitkeeper you can follow the
+tutorial at:
+
+http://www.bitkeeper.com/UG/
+
+Then you can clone OMAP Linux by:
+
+bk clone http://linux-omap.bkbits.net/main
+
+Now, you have a copy (clone) of the reprository. To work with it and to
+compile the kernel you have to check out the files from your local
+repository by:
+
+bk -r get (or: bk -r edit)
+
+For kernel related BitKeeper information see also kernel documentation in:
+
+Documentation/BK-usage/bk-kernel-howto.txt
+
+Hint: If you are sitting behind a firewall and have to use a proxy for
+internet access, you can access BitKeeper 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 BitKeeper, 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 BitKeeper or by patch, you
+should look into arch/arm/config/ 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).
+
+/* 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/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/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/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/. 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/common.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/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/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
+- Powermanagement
+- 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 13. June 2004
+The OMAP Linux Kernel Team
+Dirk Behme <dirk.behme@de.bosch.com>
# Comments in this file are targeted only to the developer, do not
# expect to learn how to build the kernel reading this file.
+# Add custom flags here to avoid conflict with updates
+EXTRAVERSION := $(EXTRAVERSION)-omap1
+
# Do not print "Entering directory ..."
MAKEFLAGS += --no-print-directory
-e s/arm.*/arm/ -e s/sa110/arm/ \
-e s/s390x/s390/ -e s/parisc64/parisc/ \
-e s/ppc.*/powerpc/ )
+SUBARCH := arm
# Cross compiling and selecting different set of gcc/bin-utils
# ---------------------------------------------------------------------------
# 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)
system, but the driver will do nothing.
config LEDS_TIMER
- bool "Timer LED" if (!ARCH_CDB89712 && !ARCH_OMAP) || \
- MACH_OMAP_H2 || MACH_OMAP_PERSEUS2
+ bool "Timer LED" if !ARCH_CDB89712
depends on LEDS
default y if ARCH_EBSA110
help
will overrule the CPU usage LED.
config LEDS_CPU
- bool "CPU usage LED" if (!ARCH_CDB89712 && !ARCH_EBSA110 && \
- !ARCH_OMAP) || MACH_OMAP_H2 || MACH_OMAP_PERSEUS2
+ bool "CPU usage LED" if (!ARCH_CDB89712 && !ARCH_EBSA110)
depends on LEDS
help
If you say Y here, the red LED will be used to give a good real
source "drivers/mmc/Kconfig"
+source "drivers/ssi/Kconfig"
+
+if ARCH_OMAP
+source "drivers/cbus/Kconfig"
+endif
+
endmenu
source "fs/Kconfig"
tune-$(CONFIG_CPU_SA110) :=-mtune=strongarm110
tune-$(CONFIG_CPU_SA1100) :=-mtune=strongarm1100
tune-$(CONFIG_CPU_XSCALE) :=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale
-tune-$(CONFIG_CPU_V6) :=$(call cc-option,-mtune=arm1136j-s,-mtune=strongarm)
+tune-$(CONFIG_CPU_V6) :=$(call cc-option,-mtune=arm1136jf-s,-mtune=arm1136jfs)
ifeq ($(CONFIG_AEABI),y)
CFLAGS_ABI :=-mabi=aapcs -mno-thumb-interwork
--- /dev/null
+Image
+zImage
+uImage
endif
ifeq ($(CONFIG_DEBUG_ICEDCC),y)
-OBJS += ice-dcc.o
+OBJS += ice-dcc.o
+endif
+
+ifeq ($(CONFIG_MACH_OMAP_PERSEUS2),y)
+OBJS += head-omap.o
endif
ifeq ($(CONFIG_CPU_BIG_ENDIAN),y)
--- /dev/null
+/*
+ * linux/arch/arm/boot/compressed/head-omap.S
+ *
+ * OMAP specific tweaks. This is merged into head.S by the linker.
+ *
+ */
+
+#include <linux/config.h>
+#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
add \rb, \rb, #0x00010000 @ Ser1
#endif
.endm
+#elif defined(CONFIG_ARCH_OMAP2)
+ .macro loadsp, rb
+ mov \rb, #0x48000000 @ physical base address
+ add \rb, \rb, #0x0006a000
+#ifdef CONFIG_OMAP_LL_DEBUG_UART2
+ add \rb, \rb, #0x00002000
+#endif
+#ifdef CONFIG_OMAP_LL_DEBUG_UART3
+ add \rb, \rb, #0x00004000
+#endif
+ .endm
+ .macro writeb, rb
+ strb \rb, [r3]
+ .endm
#elif defined(CONFIG_ARCH_IOP331)
.macro loadsp, rb
mov \rb, #0xff000000
--- /dev/null
+#
+# 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
--- /dev/null
+#
+# 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
--- /dev/null
+#
+# 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
--- /dev/null
+#
+# 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
--- /dev/null
+#
+# 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
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.14
-# Wed Nov 9 18:53:40 2005
+# Linux kernel version: 2.6.15-rc1-omap1
+# Mon Nov 14 16:08:57 2005
#
CONFIG_ARM=y
CONFIG_MMU=y
CONFIG_EXPERIMENTAL=y
CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
-CONFIG_LOCK_KERNEL=y
CONFIG_INIT_ENV_ARG_LIMIT=32
#
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
# 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=y
-# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_DEBUG=y
CONFIG_OMAP_MUX_WARNINGS=y
-# CONFIG_OMAP_MPU_TIMER is not set
-CONFIG_OMAP_32K_TIMER=y
-CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
# CONFIG_OMAP_DM_TIMER is not set
CONFIG_OMAP_LL_DEBUG_UART1=y
# CONFIG_OMAP_LL_DEBUG_UART2 is not set
#
# CONFIG_OMAP_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
+# CONFIG_OMAP_DSP is not set
#
# Processor Type
#
# Kernel Features
#
-CONFIG_PREEMPT=y
-CONFIG_NO_IDLE_HZ=y
+# 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_FLAT_NODE_MEM_MAP=y
# CONFIG_SPARSEMEM_STATIC is not set
CONFIG_SPLIT_PTLOCK_CPUS=4096
-# CONFIG_LEDS is not set
+CONFIG_LEDS=y
+# CONFIG_LEDS_TIMER is not set
+# CONFIG_LEDS_CPU is not set
CONFIG_ALIGNMENT_TRAP=y
#
#
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="mem=32M console=ttyS0,115200n8 root=0801 ro init=/bin/sh"
+CONFIG_CMDLINE="mem=32M console=ttyS0,115200n8 root=/dev/ram0 rw initrd=0x10600000,8M ramdisk_size=8192"
# CONFIG_XIP_KERNEL is not set
#
# CPU Frequency scaling
#
-CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_TABLE=y
-# CONFIG_CPU_FREQ_DEBUG is not set
-CONFIG_CPU_FREQ_STAT=y
-# CONFIG_CPU_FREQ_STAT_DETAILS is not set
-# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
-CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
-# CONFIG_CPU_FREQ_GOV_PERFORMANCE is not set
-# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
-CONFIG_CPU_FREQ_GOV_USERSPACE=y
-# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
-# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+# CONFIG_CPU_FREQ is not set
#
# Floating point emulation
#
# Power management options
#
-CONFIG_PM=y
-# CONFIG_APM is not set
+# CONFIG_PM is not set
#
# Networking
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
+CONFIG_DEBUG_DRIVER=y
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
#
# Memory Technology Devices (MTD)
#
-# CONFIG_MTD is not set
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=3
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+
+#
+# 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_OMAP_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_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 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_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
-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_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
-
-#
-# 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
+# CONFIG_SCSI is not set
#
# Multi-device support (RAID and LVM)
# Watchdog Device Drivers
#
# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+# CONFIG_OMAP_WATCHDOG is not set
+# CONFIG_OMAP_RNG is not set
# CONFIG_NVRAM is not set
# CONFIG_RTC is not set
+CONFIG_OMAP_RTC=y
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
#
# 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_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=y
+CONFIG_TPS65010=y
+# CONFIG_SENSORS_TLV320AIC23 is not set
+# 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
#
# 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
#
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
#
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
-# CONFIG_FONT_RL is not set
#
# Logo configuration
#
# Sound
#
-CONFIG_SOUND=y
+# CONFIG_SOUND is not set
#
-# Advanced Linux Sound Architecture
+# USB support
#
-# CONFIG_SND is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
#
-# Open Sound System
+# Miscellaneous USB options
#
-CONFIG_SOUND_PRIME=y
-# CONFIG_OBSOLETE_OSS_DRIVER is not set
-# CONFIG_SOUND_MSNDCLAS is not set
-# CONFIG_SOUND_MSNDPIN is not set
-# CONFIG_SOUND_OSS is not set
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
+CONFIG_USB_OTG_WHITELIST=y
#
-# USB support
+# USB Host Controller Drivers
#
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
-# CONFIG_USB is not set
+# 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_ACM is not set
+# CONFIG_USB_PRINTER is not set
#
# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
#
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+# CONFIG_USB_STORAGE is not set
+
+#
+# USB Input Devices
+#
+# CONFIG_USB_HID is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_ITMTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+
+#
+# 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 is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_LD is not set
+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 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 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_MMC is not set
+#
+# Synchronous Serial Interfaces (SSI)
+#
+CONFIG_OMAP_UWIRE=y
+# CONFIG_OMAP_TSC2101 is not set
+
#
# File systems
#
# 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=2
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
CONFIG_CRAMFS=y
# CONFIG_VXFS_FS is not set
# CONFIG_HPFS_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_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
# Kernel hacking
#
# CONFIG_PRINTK_TIME is not set
-# CONFIG_DEBUG_KERNEL is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_MAGIC_SYSRQ is not set
CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
CONFIG_FRAME_POINTER=y
-# CONFIG_DEBUG_USER is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_LL is not set
#
# Security options
#
# 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
+# CONFIG_CRYPTO is not set
#
# Hardware crypto devices
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.14-rc4-omap1
+# Tue Oct 18 17:58:27 2005
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+# CONFIG_OMAP_DM_TIMER is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+# CONFIG_ARCH_OMAP15XX is not set
+CONFIG_ARCH_OMAP16XX=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_OMAP_H2 is not set
+CONFIG_MACH_OMAP_H3=y
+# CONFIG_MACH_OMAP_OSK is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
+# CONFIG_OMAP_ARM_216MHZ is not set
+# CONFIG_OMAP_ARM_192MHZ is not set
+CONFIG_OMAP_ARM_168MHZ=y
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+# CONFIG_OMAP_DSP is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+
+#
+# Bus support
+#
+CONFIG_ISA_DMA_API=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_LEDS=y
+# CONFIG_LEDS_TIMER is not set
+# CONFIG_LEDS_CPU is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x10C08000
+CONFIG_ZBOOT_ROM_BSS=0x10200000
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_CMDLINE="mem=32M console=ttyS0,115200n8 initrd=0x10A00000,8M root=/dev/ram0 rw ip=dhcp devfs=mount"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM 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=y
+
+#
+# IrDA protocols
+#
+# CONFIG_IRLAN is not set
+# CONFIG_IRNET is not set
+# CONFIG_IRCOMM is not set
+# CONFIG_IRDA_ULTRA is not set
+
+#
+# IrDA options
+#
+# CONFIG_IRDA_CACHE_LAST_LSAP is not set
+# CONFIG_IRDA_FAST_RR is not set
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+# CONFIG_IRTTY_SIR is not set
+
+#
+# Dongle support
+#
+
+#
+# Old SIR device drivers
+#
+# CONFIG_IRPORT_SIR is not set
+
+#
+# Old Serial dongle support
+#
+
+#
+# FIR device drivers
+#
+# CONFIG_USB_IRDA is not set
+# CONFIG_SIGMATEL_FIR is not set
+# CONFIG_NSC_FIR is not set
+# CONFIG_WINBOND_FIR is not set
+CONFIG_OMAP1610_IR=y
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+# CONFIG_VIA_FIR is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPPOE is not set
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+# CONFIG_SLIP_SMART is not set
+# CONFIG_SLIP_MODE_SLIP6 is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+# CONFIG_OMAP_WATCHDOG is not set
+# CONFIG_OMAP_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_OMAP_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+CONFIG_I2C_OMAP=y
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+CONFIG_ISP1301_OMAP=m
+CONFIG_TPS65010=y
+# CONFIG_SENSORS_TLV320AIC23 is not set
+CONFIG_GPIOEXPANDER_OMAP=y
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_OVCAMCHIP is not set
+# CONFIG_VIDEO_OMAP_CAMERA is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_MAESTRO is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+CONFIG_FB_OMAP_LCDC_INTERNAL=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=y
+# CONFIG_SOUND_OMAP is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_TVMIXER is not set
+# CONFIG_SOUND_AD1980 is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
+# CONFIG_USB_BLUETOOTH_TTY is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+# CONFIG_USB_STORAGE is not set
+
+#
+# USB Input Devices
+#
+# CONFIG_USB_HID is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_ITMTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_PWC is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_LD is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+# CONFIG_MMC_BLOCK_BROKEN_RFD is not set
+# CONFIG_MMC_BULKTRANSFER is not set
+CONFIG_MMC_OMAP=y
+# CONFIG_MMC_WBSD is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+CONFIG_OMAP_UWIRE=y
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_ROMFS_FS=y
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_LL is not set
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.16-rc4-omap1
+# Wed Feb 22 02:25:55 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 is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_UID16=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_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
+CONFIG_OBSOLETE_INTERMODULE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_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_OMAP1 is not set
+CONFIG_ARCH_OMAP2=y
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_BOOT_TAG=y
+# CONFIG_OMAP_BOOT_REASON is not set
+# CONFIG_OMAP_COMPONENT_VERSION is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+CONFIG_OMAP_MUX_DEBUG=y
+CONFIG_OMAP_MUX_WARNINGS=y
+# CONFIG_OMAP_STI is not set
+CONFIG_OMAP_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_MACH_OMAP_GENERIC=y
+
+#
+# OMAP Core Type
+#
+CONFIG_ARCH_OMAP24XX=y
+CONFIG_ARCH_OMAP2420=y
+
+#
+# OMAP Board Type
+#
+CONFIG_MACH_OMAP_H4=y
+# CONFIG_MACH_OMAP_APOLLON is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_V6=y
+# CONFIG_CPU_32v6K is not set
+CONFIG_CPU_32v6=y
+CONFIG_CPU_ABRT_EV6=y
+CONFIG_CPU_CACHE_V6=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V6=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+
+#
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/ram0 rw console=ttyS0,115200n8 initrd=0x80600000,8M ramdisk_size=8192"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_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
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_IRDA=y
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=y
+CONFIG_IRCOMM=y
+# CONFIG_IRDA_ULTRA is not set
+
+#
+# IrDA options
+#
+# CONFIG_IRDA_CACHE_LAST_LSAP is not set
+# CONFIG_IRDA_FAST_RR is not set
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+# CONFIG_IRTTY_SIR is not set
+
+#
+# Dongle support
+#
+
+#
+# Old SIR device drivers
+#
+# CONFIG_IRPORT_SIR is not set
+
+#
+# Old Serial dongle support
+#
+
+#
+# FIR device drivers
+#
+CONFIG_OMAP_IR=y
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_OMAP_NOR=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_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 is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+# CONFIG_MTD_ONENAND_SYNC_READ is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+# CONFIG_OMAP_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_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_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+CONFIG_GPIOEXPANDER_OMAP=y
+CONFIG_MENELAUS=y
+# 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 is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# 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 is not set
+# CONFIG_FB_OMAP_LCD_LPH8923 is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BROKEN_RFD=y
+CONFIG_MMC_BULKTRANSFER=y
+CONFIG_MMC_OMAP=y
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+# CONFIG_OMAP_TSC2101 is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_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 is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_ERRORS is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
--- /dev/null
+#
+# 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
--- /dev/null
+#
+# 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
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.14-rc4-omap1
+# Tue Oct 18 17:56: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_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=y
+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=y
+# 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 is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+# CONFIG_OMAP_DM_TIMER is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+# CONFIG_ARCH_OMAP15XX is not set
+CONFIG_ARCH_OMAP16XX=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_OMAP_H2 is not set
+# CONFIG_MACH_OMAP_H3 is not set
+CONFIG_MACH_OMAP_OSK=y
+# CONFIG_OMAP_OSK_MISTRAL 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 is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+
+#
+# Bus support
+#
+CONFIG_ISA_DMA_API=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+CONFIG_PCCARD=y
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=y
+CONFIG_PCMCIA_LOAD_CIS=y
+CONFIG_PCMCIA_IOCTL=y
+
+#
+# PC-card bridges
+#
+CONFIG_OMAP_CF=y
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_NO_IDLE_HZ=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_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,115200 initrd=0x10400000,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=y
+# CONFIG_APM 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=y
+
+#
+# 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 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
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=m
+CONFIG_BLK_DEV_IDE=m
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECS=m
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_IDE_GENERIC is not set
+# CONFIG_IDE_ARM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD 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
+
+#
+# PCMCIA network device support
+#
+# CONFIG_NET_PCMCIA 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 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_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=y
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_CS is not set
+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
+#
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+
+#
+# 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_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=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
+
+#
+# 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=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 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 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 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=y
+
+#
+# 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_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 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=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=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+# 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=m
+# 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 is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
--- /dev/null
+#
+# 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
--- /dev/null
+#
+# 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
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
}
-
-/*
- * These must never be empty
- * If you have to comment these two assert statements out, your
- * binutils is too old (for other reasons as well)
- */
-ASSERT((__proc_info_end - __proc_info_begin), "missing CPU support")
-ASSERT((__arch_info_end - __arch_info_begin), "no machine record defined")
config MACH_OMAP_H3
bool "TI H3 Support"
depends on ARCH_OMAP1 && ARCH_OMAP16XX
+ select GPIOEXPANDER_OMAP
help
TI OMAP 1710 H3 board support. Say Y here if you have such
a board.
Support for Voiceblue GSM/VoIP gateway. Say Y here if you have
such a board.
-config MACH_NETSTAR
- bool "NetStar"
- depends on ARCH_OMAP1 && ARCH_OMAP15XX
- help
- Support for NetStar PBX. Say Y here if you have such a board.
-
config MACH_OMAP_PALMTE
bool "Palm Tungsten E"
depends on ARCH_OMAP1 && ARCH_OMAP15XX
informations.
Say Y here if you have such a PDA, say NO otherwise.
+config MACH_NOKIA770
+ bool "Nokia 770"
+ depends on ARCH_OMAP1 && ARCH_OMAP16XX
+ help
+ Support for the Nokia 770 Internet Tablet. Say Y here if you
+ have such a device.
+
config MACH_OMAP_GENERIC
bool "Generic OMAP board"
depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX)
help
Enable 30MHz clock for OMAP CPU. If unsure, say N.
+source "arch/arm/plat-omap/dsp/Kconfig"
+
#
# Common support
-obj-y := io.o id.o clock.o irq.o time.o mux.o serial.o devices.o
+obj-y := io.o id.o clock.o irq.o mux.o serial.o devices.o
+
+obj-$(CONFIG_OMAP_MPU_TIMER) += time.o
+
+# Power Management
+obj-$(CONFIG_PM) += pm.o sleep.o
+
led-y := leds.o
# Specific board support
obj-$(CONFIG_MACH_OMAP_OSK) += board-osk.o
obj-$(CONFIG_MACH_OMAP_H3) += board-h3.o
obj-$(CONFIG_MACH_VOICEBLUE) += board-voiceblue.o
-obj-$(CONFIG_MACH_NETSTAR) += board-netstar.o
obj-$(CONFIG_MACH_OMAP_PALMTE) += board-palmte.o
+obj-$(CONFIG_MACH_NOKIA770) += board-nokia770.o
ifeq ($(CONFIG_ARCH_OMAP15XX),y)
# Innovator-1510 FPGA
static void __init omap_generic_init(void)
{
#ifdef CONFIG_ARCH_OMAP15XX
- if (cpu_is_omap1510()) {
+ if (cpu_is_omap15xx()) {
generic_config[0].data = &generic1510_usb_config;
}
#endif
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
+#include <linux/input.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
#include <asm/arch/gpio.h>
#include <asm/arch/mux.h>
#include <asm/arch/tc.h>
+#include <asm/arch/irda.h>
#include <asm/arch/usb.h>
+#include <asm/arch/keypad.h>
+#include <asm/arch/dma.h>
#include <asm/arch/common.h>
extern int omap_gpio_init(void);
-static struct mtd_partition h2_partitions[] = {
+static int h2_keymap[] = {
+ KEY(0, 0, KEY_LEFT),
+ KEY(0, 1, KEY_RIGHT),
+ KEY(0, 2, KEY_3),
+ KEY(0, 3, KEY_F10),
+ KEY(0, 4, KEY_F5),
+ KEY(0, 5, KEY_9),
+ KEY(1, 0, KEY_DOWN),
+ KEY(1, 1, KEY_UP),
+ KEY(1, 2, KEY_2),
+ KEY(1, 3, KEY_F9),
+ KEY(1, 4, KEY_F7),
+ KEY(1, 5, KEY_0),
+ KEY(2, 0, KEY_ENTER),
+ KEY(2, 1, KEY_6),
+ KEY(2, 2, KEY_1),
+ KEY(2, 3, KEY_F2),
+ KEY(2, 4, KEY_F6),
+ KEY(2, 5, KEY_HOME),
+ KEY(3, 0, KEY_8),
+ KEY(3, 1, KEY_5),
+ KEY(3, 2, KEY_F12),
+ KEY(3, 3, KEY_F3),
+ KEY(3, 4, KEY_F8),
+ KEY(3, 5, KEY_END),
+ KEY(4, 0, KEY_7),
+ KEY(4, 1, KEY_4),
+ KEY(4, 2, KEY_F11),
+ KEY(4, 3, KEY_F1),
+ KEY(4, 4, KEY_F4),
+ KEY(4, 5, KEY_ESC),
+ KEY(5, 0, KEY_F13),
+ KEY(5, 1, KEY_F14),
+ KEY(5, 2, KEY_F15),
+ KEY(5, 3, KEY_F16),
+ KEY(5, 4, KEY_SLEEP),
+ 0
+};
+
+static struct mtd_partition h2_nor_partitions[] = {
/* bootloader (U-Boot, etc) in first sector */
{
.name = "bootloader",
}
};
-static struct flash_platform_data h2_flash_data = {
+static struct flash_platform_data h2_nor_data = {
.map_name = "cfi_probe",
.width = 2,
- .parts = h2_partitions,
- .nr_parts = ARRAY_SIZE(h2_partitions),
+ .parts = h2_nor_partitions,
+ .nr_parts = ARRAY_SIZE(h2_nor_partitions),
};
-static struct resource h2_flash_resource = {
+static struct resource h2_nor_resource = {
/* This is on CS3, wherever it's mapped */
.flags = IORESOURCE_MEM,
};
-static struct platform_device h2_flash_device = {
+static struct platform_device h2_nor_device = {
.name = "omapflash",
.id = 0,
.dev = {
- .platform_data = &h2_flash_data,
+ .platform_data = &h2_nor_data,
},
.num_resources = 1,
- .resource = &h2_flash_resource,
+ .resource = &h2_nor_resource,
+};
+
+static struct mtd_partition h2_nand_partitions[] = {
+#if 0
+ /* REVISIT: enable these partitions if you make NAND BOOT
+ * work on your H2 (rev C or newer); published versions of
+ * x-load only support P2 and H3.
+ */
+ {
+ .name = "xloader",
+ .offset = 0,
+ .size = 64 * 1024,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ {
+ .name = "bootloader",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 256 * 1024,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ {
+ .name = "params",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 192 * 1024,
+ },
+ {
+ .name = "kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 2 * SZ_1M,
+ },
+#endif
+ {
+ .name = "filesystem",
+ .size = MTDPART_SIZ_FULL,
+ .offset = MTDPART_OFS_APPEND,
+ },
+};
+
+/* dip switches control NAND chip access: 8 bit, 16 bit, or neither */
+static struct nand_platform_data h2_nand_data = {
+ .options = NAND_SAMSUNG_LP_OPTIONS,
+ .parts = h2_nand_partitions,
+ .nr_parts = ARRAY_SIZE(h2_nand_partitions),
+};
+
+static struct resource h2_nand_resource = {
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device h2_nand_device = {
+ .name = "omapnand",
+ .id = 0,
+ .dev = {
+ .platform_data = &h2_nand_data,
+ },
+ .num_resources = 1,
+ .resource = &h2_nand_resource,
};
static struct resource h2_smc91x_resources[] = {
.resource = h2_smc91x_resources,
};
+static struct resource h2_kp_resources[] = {
+ [0] = {
+ .start = INT_KEYBOARD,
+ .end = INT_KEYBOARD,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct omap_kp_platform_data h2_kp_data = {
+ .rows = 8,
+ .cols = 8,
+ .keymap = h2_keymap,
+ .rep = 1,
+};
+
+static struct platform_device h2_kp_device = {
+ .name = "omap-keypad",
+ .id = -1,
+ .dev = {
+ .platform_data = &h2_kp_data,
+ },
+ .num_resources = ARRAY_SIZE(h2_kp_resources),
+ .resource = h2_kp_resources,
+};
+
+#define H2_IRDA_FIRSEL_GPIO_PIN 17
+
+#if defined(CONFIG_OMAP_IR) || defined(CONFIG_OMAP_IR_MODULE)
+static int h2_transceiver_mode(struct device *dev, int state)
+{
+ if (state & IR_SIRMODE)
+ omap_set_gpio_dataout(H2_IRDA_FIRSEL_GPIO_PIN, 0);
+ else /* MIR/FIR */
+ omap_set_gpio_dataout(H2_IRDA_FIRSEL_GPIO_PIN, 1);
+
+ return 0;
+}
+#endif
+
+static struct omap_irda_config h2_irda_data = {
+ .transceiver_cap = IR_SIRMODE | IR_MIRMODE | IR_FIRMODE,
+ .rx_channel = OMAP_DMA_UART3_RX,
+ .tx_channel = OMAP_DMA_UART3_TX,
+ .dest_start = UART3_THR,
+ .src_start = UART3_RHR,
+ .tx_trigger = 0,
+ .rx_trigger = 0,
+};
+
+static struct resource h2_irda_resources[] = {
+ [0] = {
+ .start = INT_UART3,
+ .end = INT_UART3,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+static struct platform_device h2_irda_device = {
+ .name = "omapirda",
+ .id = 0,
+ .dev = {
+ .platform_data = &h2_irda_data,
+ },
+ .num_resources = ARRAY_SIZE(h2_irda_resources),
+ .resource = h2_irda_resources,
+};
+
+static struct platform_device h2_lcd_device = {
+ .name = "lcd_h2",
+ .id = -1,
+};
+
static struct platform_device *h2_devices[] __initdata = {
- &h2_flash_device,
+ &h2_nor_device,
+ &h2_nand_device,
&h2_smc91x_device,
+ &h2_irda_device,
+ &h2_kp_device,
+ &h2_lcd_device,
};
static void __init h2_init_smc91x(void)
};
static struct omap_lcd_config h2_lcd_config __initdata = {
- .panel_name = "h2",
.ctrl_name = "internal",
};
{ OMAP_TAG_LCD, &h2_lcd_config },
};
+#define H2_NAND_RB_GPIO_PIN 62
+
+static int h2_nand_dev_ready(struct nand_platform_data *data)
+{
+ return omap_get_gpio_datain(H2_NAND_RB_GPIO_PIN);
+}
+
static void __init h2_init(void)
{
- /* NOTE: revC boards support NAND-boot, which can put NOR on CS2B
- * and NAND (either 16bit or 8bit) on CS3.
+ /* Here we assume the NOR boot config: NOR on CS3 (possibly swapped
+ * to address 0 by a dip switch), NAND on CS2B. The NAND driver will
+ * notice whether a NAND chip is enabled at probe time.
+ *
+ * FIXME revC boards (and H3) support NAND-boot, with a dip switch to
+ * put NOR on CS2B and NAND (which on H2 may be 16bit) on CS3. Try
+ * detecting that in code here, to avoid probing every possible flash
+ * configuration...
*/
- h2_flash_resource.end = h2_flash_resource.start = omap_cs3_phys();
- h2_flash_resource.end += SZ_32M - 1;
+ h2_nor_resource.end = h2_nor_resource.start = omap_cs3_phys();
+ h2_nor_resource.end += SZ_32M - 1;
+
+ 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;
+
+ omap_cfg_reg(L3_1610_FLASH_CS2B_OE);
+ omap_cfg_reg(M8_1610_FLASH_CS2B_WE);
/* MMC: card detect and WP */
// omap_cfg_reg(U19_ARMIO1); /* CD */
omap_cfg_reg(BALLOUT_V8_ARMIO3); /* WP */
+ /* Irda */
+#if defined(CONFIG_OMAP_IR) || defined(CONFIG_OMAP_IR_MODULE)
+ omap_writel(omap_readl(FUNC_MUX_CTRL_A) | 7, FUNC_MUX_CTRL_A);
+ if (!(omap_request_gpio(H2_IRDA_FIRSEL_GPIO_PIN))) {
+ omap_set_gpio_direction(H2_IRDA_FIRSEL_GPIO_PIN, 0);
+ h2_irda_data.transceiver_mode = h2_transceiver_mode;
+ }
+#endif
+
platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices));
omap_board_config = h2_config;
omap_board_config_size = ARRAY_SIZE(h2_config);
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/errno.h>
+#include <linux/workqueue.h>
#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
+#include <linux/input.h>
#include <asm/setup.h>
#include <asm/page.h>
#include <asm/mach/map.h>
#include <asm/arch/gpio.h>
+#include <asm/arch/gpioexpander.h>
#include <asm/arch/irqs.h>
#include <asm/arch/mux.h>
#include <asm/arch/tc.h>
+#include <asm/arch/irda.h>
#include <asm/arch/usb.h>
+#include <asm/arch/keypad.h>
+#include <asm/arch/dma.h>
#include <asm/arch/common.h>
extern int omap_gpio_init(void);
-static struct mtd_partition h3_partitions[] = {
+static int h3_keymap[] = {
+ KEY(0, 0, KEY_LEFT),
+ KEY(0, 1, KEY_RIGHT),
+ KEY(0, 2, KEY_3),
+ KEY(0, 3, KEY_F10),
+ KEY(0, 4, KEY_F5),
+ KEY(0, 5, KEY_9),
+ KEY(1, 0, KEY_DOWN),
+ KEY(1, 1, KEY_UP),
+ KEY(1, 2, KEY_2),
+ KEY(1, 3, KEY_F9),
+ KEY(1, 4, KEY_F7),
+ KEY(1, 5, KEY_0),
+ KEY(2, 0, KEY_ENTER),
+ KEY(2, 1, KEY_6),
+ KEY(2, 2, KEY_1),
+ KEY(2, 3, KEY_F2),
+ KEY(2, 4, KEY_F6),
+ KEY(2, 5, KEY_HOME),
+ KEY(3, 0, KEY_8),
+ KEY(3, 1, KEY_5),
+ KEY(3, 2, KEY_F12),
+ KEY(3, 3, KEY_F3),
+ KEY(3, 4, KEY_F8),
+ KEY(3, 5, KEY_END),
+ KEY(4, 0, KEY_7),
+ KEY(4, 1, KEY_4),
+ KEY(4, 2, KEY_F11),
+ KEY(4, 3, KEY_F1),
+ KEY(4, 4, KEY_F4),
+ KEY(4, 5, KEY_ESC),
+ KEY(5, 0, KEY_F13),
+ KEY(5, 1, KEY_F14),
+ KEY(5, 2, KEY_F15),
+ KEY(5, 3, KEY_F16),
+ KEY(5, 4, KEY_SLEEP),
+ 0
+};
+
+
+static struct mtd_partition nor_partitions[] = {
/* bootloader (U-Boot, etc) in first sector */
{
.name = "bootloader",
}
};
-static struct flash_platform_data h3_flash_data = {
+static struct flash_platform_data nor_data = {
.map_name = "cfi_probe",
.width = 2,
- .parts = h3_partitions,
- .nr_parts = ARRAY_SIZE(h3_partitions),
+ .parts = nor_partitions,
+ .nr_parts = ARRAY_SIZE(nor_partitions),
};
-static struct resource h3_flash_resource = {
+static struct resource nor_resource = {
/* This is on CS3, wherever it's mapped */
.flags = IORESOURCE_MEM,
};
-static struct platform_device flash_device = {
+static struct platform_device nor_device = {
.name = "omapflash",
.id = 0,
.dev = {
- .platform_data = &h3_flash_data,
+ .platform_data = &nor_data,
+ },
+ .num_resources = 1,
+ .resource = &nor_resource,
+};
+
+static struct mtd_partition nand_partitions[] = {
+#if 0
+ /* REVISIT: enable these partitions if you make NAND BOOT work */
+ {
+ .name = "xloader",
+ .offset = 0,
+ .size = 64 * 1024,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ {
+ .name = "bootloader",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 256 * 1024,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ {
+ .name = "params",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 192 * 1024,
+ },
+ {
+ .name = "kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 2 * SZ_1M,
+ },
+#endif
+ {
+ .name = "filesystem",
+ .size = MTDPART_SIZ_FULL,
+ .offset = MTDPART_OFS_APPEND,
+ },
+};
+
+/* dip switches control NAND chip access: 8 bit, 16 bit, or neither */
+static struct nand_platform_data nand_data = {
+ .options = NAND_SAMSUNG_LP_OPTIONS,
+ .parts = nand_partitions,
+ .nr_parts = ARRAY_SIZE(nand_partitions),
+};
+
+static struct resource nand_resource = {
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device nand_device = {
+ .name = "omapnand",
+ .id = 0,
+ .dev = {
+ .platform_data = &nand_data,
},
.num_resources = 1,
- .resource = &h3_flash_resource,
+ .resource = &nand_resource,
};
static struct resource smc91x_resources[] = {
.resource = intlat_resources,
};
+static struct resource h3_kp_resources[] = {
+ [0] = {
+ .start = INT_KEYBOARD,
+ .end = INT_KEYBOARD,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct omap_kp_platform_data h3_kp_data = {
+ .rows = 8,
+ .cols = 8,
+ .keymap = h3_keymap,
+ .rep = 1,
+};
+
+static struct platform_device h3_kp_device = {
+ .name = "omap-keypad",
+ .id = -1,
+ .dev = {
+ .platform_data = &h3_kp_data,
+ },
+ .num_resources = ARRAY_SIZE(h3_kp_resources),
+ .resource = h3_kp_resources,
+};
+
+
+/* Select between the IrDA and aGPS module
+ */
+static int h3_select_irda(struct device *dev, int state)
+{
+ unsigned char expa;
+ int err = 0;
+
+ if ((err = read_gpio_expa(&expa, 0x26))) {
+ printk(KERN_ERR "Error reading from I/O EXPANDER \n");
+ return err;
+ }
+
+ /* 'P6' enable/disable IRDA_TX and IRDA_RX */
+ if (state & IR_SEL) { /* IrDA */
+ if ((err = write_gpio_expa(expa | 0x40, 0x26))) {
+ printk(KERN_ERR "Error writing to I/O EXPANDER \n");
+ return err;
+ }
+ } else {
+ if ((err = write_gpio_expa(expa & ~0x40, 0x26))) {
+ printk(KERN_ERR "Error writing to I/O EXPANDER \n");
+ return err;
+ }
+ }
+ return err;
+}
+
+static void set_trans_mode(void *data)
+{
+ int *mode = data;
+ unsigned char expa;
+ int err = 0;
+
+ if ((err = read_gpio_expa(&expa, 0x27)) != 0) {
+ printk(KERN_ERR "Error reading from I/O expander\n");
+ }
+
+ expa &= ~0x03;
+
+ if (*mode & IR_SIRMODE) {
+ expa |= 0x01;
+ } else { /* MIR/FIR */
+ expa |= 0x03;
+ }
+
+ if ((err = write_gpio_expa(expa, 0x27)) != 0) {
+ printk(KERN_ERR "Error writing to I/O expander\n");
+ }
+}
+
+static int h3_transceiver_mode(struct device *dev, int mode)
+{
+ struct omap_irda_config *irda_config = dev->platform_data;
+
+ cancel_delayed_work(&irda_config->gpio_expa);
+ PREPARE_WORK(&irda_config->gpio_expa, set_trans_mode, &mode);
+ schedule_work(&irda_config->gpio_expa);
+
+ return 0;
+}
+
+static struct omap_irda_config h3_irda_data = {
+ .transceiver_cap = IR_SIRMODE | IR_MIRMODE | IR_FIRMODE,
+ .transceiver_mode = h3_transceiver_mode,
+ .select_irda = h3_select_irda,
+ .rx_channel = OMAP_DMA_UART3_RX,
+ .tx_channel = OMAP_DMA_UART3_TX,
+ .dest_start = UART3_THR,
+ .src_start = UART3_RHR,
+ .tx_trigger = 0,
+ .rx_trigger = 0,
+};
+
+static struct resource h3_irda_resources[] = {
+ [0] = {
+ .start = INT_UART3,
+ .end = INT_UART3,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device h3_irda_device = {
+ .name = "omapirda",
+ .id = 0,
+ .dev = {
+ .platform_data = &h3_irda_data,
+ },
+ .num_resources = ARRAY_SIZE(h3_irda_resources),
+ .resource = h3_irda_resources,
+};
+
+static struct platform_device h3_lcd_device = {
+ .name = "lcd_h3",
+ .id = -1,
+};
+
static struct platform_device *devices[] __initdata = {
- &flash_device,
+ &nor_device,
+ &nand_device,
&smc91x_device,
&intlat_device,
+ &h3_irda_device,
+ &h3_kp_device,
+ &h3_lcd_device,
};
static struct omap_usb_config h3_usb_config __initdata = {
};
static struct omap_lcd_config h3_lcd_config __initdata = {
- .panel_name = "h3",
.ctrl_name = "internal",
};
{ OMAP_TAG_LCD, &h3_lcd_config },
};
+#define H3_NAND_RB_GPIO_PIN 10
+
+static int nand_dev_ready(struct nand_platform_data *data)
+{
+ return omap_get_gpio_datain(H3_NAND_RB_GPIO_PIN);
+}
+
static void __init h3_init(void)
{
- h3_flash_resource.end = h3_flash_resource.start = omap_cs3_phys();
- h3_flash_resource.end += OMAP_CS3_SIZE - 1;
- (void) platform_add_devices(devices, ARRAY_SIZE(devices));
+ /* Here we assume the NOR boot config: NOR on CS3 (possibly swapped
+ * to address 0 by a dip switch), NAND on CS2B. The NAND driver will
+ * notice whether a NAND chip is enabled at probe time.
+ *
+ * H3 support NAND-boot, with a dip switch to put NOR on CS2B and NAND
+ * (which on H2 may be 16bit) on CS3. Try detecting that in code here,
+ * to avoid probing every possible flash configuration...
+ */
+ nor_resource.end = nor_resource.start = omap_cs3_phys();
+ nor_resource.end += SZ_32M - 1;
+
+ nand_resource.end = nand_resource.start = OMAP_CS2B_PHYS;
+ nand_resource.end += SZ_4K - 1;
+ if (!(omap_request_gpio(H3_NAND_RB_GPIO_PIN)))
+ nand_data.dev_ready = nand_dev_ready;
+
+ /* GPIO10 Func_MUX_CTRL reg bit 29:27, Configure V2 to mode1 as GPIO */
+ /* GPIO10 pullup/down register, Enable pullup on GPIO10 */
+ omap_cfg_reg(V2_1710_GPIO10);
+
+ platform_add_devices(devices, ARRAY_SIZE(devices));
omap_board_config = h3_config;
omap_board_config_size = ARRAY_SIZE(h3_config);
omap_serial_init();
#include <linux/delay.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#include <linux/input.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
#include <asm/arch/gpio.h>
#include <asm/arch/tc.h>
#include <asm/arch/usb.h>
+#include <asm/arch/keypad.h>
#include <asm/arch/common.h>
+static int innovator_keymap[] = {
+ KEY(0, 0, KEY_F1),
+ KEY(0, 3, KEY_DOWN),
+ KEY(1, 1, KEY_F2),
+ KEY(1, 2, KEY_RIGHT),
+ KEY(2, 0, KEY_F3),
+ KEY(2, 1, KEY_F4),
+ KEY(2, 2, KEY_UP),
+ KEY(3, 2, KEY_ENTER),
+ KEY(3, 3, KEY_LEFT),
+ 0
+};
+
static struct mtd_partition innovator_partitions[] = {
/* bootloader (U-Boot, etc) in first sector */
{
.resource = &innovator_flash_resource,
};
+static struct resource innovator_kp_resources[] = {
+ [0] = {
+ .start = INT_KEYBOARD,
+ .end = INT_KEYBOARD,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct omap_kp_platform_data innovator_kp_data = {
+ .rows = 8,
+ .cols = 8,
+ .keymap = innovator_keymap,
+};
+
+static struct platform_device innovator_kp_device = {
+ .name = "omap-keypad",
+ .id = -1,
+ .dev = {
+ .platform_data = &innovator_kp_data,
+ },
+ .num_resources = ARRAY_SIZE(innovator_kp_resources),
+ .resource = innovator_kp_resources,
+};
+
+
#ifdef CONFIG_ARCH_OMAP15XX
/* Only FPGA needs to be mapped here. All others are done with ioremap */
.resource = innovator1510_smc91x_resources,
};
+static struct platform_device innovator1510_lcd_device = {
+ .name = "lcd_inn1510",
+ .id = -1,
+};
+
static struct platform_device *innovator1510_devices[] __initdata = {
&innovator_flash_device,
&innovator1510_smc91x_device,
+ &innovator_kp_device,
+ &innovator1510_lcd_device,
};
#endif /* CONFIG_ARCH_OMAP15XX */
.resource = innovator1610_smc91x_resources,
};
+static struct platform_device innovator1610_lcd_device = {
+ .name = "inn1610_lcd",
+ .id = -1,
+};
+
static struct platform_device *innovator1610_devices[] __initdata = {
&innovator_flash_device,
&innovator1610_smc91x_device,
+ &innovator_kp_device,
+ &innovator1610_lcd_device,
};
#endif /* CONFIG_ARCH_OMAP16XX */
};
static struct omap_lcd_config innovator1510_lcd_config __initdata = {
- .panel_name = "inn1510",
.ctrl_name = "internal",
};
#endif
};
static struct omap_lcd_config innovator1610_lcd_config __initdata = {
- .panel_name = "inn1610",
.ctrl_name = "internal",
};
#endif
+++ /dev/null
-/*
- * Modified from board-generic.c
- *
- * Copyright (C) 2004 2N Telekomunikace, Ladislav Michl <michl@2n.cz>
- *
- * Code for Netstar OMAP board.
- *
- * 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/delay.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-
-#include <asm/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include <asm/arch/gpio.h>
-#include <asm/arch/mux.h>
-#include <asm/arch/usb.h>
-#include <asm/arch/common.h>
-
-extern void __init omap_init_time(void);
-extern int omap_gpio_init(void);
-
-static struct resource netstar_smc91x_resources[] = {
- [0] = {
- .start = OMAP_CS1_PHYS + 0x300,
- .end = OMAP_CS1_PHYS + 0x300 + 16,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = OMAP_GPIO_IRQ(8),
- .end = OMAP_GPIO_IRQ(8),
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device netstar_smc91x_device = {
- .name = "smc91x",
- .id = 0,
- .num_resources = ARRAY_SIZE(netstar_smc91x_resources),
- .resource = netstar_smc91x_resources,
-};
-
-static struct platform_device *netstar_devices[] __initdata = {
- &netstar_smc91x_device,
-};
-
-static struct omap_uart_config netstar_uart_config __initdata = {
- .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
-};
-
-static struct omap_board_config_kernel netstar_config[] = {
- { OMAP_TAG_UART, &netstar_uart_config },
-};
-
-static void __init netstar_init_irq(void)
-{
- omap1_init_common_hw();
- omap_init_irq();
- omap_gpio_init();
-}
-
-static void __init netstar_init(void)
-{
- /* green LED */
- omap_request_gpio(4);
- omap_set_gpio_direction(4, 0);
- /* smc91x reset */
- omap_request_gpio(7);
- omap_set_gpio_direction(7, 0);
- omap_set_gpio_dataout(7, 1);
- udelay(2); /* wait at least 100ns */
- omap_set_gpio_dataout(7, 0);
- mdelay(50); /* 50ms until PHY ready */
- /* smc91x interrupt pin */
- omap_request_gpio(8);
-
- omap_request_gpio(12);
- omap_request_gpio(13);
- omap_request_gpio(14);
- omap_request_gpio(15);
- set_irq_type(OMAP_GPIO_IRQ(12), IRQT_FALLING);
- set_irq_type(OMAP_GPIO_IRQ(13), IRQT_FALLING);
- set_irq_type(OMAP_GPIO_IRQ(14), IRQT_FALLING);
- set_irq_type(OMAP_GPIO_IRQ(15), IRQT_FALLING);
-
- platform_add_devices(netstar_devices, ARRAY_SIZE(netstar_devices));
-
- /* Switch on green LED */
- omap_set_gpio_dataout(4, 0);
- /* Switch off red LED */
- omap_writeb(0x00, OMAP_LPG1_PMR); /* Disable clock */
- omap_writeb(0x80, OMAP_LPG1_LCR);
-
- omap_board_config = netstar_config;
- omap_board_config_size = ARRAY_SIZE(netstar_config);
- omap_serial_init();
-}
-
-static void __init netstar_map_io(void)
-{
- omap1_map_common_io();
-}
-
-#define MACHINE_PANICED 1
-#define MACHINE_REBOOTING 2
-#define MACHINE_REBOOT 4
-static unsigned long machine_state;
-
-static int panic_event(struct notifier_block *this, unsigned long event,
- void *ptr)
-{
- if (test_and_set_bit(MACHINE_PANICED, &machine_state))
- return NOTIFY_DONE;
-
- /* Switch off green LED */
- omap_set_gpio_dataout(4, 1);
- /* Flash red LED */
- omap_writeb(0x78, OMAP_LPG1_LCR);
- omap_writeb(0x01, OMAP_LPG1_PMR); /* Enable clock */
-
- return NOTIFY_DONE;
-}
-
-static struct notifier_block panic_block = {
- .notifier_call = panic_event,
-};
-
-static int __init netstar_late_init(void)
-{
- /* TODO: Setup front panel switch here */
-
- /* Setup panic notifier */
- notifier_chain_register(&panic_notifier_list, &panic_block);
-
- return 0;
-}
-
-postcore_initcall(netstar_late_init);
-
-MACHINE_START(NETSTAR, "NetStar OMAP5910")
- /* Maintainer: Ladislav Michl <michl@2n.cz> */
- .phys_io = 0xfff00000,
- .io_pg_offst = ((0xfef00000) >> 18) & 0xfffc,
- .boot_params = 0x10000100,
- .map_io = netstar_map_io,
- .init_irq = netstar_init_irq,
- .init_machine = netstar_init,
- .timer = &omap_timer,
-MACHINE_END
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap1/board-nokia770.c
+ *
+ * Modified from board-generic.c
+ *
+ * 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/input.h>
+#include <linux/clk.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/usb.h>
+#include <asm/arch/board.h>
+#include <asm/arch/keypad.h>
+#include <asm/arch/common.h>
+#include <asm/arch/dsp_common.h>
+#include <asm/arch/aic23.h>
+#include <asm/arch/gpio.h>
+
+static void __init omap_nokia770_init_irq(void)
+{
+ omap1_init_common_hw();
+ omap_init_irq();
+}
+
+static int nokia770_keymap[] = {
+ KEY(0, 1, GROUP_0 | KEY_UP),
+ KEY(0, 2, GROUP_1 | KEY_F5),
+ KEY(1, 0, GROUP_0 | KEY_LEFT),
+ KEY(1, 1, GROUP_0 | KEY_ENTER),
+ KEY(1, 2, GROUP_0 | KEY_RIGHT),
+ KEY(2, 0, GROUP_1 | KEY_ESC),
+ KEY(2, 1, GROUP_0 | KEY_DOWN),
+ KEY(2, 2, GROUP_1 | KEY_F4),
+ KEY(3, 0, GROUP_2 | KEY_F7),
+ KEY(3, 1, GROUP_2 | KEY_F8),
+ KEY(3, 2, GROUP_2 | KEY_F6),
+ 0
+};
+
+static struct resource nokia770_kp_resources[] = {
+ [0] = {
+ .start = INT_KEYBOARD,
+ .end = INT_KEYBOARD,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct omap_kp_platform_data nokia770_kp_data = {
+ .rows = 8,
+ .cols = 8,
+ .keymap = nokia770_keymap
+};
+
+static struct platform_device nokia770_kp_device = {
+ .name = "omap-keypad",
+ .id = -1,
+ .dev = {
+ .platform_data = &nokia770_kp_data,
+ },
+ .num_resources = ARRAY_SIZE(nokia770_kp_resources),
+ .resource = nokia770_kp_resources,
+};
+
+static struct platform_device *nokia770_devices[] __initdata = {
+ &nokia770_kp_device,
+};
+
+static struct ads7846_platform_data nokia770_ads7846_platform_data __initdata = {
+ .x_max = 0x0fff,
+ .y_max = 0x0fff,
+ .x_plate_ohms = 120,
+ .pressure_max = 200,
+ .debounce_max = 10,
+ .debounce_tol = 3,
+};
+
+static struct spi_board_info nokia770_spi_board_info[] __initdata = {
+ [0] = {
+ .modalias = "lcd_lph8923",
+ .bus_num = 2,
+ .chip_select = 3,
+ .max_speed_hz = 12000000,
+ },
+ [1] = {
+ .modalias = "ads7846",
+ .bus_num = 2,
+ .chip_select = 0,
+ .max_speed_hz = 2500000,
+ .irq = OMAP_GPIO_IRQ(15),
+ .platform_data = &nokia770_ads7846_platform_data,
+ },
+};
+
+
+/* assume no Mini-AB port */
+
+static struct omap_usb_config nokia770_usb_config __initdata = {
+ .otg = 1,
+ .register_host = 1,
+ .register_dev = 1,
+ .hmc_mode = 16,
+ .pins[0] = 6,
+};
+
+static struct omap_mmc_config nokia770_mmc_config __initdata = {
+ .mmc[0] = {
+ .enabled = 0,
+ .wire4 = 0,
+ .wp_pin = -1,
+ .power_pin = -1,
+ .switch_pin = -1,
+ },
+ .mmc[1] = {
+ .enabled = 0,
+ .wire4 = 0,
+ .wp_pin = -1,
+ .power_pin = -1,
+ .switch_pin = -1,
+ },
+};
+
+static struct omap_board_config_kernel nokia770_config[] = {
+ { OMAP_TAG_USB, NULL },
+ { OMAP_TAG_MMC, &nokia770_mmc_config },
+};
+
+/*
+ * audio power control
+ */
+#define HEADPHONE_GPIO 14
+#define AMPLIFIER_CTRL_GPIO 58
+
+static struct clk *dspxor_ck;
+static DECLARE_MUTEX(audio_pwr_sem);
+/*
+ * audio_pwr_state
+ * +--+-------------------------+---------------------------------------+
+ * |-1|down |power-up request -> 0 |
+ * +--+-------------------------+---------------------------------------+
+ * | 0|up |power-down(1) request -> 1 |
+ * | | |power-down(2) request -> (ignore) |
+ * +--+-------------------------+---------------------------------------+
+ * | 1|up, |power-up request -> 0 |
+ * | |received down(1) request |power-down(2) request -> -1 |
+ * +--+-------------------------+---------------------------------------+
+ */
+static int audio_pwr_state = -1;
+
+/*
+ * audio_pwr_up / down should be called under audio_pwr_sem
+ */
+static void nokia770_audio_pwr_up(void)
+{
+ clk_enable(dspxor_ck);
+
+ /* Turn on codec */
+ tlv320aic23_power_up();
+
+ if (omap_get_gpio_datain(HEADPHONE_GPIO))
+ /* HP not connected, turn on amplifier */
+ omap_set_gpio_dataout(AMPLIFIER_CTRL_GPIO, 1);
+ else
+ /* HP connected, do not turn on amplifier */
+ printk("HP connected\n");
+}
+
+static void codec_delayed_power_down(void *arg)
+{
+ down(&audio_pwr_sem);
+ if (audio_pwr_state == -1)
+ tlv320aic23_power_down();
+ up(&audio_pwr_sem);
+}
+
+static DECLARE_WORK(codec_power_down_work, codec_delayed_power_down, NULL);
+
+static void nokia770_audio_pwr_down(void)
+{
+ clk_disable(dspxor_ck);
+
+ /* Turn off amplifier */
+ omap_set_gpio_dataout(AMPLIFIER_CTRL_GPIO, 0);
+
+ /* Turn off codec: schedule delayed work */
+ schedule_delayed_work(&codec_power_down_work, HZ / 20); /* 50ms */
+}
+
+void nokia770_audio_pwr_up_request(int stage)
+{
+ down(&audio_pwr_sem);
+ if (audio_pwr_state == -1)
+ nokia770_audio_pwr_up();
+ /* force audio_pwr_state = 0, even if it was 1. */
+ audio_pwr_state = 0;
+ up(&audio_pwr_sem);
+}
+
+void nokia770_audio_pwr_down_request(int stage)
+{
+ down(&audio_pwr_sem);
+ switch (stage) {
+ case 1:
+ if (audio_pwr_state == 0)
+ audio_pwr_state = 1;
+ break;
+ case 2:
+ if (audio_pwr_state == 1) {
+ nokia770_audio_pwr_down();
+ audio_pwr_state = -1;
+ }
+ break;
+ }
+ up(&audio_pwr_sem);
+}
+
+static void __init omap_nokia770_init(void)
+{
+ nokia770_config[0].data = &nokia770_usb_config;
+
+ platform_add_devices(nokia770_devices, ARRAY_SIZE(nokia770_devices));
+ spi_register_board_info(nokia770_spi_board_info,
+ ARRAY_SIZE(nokia770_spi_board_info));
+ omap_board_config = nokia770_config;
+ omap_board_config_size = ARRAY_SIZE(nokia770_config);
+ omap_serial_init();
+ omap_dsp_audio_pwr_up_request = nokia770_audio_pwr_up_request;
+ omap_dsp_audio_pwr_down_request = nokia770_audio_pwr_down_request;
+ dspxor_ck = clk_get(0, "dspxor_ck");
+}
+
+static void __init omap_nokia770_map_io(void)
+{
+ omap1_map_common_io();
+}
+
+MACHINE_START(NOKIA770, "Nokia 770")
+ .phys_io = 0xfff00000,
+ .io_pg_offst = ((0xfef00000) >> 18) & 0xfffc,
+ .boot_params = 0x10000100,
+ .map_io = omap_nokia770_map_io,
+ .init_irq = omap_nokia770_init_irq,
+ .init_machine = omap_nokia770_init,
+ .timer = &omap_timer,
+MACHINE_END
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#include <linux/input.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
#include <asm/arch/usb.h>
#include <asm/arch/mux.h>
#include <asm/arch/tc.h>
+#include <asm/arch/keypad.h>
#include <asm/arch/common.h>
+static int osk_keymap[] = {
+ KEY(0, 0, KEY_F1),
+ KEY(0, 3, KEY_UP),
+ KEY(1, 1, KEY_LEFTCTRL),
+ KEY(1, 2, KEY_LEFT),
+ KEY(2, 0, KEY_SPACE),
+ KEY(2, 1, KEY_ESC),
+ KEY(2, 2, KEY_DOWN),
+ KEY(3, 2, KEY_ENTER),
+ KEY(3, 3, KEY_RIGHT),
+ 0
+};
+
+
static struct mtd_partition osk_partitions[] = {
/* bootloader (U-Boot, etc) in first sector */
{
.id = 1,
};
+static struct resource osk5912_kp_resources[] = {
+ [0] = {
+ .start = INT_KEYBOARD,
+ .end = INT_KEYBOARD,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct omap_kp_platform_data osk_kp_data = {
+ .rows = 8,
+ .cols = 8,
+ .keymap = osk_keymap,
+};
+
+static struct platform_device osk5912_kp_device = {
+ .name = "omap-keypad",
+ .id = -1,
+ .dev = {
+ .platform_data = &osk_kp_data,
+ },
+ .num_resources = ARRAY_SIZE(osk5912_kp_resources),
+ .resource = osk5912_kp_resources,
+};
+
+static struct platform_device osk5912_lcd_device = {
+ .name = "lcd_osk",
+ .id = -1,
+};
+
static struct platform_device *osk5912_devices[] __initdata = {
&osk5912_flash_device,
&osk5912_smc91x_device,
&osk5912_cf_device,
&osk5912_mcbsp1_device,
+ &osk5912_kp_device,
+ &osk5912_lcd_device,
};
static void __init osk_init_smc91x(void)
};
static struct omap_lcd_config osk_lcd_config __initdata = {
- .panel_name = "osk",
.ctrl_name = "internal",
};
static void __init osk_mistral_init(void) { }
#endif
+#define EMIFS_CS3_VAL (0x88013141)
+
static void __init osk_init(void)
{
+ /* Workaround for wrong CS3 (NOR flash) timing
+ * There are some U-Boot versions out there which configure
+ * wrong CS3 memory timings. This mainly leads to CRC
+ * or similiar errors if you use NOR flash (e.g. with JFFS2)
+ */
+ if (EMIFS_CCS(3) != EMIFS_CS3_VAL)
+ EMIFS_CCS(3) = EMIFS_CS3_VAL;
+
osk_flash_resource.end = osk_flash_resource.start = omap_cs3_phys();
osk_flash_resource.end += SZ_32M - 1;
platform_add_devices(osk5912_devices, ARRAY_SIZE(osk5912_devices));
omap_init_irq();
}
+static struct platform_device palmte_lcd_device = {
+ .name = "lcd_palmte",
+ .id = -1,
+};
+
+static struct platform_device *devices[] __initdata = {
+ &palmte_lcd_device,
+};
+
static struct omap_usb_config palmte_usb_config __initdata = {
.register_dev = 1,
.hmc_mode = 0,
};
static struct omap_lcd_config palmte_lcd_config __initdata = {
- .panel_name = "palmte",
.ctrl_name = "internal",
};
{
omap_board_config = palmte_config;
omap_board_config_size = ARRAY_SIZE(palmte_config);
+
+ platform_add_devices(devices, ARRAY_SIZE(devices));
}
static void __init omap_generic_map_io(void)
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
+#include <linux/input.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
#include <asm/arch/gpio.h>
#include <asm/arch/mux.h>
#include <asm/arch/fpga.h>
+#include <asm/arch/keypad.h>
#include <asm/arch/common.h>
#include <asm/arch/board.h>
+static int p2_keymap[] = {
+ KEY(0,0,KEY_UP),
+ KEY(0,1,KEY_RIGHT),
+ KEY(0,2,KEY_LEFT),
+ KEY(0,3,KEY_DOWN),
+ KEY(0,4,KEY_CENTER),
+ KEY(0,5,KEY_0_5),
+ KEY(1,0,KEY_SOFT2),
+ KEY(1,1,KEY_SEND),
+ KEY(1,2,KEY_END),
+ KEY(1,3,KEY_VOLUMEDOWN),
+ KEY(1,4,KEY_VOLUMEUP),
+ KEY(1,5,KEY_RECORD),
+ KEY(2,0,KEY_SOFT1),
+ KEY(2,1,KEY_3),
+ KEY(2,2,KEY_6),
+ KEY(2,3,KEY_9),
+ KEY(2,4,KEY_SHARP),
+ KEY(2,5,KEY_2_5),
+ KEY(3,0,KEY_BACK),
+ KEY(3,1,KEY_2),
+ KEY(3,2,KEY_5),
+ KEY(3,3,KEY_8),
+ KEY(3,4,KEY_0),
+ KEY(3,5,KEY_HEADSETHOOK),
+ KEY(4,0,KEY_HOME),
+ KEY(4,1,KEY_1),
+ KEY(4,2,KEY_4),
+ KEY(4,3,KEY_7),
+ KEY(4,4,KEY_STAR),
+ KEY(4,5,KEY_POWER),
+ 0
+};
+
static struct resource smc91x_resources[] = {
[0] = {
.start = H2P2_DBG_FPGA_ETHR_START, /* Physical */
},
};
-static struct mtd_partition p2_partitions[] = {
+static struct mtd_partition nor_partitions[] = {
/* bootloader (U-Boot, etc) in first sector */
{
.name = "bootloader",
},
};
-static struct flash_platform_data p2_flash_data = {
+static struct flash_platform_data nor_data = {
.map_name = "cfi_probe",
.width = 2,
- .parts = p2_partitions,
- .nr_parts = ARRAY_SIZE(p2_partitions),
+ .parts = nor_partitions,
+ .nr_parts = ARRAY_SIZE(nor_partitions),
};
-static struct resource p2_flash_resource = {
+static struct resource nor_resource = {
.start = OMAP_CS0_PHYS,
.end = OMAP_CS0_PHYS + SZ_32M - 1,
.flags = IORESOURCE_MEM,
};
-static struct platform_device p2_flash_device = {
+static struct platform_device nor_device = {
.name = "omapflash",
.id = 0,
.dev = {
- .platform_data = &p2_flash_data,
+ .platform_data = &nor_data,
+ },
+ .num_resources = 1,
+ .resource = &nor_resource,
+};
+
+static struct nand_platform_data nand_data = {
+ .options = NAND_SAMSUNG_LP_OPTIONS,
+};
+
+static struct resource nand_resource = {
+ .start = OMAP_CS3_PHYS,
+ .end = OMAP_CS3_PHYS + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device nand_device = {
+ .name = "omapnand",
+ .id = 0,
+ .dev = {
+ .platform_data = &nand_data,
},
.num_resources = 1,
- .resource = &p2_flash_resource,
+ .resource = &nand_resource,
};
static struct platform_device smc91x_device = {
.resource = smc91x_resources,
};
+static struct resource kp_resources[] = {
+ [0] = {
+ .start = INT_730_MPUIO_KEYPAD,
+ .end = INT_730_MPUIO_KEYPAD,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct omap_kp_platform_data kp_data = {
+ .rows = 8,
+ .cols = 8,
+ .keymap = p2_keymap,
+};
+
+static struct platform_device kp_device = {
+ .name = "omap-keypad",
+ .id = -1,
+ .dev = {
+ .platform_data = &kp_data,
+ },
+ .num_resources = ARRAY_SIZE(kp_resources),
+ .resource = kp_resources,
+};
+
+static struct platform_device lcd_device = {
+ .name = "lcd_p2",
+ .id = -1,
+};
+
static struct platform_device *devices[] __initdata = {
- &p2_flash_device,
+ &nor_device,
+ &nand_device,
&smc91x_device,
+ &kp_device,
+ &lcd_device,
};
+#define P2_NAND_RB_GPIO_PIN 62
+
+static int nand_dev_ready(struct nand_platform_data *data)
+{
+ return omap_get_gpio_datain(P2_NAND_RB_GPIO_PIN);
+}
+
static struct omap_uart_config perseus2_uart_config __initdata = {
.enabled_uarts = ((1 << 0) | (1 << 1)),
};
static struct omap_lcd_config perseus2_lcd_config __initdata = {
- .panel_name = "p2",
.ctrl_name = "internal",
};
static void __init omap_perseus2_init(void)
{
- (void) platform_add_devices(devices, ARRAY_SIZE(devices));
+ if (!(omap_request_gpio(P2_NAND_RB_GPIO_PIN)))
+ nand_data.dev_ready = nand_dev_ready;
+
+ omap_cfg_reg(L3_1610_FLASH_CS2B_OE);
+ omap_cfg_reg(M8_1610_FLASH_CS2B_WE);
+
+ platform_add_devices(devices, ARRAY_SIZE(devices));
omap_board_config = perseus2_config;
omap_board_config_size = ARRAY_SIZE(perseus2_config);
};
static struct omap_board_config_kernel voiceblue_config[] = {
- { OMAP_TAG_USB, &voiceblue_usb_config },
- { OMAP_TAG_MMC, &voiceblue_mmc_config },
- { OMAP_TAG_UART, &voiceblue_uart_config },
+ { OMAP_TAG_USB, &voiceblue_usb_config },
+ { OMAP_TAG_MMC, &voiceblue_mmc_config },
+ { OMAP_TAG_UART, &voiceblue_uart_config },
};
static void __init voiceblue_init_irq(void)
*/
for (dsor = 2; dsor < 96; ++dsor) {
if ((dsor & 1) && dsor > 8)
- continue;
+ continue;
if (rate >= 96000000 / dsor)
break;
}
clk_register(*clkp);
continue;
}
+
+ if (((*clkp)->flags &CLOCK_IN_OMAP310) && cpu_is_omap310()) {
+ clk_register(*clkp);
+ continue;
+ }
}
info = omap_get_config(OMAP_TAG_CLOCK, struct omap_clock_config);
clk_enable(&armxor_ck.clk);
clk_enable(&armtim_ck.clk); /* This should be done by timer code */
- if (cpu_is_omap1510())
+ if (cpu_is_omap15xx())
clk_enable(&arm_gpio_ck);
return 0;
.name = "ck_ref",
.rate = 12000000,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- ALWAYS_ENABLED,
+ CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
.enable = &omap1_clk_enable_generic,
.disable = &omap1_clk_disable_generic,
};
.name = "ck_dpll1",
.parent = &ck_ref,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- RATE_PROPAGATES | ALWAYS_ENABLED,
+ CLOCK_IN_OMAP310 | RATE_PROPAGATES | ALWAYS_ENABLED,
.enable = &omap1_clk_enable_generic,
.disable = &omap1_clk_disable_generic,
};
.name = "arm_ck",
.parent = &ck_dpll1,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- RATE_CKCTL | RATE_PROPAGATES | ALWAYS_ENABLED,
+ CLOCK_IN_OMAP310 | RATE_CKCTL | RATE_PROPAGATES |
+ ALWAYS_ENABLED,
.rate_offset = CKCTL_ARMDIV_OFFSET,
.recalc = &omap1_ckctl_recalc,
.enable = &omap1_clk_enable_generic,
.name = "armper_ck",
.parent = &ck_dpll1,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- RATE_CKCTL | CLOCK_IDLE_CONTROL,
+ CLOCK_IN_OMAP310 | RATE_CKCTL |
+ CLOCK_IDLE_CONTROL,
.enable_reg = (void __iomem *)ARM_IDLECT2,
.enable_bit = EN_PERCK,
.rate_offset = CKCTL_PERDIV_OFFSET,
static struct clk arm_gpio_ck = {
.name = "arm_gpio_ck",
.parent = &ck_dpll1,
- .flags = CLOCK_IN_OMAP1510,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
.enable_reg = (void __iomem *)ARM_IDLECT2,
.enable_bit = EN_GPIOCK,
.recalc = &followparent_recalc,
.name = "armxor_ck",
.parent = &ck_ref,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- CLOCK_IDLE_CONTROL,
+ CLOCK_IN_OMAP310 | CLOCK_IDLE_CONTROL,
.enable_reg = (void __iomem *)ARM_IDLECT2,
.enable_bit = EN_XORPCK,
.recalc = &followparent_recalc,
.name = "armtim_ck",
.parent = &ck_ref,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- CLOCK_IDLE_CONTROL,
+ CLOCK_IN_OMAP310 | CLOCK_IDLE_CONTROL,
.enable_reg = (void __iomem *)ARM_IDLECT2,
.enable_bit = EN_TIMCK,
.recalc = &followparent_recalc,
.name = "armwdt_ck",
.parent = &ck_ref,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- CLOCK_IDLE_CONTROL,
+ CLOCK_IN_OMAP310 | CLOCK_IDLE_CONTROL,
.enable_reg = (void __iomem *)ARM_IDLECT2,
.enable_bit = EN_WDTCK,
.recalc = &omap1_watchdog_recalc,
.name = "tc_ck",
.parent = &ck_dpll1,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- CLOCK_IN_OMAP730 | RATE_CKCTL |
- RATE_PROPAGATES | ALWAYS_ENABLED |
- CLOCK_IDLE_CONTROL,
+ CLOCK_IN_OMAP730 | CLOCK_IN_OMAP310 |
+ RATE_CKCTL | RATE_PROPAGATES |
+ ALWAYS_ENABLED | CLOCK_IDLE_CONTROL,
.rate_offset = CKCTL_TCDIV_OFFSET,
.recalc = &omap1_ckctl_recalc,
.enable = &omap1_clk_enable_generic,
static struct clk arminth_ck1510 = {
.name = "arminth_ck",
.parent = &tc_ck.clk,
- .flags = CLOCK_IN_OMAP1510 | ALWAYS_ENABLED,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 |
+ ALWAYS_ENABLED,
.recalc = &followparent_recalc,
/* Note: On 1510 the frequency follows TC_CK
*
/* No-idle controlled by "tc_ck" */
.name = "tibp_ck",
.parent = &tc_ck.clk,
- .flags = CLOCK_IN_OMAP1510 | ALWAYS_ENABLED,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 |
+ ALWAYS_ENABLED,
.recalc = &followparent_recalc,
.enable = &omap1_clk_enable_generic,
.disable = &omap1_clk_disable_generic,
.name = "dma_ck",
.parent = &tc_ck.clk,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- ALWAYS_ENABLED,
+ CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
.recalc = &followparent_recalc,
.enable = &omap1_clk_enable_generic,
.disable = &omap1_clk_disable_generic,
.name = "api_ck",
.parent = &tc_ck.clk,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- CLOCK_IDLE_CONTROL,
+ CLOCK_IN_OMAP310 | CLOCK_IDLE_CONTROL,
.enable_reg = (void __iomem *)ARM_IDLECT2,
.enable_bit = EN_APICK,
.recalc = &followparent_recalc,
.clk = {
.name = "lb_ck",
.parent = &tc_ck.clk,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IDLE_CONTROL,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 |
+ CLOCK_IDLE_CONTROL,
.enable_reg = (void __iomem *)ARM_IDLECT2,
.enable_bit = EN_LBCK,
.recalc = &followparent_recalc,
.clk = {
.name = "lcd_ck",
.parent = &ck_dpll1,
- .flags = CLOCK_IN_OMAP1510 | RATE_CKCTL |
- CLOCK_IDLE_CONTROL,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 |
+ RATE_CKCTL | CLOCK_IDLE_CONTROL,
.enable_reg = (void __iomem *)ARM_IDLECT2,
.enable_bit = EN_LCDCK,
.rate_offset = CKCTL_LCDDIV_OFFSET,
/* Direct from ULPD, no real parent */
.parent = &armper_ck.clk,
.rate = 12000000,
- .flags = CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT |
- ALWAYS_ENABLED | CLOCK_NO_IDLE_PARENT,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 |
+ ENABLE_REG_32BIT | ALWAYS_ENABLED |
+ CLOCK_NO_IDLE_PARENT,
.enable_reg = (void __iomem *)MOD_CONF_CTRL_0,
.enable_bit = 29, /* Chooses between 12MHz and 48MHz */
.set_rate = &omap1_set_uart_rate,
.parent = &armper_ck.clk,
.rate = 12000000,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- ENABLE_REG_32BIT | ALWAYS_ENABLED |
- CLOCK_NO_IDLE_PARENT,
+ CLOCK_IN_OMAP310 | ENABLE_REG_32BIT |
+ ALWAYS_ENABLED | CLOCK_NO_IDLE_PARENT,
.enable_reg = (void __iomem *)MOD_CONF_CTRL_0,
.enable_bit = 30, /* Chooses between 12MHz and 48MHz */
.set_rate = &omap1_set_uart_rate,
/* Direct from ULPD, no real parent */
.parent = &armper_ck.clk,
.rate = 12000000,
- .flags = CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT |
- ALWAYS_ENABLED | CLOCK_NO_IDLE_PARENT,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 |
+ ENABLE_REG_32BIT | ALWAYS_ENABLED |
+ CLOCK_NO_IDLE_PARENT,
.enable_reg = (void __iomem *)MOD_CONF_CTRL_0,
.enable_bit = 31, /* Chooses between 12MHz and 48MHz */
.set_rate = &omap1_set_uart_rate,
/* Direct from ULPD, no parent */
.rate = 6000000,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- RATE_FIXED | ENABLE_REG_32BIT,
+ CLOCK_IN_OMAP310 | RATE_FIXED | ENABLE_REG_32BIT,
.enable_reg = (void __iomem *)ULPD_CLOCK_CTRL,
.enable_bit = USB_MCLK_EN_BIT,
.enable = &omap1_clk_enable_generic,
.name = "usb_hhc_ck",
/* Direct from ULPD, no parent */
.rate = 48000000, /* Actually 2 clocks, 12MHz and 48MHz */
- .flags = CLOCK_IN_OMAP1510 |
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 |
RATE_FIXED | ENABLE_REG_32BIT,
.enable_reg = (void __iomem *)MOD_CONF_CTRL_0,
.enable_bit = USB_HOST_HHC_UHOST_EN,
.name = "mclk",
/* Direct from ULPD, no parent. May be enabled by ext hardware. */
.rate = 12000000,
- .flags = CLOCK_IN_OMAP1510 | RATE_FIXED,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | RATE_FIXED,
+ .enable_reg = (void __iomem *)SOFT_REQ_REG,
+ .enable_bit = 6,
.enable = &omap1_clk_enable_generic,
.disable = &omap1_clk_disable_generic,
};
.name = "bclk",
/* Direct from ULPD, no parent. May be enabled by ext hardware. */
.rate = 12000000,
- .flags = CLOCK_IN_OMAP1510 | RATE_FIXED,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | RATE_FIXED,
.enable = &omap1_clk_enable_generic,
.disable = &omap1_clk_disable_generic,
};
};
static struct clk mmc1_ck = {
- .name = "mmc1_ck",
+ .name = "mmc_ck",
+ .id = 1,
/* Functional clock is direct from ULPD, interface clock is ARMPER */
.parent = &armper_ck.clk,
.rate = 48000000,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- RATE_FIXED | ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT,
+ CLOCK_IN_OMAP310 | RATE_FIXED | ENABLE_REG_32BIT |
+ CLOCK_NO_IDLE_PARENT,
.enable_reg = (void __iomem *)MOD_CONF_CTRL_0,
.enable_bit = 23,
.enable = &omap1_clk_enable_generic,
};
static struct clk mmc2_ck = {
- .name = "mmc2_ck",
+ .name = "mmc_ck",
+ .id = 2,
/* Functional clock is direct from ULPD, interface clock is ARMPER */
.parent = &armper_ck.clk,
.rate = 48000000,
static struct clk virtual_ck_mpu = {
.name = "mpu",
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- VIRTUAL_CLOCK | ALWAYS_ENABLED,
+ CLOCK_IN_OMAP310 | VIRTUAL_CLOCK | ALWAYS_ENABLED,
.parent = &arm_ck, /* Is smarter alias for */
.recalc = &followparent_recalc,
.set_rate = &omap1_select_table_rate,
.disable = &omap1_clk_disable_generic,
};
+/* virtual functional clock domain for I2C. Just for making sure that ARMXOR_CK
+remains active during MPU idle whenever this is enabled */
+static struct clk i2c_fck = {
+ .name = "i2c_fck",
+ .id = 1,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+ VIRTUAL_CLOCK | CLOCK_NO_IDLE_PARENT |
+ ALWAYS_ENABLED,
+ .parent = &armxor_ck.clk,
+ .recalc = &followparent_recalc,
+ .enable = &omap1_clk_enable_generic,
+ .disable = &omap1_clk_disable_generic,
+};
+
static struct clk * onchip_clks[] = {
/* non-ULPD clocks */
&ck_ref,
&mmc2_ck,
/* Virtual clocks */
&virtual_ck_mpu,
+ &i2c_fck,
};
#endif
static inline void omap_init_rtc(void) {}
#endif
+#if defined(CONFIG_OMAP_STI)
+
+#define OMAP1_STI_BASE IO_ADDRESS(0xfffea000)
+#define OMAP1_STI_CHANNEL_BASE (OMAP1_STI_BASE + 0x400)
+
+static struct resource sti_resources[] = {
+ {
+ .start = OMAP1_STI_BASE,
+ .end = OMAP1_STI_BASE + SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = OMAP1_STI_CHANNEL_BASE,
+ .end = OMAP1_STI_CHANNEL_BASE + SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = INT_1610_STI,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device sti_device = {
+ .name = "sti",
+ .id = -1,
+ .dev = {
+ .release = omap_nop_release,
+ },
+ .num_resources = ARRAY_SIZE(sti_resources),
+ .resource = sti_resources,
+};
+
+static inline void omap_init_sti(void)
+{
+ platform_device_register(&sti_device);
+}
+#else
+static inline void omap_init_sti(void) {}
+#endif
/*-------------------------------------------------------------------------*/
*/
omap_init_irda();
omap_init_rtc();
+ omap_init_sti();
return 0;
}
#include <asm/io.h>
#include <asm/arch/mux.h>
#include <asm/arch/tc.h>
+#include <asm/arch/omapfb.h>
extern int omap1_clk_init(void);
extern void omap_check_revision(void);
}
#endif
#ifdef CONFIG_ARCH_OMAP15XX
- if (cpu_is_omap1510()) {
+ if (cpu_is_omap15xx()) {
iotable_init(omap1510_io_desc, ARRAY_SIZE(omap1510_io_desc));
}
#endif
#endif
omap_sram_init();
+ omapfb_reserve_mem();
}
/*
unsigned long wake_enable;
};
-static unsigned int irq_bank_count = 0;
+static unsigned int irq_bank_count;
static struct omap_irq_bank *irq_banks;
static inline unsigned int irq_bank_readl(int bank, int offset)
#ifdef CONFIG_ARCH_OMAP730
static struct omap_irq_bank omap730_irq_banks[] = {
- { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3f8e22f },
- { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfdb9c1f2 },
+ { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3f8e22f },
+ { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfdb9c1f2 },
{ .base_reg = OMAP_IH2_BASE + 0x100, .trigger_map = 0x800040f3 },
};
#endif
#ifdef CONFIG_ARCH_OMAP15XX
static struct omap_irq_bank omap1510_irq_banks[] = {
- { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3febfff },
- { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xffbfffed },
+ { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3febfff },
+ { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xffbfffed },
};
static struct omap_irq_bank omap310_irq_banks[] = {
- { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3faefc3 },
- { .base_reg = OMAP_IH2_BASE, .trigger_map = 0x65b3c061 },
+ { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3faefc3 },
+ { .base_reg = OMAP_IH2_BASE, .trigger_map = 0x65b3c061 },
};
#endif
#if defined(CONFIG_ARCH_OMAP16XX)
static struct omap_irq_bank omap1610_irq_banks[] = {
- { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3fefe8f },
- { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfdb7c1fd },
+ { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3fefe8f },
+ { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfdb7c1fd },
{ .base_reg = OMAP_IH2_BASE + 0x100, .trigger_map = 0xffffb7ff },
{ .base_reg = OMAP_IH2_BASE + 0x200, .trigger_map = 0xffffffff },
};
#ifdef CONFIG_ARCH_OMAP730
struct pin_config __initdata_or_module omap730_pins[] = {
-MUX_CFG_730("E2_730_KBR0", 12, 21, 0, 0, 20, 1, NA, 0, 0)
-MUX_CFG_730("J7_730_KBR1", 12, 25, 0, 0, 24, 1, NA, 0, 0)
-MUX_CFG_730("E1_730_KBR2", 12, 29, 0, 0, 28, 1, NA, 0, 0)
-MUX_CFG_730("F3_730_KBR3", 13, 1, 0, 0, 0, 1, NA, 0, 0)
-MUX_CFG_730("D2_730_KBR4", 13, 5, 0, 0, 4, 1, NA, 0, 0)
-MUX_CFG_730("C2_730_KBC0", 13, 9, 0, 0, 8, 1, NA, 0, 0)
-MUX_CFG_730("D3_730_KBC1", 13, 13, 0, 0, 12, 1, NA, 0, 0)
-MUX_CFG_730("E4_730_KBC2", 13, 17, 0, 0, 16, 1, NA, 0, 0)
-MUX_CFG_730("F4_730_KBC3", 13, 21, 0, 0, 20, 1, NA, 0, 0)
-MUX_CFG_730("E3_730_KBC4", 13, 25, 0, 0, 24, 1, NA, 0, 0)
+MUX_CFG_730("E2_730_KBR0", 12, 21, 0, 20, 1, 0)
+MUX_CFG_730("J7_730_KBR1", 12, 25, 0, 24, 1, 0)
+MUX_CFG_730("E1_730_KBR2", 12, 29, 0, 28, 1, 0)
+MUX_CFG_730("F3_730_KBR3", 13, 1, 0, 0, 1, 0)
+MUX_CFG_730("D2_730_KBR4", 13, 5, 0, 4, 1, 0)
+MUX_CFG_730("C2_730_KBC0", 13, 9, 0, 8, 1, 0)
+MUX_CFG_730("D3_730_KBC1", 13, 13, 0, 12, 1, 0)
+MUX_CFG_730("E4_730_KBC2", 13, 17, 0, 16, 1, 0)
+MUX_CFG_730("F4_730_KBC3", 13, 21, 0, 20, 1, 0)
+MUX_CFG_730("E3_730_KBC4", 13, 25, 0, 24, 1, 0)
+
+MUX_CFG_730("AA17_730_USB_DM", 2, 21, 0, 20, 0, 0)
+MUX_CFG_730("W16_730_USB_PU_EN", 2, 25, 0, 24, 0, 0)
+MUX_CFG_730("W17_730_USB_VBUSI", 2, 29, 0, 28, 0, 0)
};
#endif
MUX_CFG("Y15_1610_UART3_RTS", A, 0, 1, 2, 6, 0, NA, 0, 0)
/* PWT & PWL, conflicts with UART3 */
-MUX_CFG("PWT", 6, 0, 2, 0, 30, 0, NA, 0, 0)
-MUX_CFG("PWL", 6, 3, 1, 0, 31, 1, NA, 0, 0)
+MUX_CFG("PWT", 6, 0, 2, 0, 30, 0, NA, 0, 0)
+MUX_CFG("PWL", 6, 3, 1, 0, 31, 1, NA, 0, 0)
/* USB internal master generic */
MUX_CFG("R18_USB_VBUS", 7, 9, 2, 1, 11, 0, NA, 0, 1)
/* Misc ballouts */
MUX_CFG("BALLOUT_V8_ARMIO3", B, 18, 0, 2, 25, 1, NA, 0, 1)
-MUX_CFG("N20_HDQ", 6, 18, 1, 1, 4, 0, 1, 4, 0)
+MUX_CFG("N20_HDQ", 6, 18, 1, 1, 4, 0, 1, 4, 0)
/* OMAP-1610 MMC2 */
MUX_CFG("W8_1610_MMC2_DAT0", B, 21, 6, 2, 23, 1, 2, 1, 1)
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap1/pm.c
+ *
+ * OMAP Power Management Routines
+ *
+ * Original code for the SA11x0:
+ * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
+ *
+ * Modified for the PXA250 by Nicolas Pitre:
+ * Copyright (c) 2002 Monta Vista Software, Inc.
+ *
+ * Modified for the OMAP1510 by David Singleton:
+ * Copyright (c) 2002 Monta Vista Software, Inc.
+ *
+ * Cleanup 2004 for OMAP1510/1610 by 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/pm.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/pm.h>
+#include <linux/interrupt.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+#include <asm/mach/time.h>
+#include <asm/mach/irq.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/irqs.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/sram.h>
+#include <asm/arch/tc.h>
+#include <asm/arch/pm.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/tps65010.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/dsp_common.h>
+#include <asm/arch/dmtimer.h>
+
+static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE];
+static unsigned short dsp_sleep_save[DSP_SLEEP_SAVE_SIZE];
+static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE];
+static unsigned int mpui730_sleep_save[MPUI730_SLEEP_SAVE_SIZE];
+static unsigned int mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_SIZE];
+static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE];
+
+static unsigned short enable_dyn_sleep = 1;
+
+static ssize_t omap_pm_sleep_while_idle_show(struct subsystem * subsys, char *buf)
+{
+ return sprintf(buf, "%hu\n", enable_dyn_sleep);
+}
+
+static ssize_t omap_pm_sleep_while_idle_store(struct subsystem * subsys,
+ const char * buf,
+ size_t n)
+{
+ unsigned short value;
+ if (sscanf(buf, "%hu", &value) != 1 ||
+ (value != 0 && value != 1)) {
+ printk(KERN_ERR "idle_sleep_store: Invalid value\n");
+ return -EINVAL;
+ }
+ enable_dyn_sleep = value;
+ return n;
+}
+
+static struct subsys_attribute sleep_while_idle_attr = {
+ .attr = {
+ .name = __stringify(sleep_while_idle),
+ .mode = 0644,
+ },
+ .show = omap_pm_sleep_while_idle_show,
+ .store = omap_pm_sleep_while_idle_store,
+};
+
+extern struct subsystem power_subsys;
+static void (*omap_sram_idle)(void) = NULL;
+static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL;
+
+/*
+ * Let's power down on idle, but only if we are really
+ * idle, because once we start down the path of
+ * going idle we continue to do idle even if we get
+ * a clock tick interrupt . .
+ */
+void omap_pm_idle(void)
+{
+ extern __u32 arm_idlect1_mask;
+ __u32 use_idlect1 = arm_idlect1_mask;
+#ifndef CONFIG_OMAP_MPU_TIMER
+ int do_sleep;
+#endif
+
+ local_irq_disable();
+ local_fiq_disable();
+ if (need_resched()) {
+ local_fiq_enable();
+ local_irq_enable();
+ return;
+ }
+
+ /*
+ * Since an interrupt may set up a timer, we don't want to
+ * reprogram the hardware timer with interrupts enabled.
+ * Re-enable interrupts only after returning from idle.
+ */
+ timer_dyn_reprogram();
+
+#ifdef CONFIG_OMAP_MPU_TIMER
+#warning Enable 32kHz OS timer in order to allow sleep states in idle
+ use_idlect1 = use_idlect1 & ~(1 << 9);
+#else
+
+ do_sleep = 0;
+ while (enable_dyn_sleep) {
+
+#ifdef CONFIG_CBUS_TAHVO_USB
+ extern int vbus_active;
+ /* Clock requirements? */
+ if (vbus_active)
+ break;
+#endif
+ do_sleep = 1;
+ break;
+ }
+
+#ifdef CONFIG_OMAP_DM_TIMER
+ use_idlect1 = omap_dm_timer_modify_idlect_mask(use_idlect1);
+#endif
+
+ if (omap_dma_running()) {
+ use_idlect1 &= ~(1 << 6);
+ if (omap_lcd_dma_ext_running())
+ use_idlect1 &= ~(1 << 12);
+ }
+
+ /* We should be able to remove the do_sleep variable and multiple
+ * tests above as soon as drivers, timer and DMA code have been fixed.
+ * Even the sleep block count should become obsolete. */
+ if ((use_idlect1 != ~0) || !do_sleep) {
+
+ __u32 saved_idlect1 = omap_readl(ARM_IDLECT1);
+ if (cpu_is_omap15xx())
+ use_idlect1 &= OMAP1510_BIG_SLEEP_REQUEST;
+ else
+ use_idlect1 &= OMAP1610_IDLECT1_SLEEP_VAL;
+ omap_writel(use_idlect1, ARM_IDLECT1);
+ __asm__ volatile ("mcr p15, 0, r0, c7, c0, 4");
+ omap_writel(saved_idlect1, ARM_IDLECT1);
+
+ local_fiq_enable();
+ local_irq_enable();
+ return;
+ }
+ omap_sram_suspend(omap_readl(ARM_IDLECT1),
+ omap_readl(ARM_IDLECT2));
+#endif
+
+ local_fiq_enable();
+ local_irq_enable();
+}
+
+/*
+ * Configuration of the wakeup event is board specific. For the
+ * moment we put it into this helper function. Later it may move
+ * to board specific files.
+ */
+static void omap_pm_wakeup_setup(void)
+{
+ u32 level1_wake = 0;
+ u32 level2_wake = OMAP_IRQ_BIT(INT_UART2);
+
+ /*
+ * Turn off all interrupts except GPIO bank 1, L1-2nd level cascade,
+ * and the L2 wakeup interrupts: keypad and UART2. Note that the
+ * drivers must still separately call omap_set_gpio_wakeup() to
+ * wake up to a GPIO interrupt.
+ */
+ if (cpu_is_omap730())
+ level1_wake = OMAP_IRQ_BIT(INT_730_GPIO_BANK1) |
+ OMAP_IRQ_BIT(INT_730_IH2_IRQ);
+ else if (cpu_is_omap15xx())
+ level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) |
+ OMAP_IRQ_BIT(INT_1510_IH2_IRQ);
+ else if (cpu_is_omap16xx())
+ level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) |
+ OMAP_IRQ_BIT(INT_1610_IH2_IRQ);
+
+ omap_writel(~level1_wake, OMAP_IH1_MIR);
+
+ if (cpu_is_omap730()) {
+ omap_writel(~level2_wake, OMAP_IH2_0_MIR);
+ omap_writel(~(OMAP_IRQ_BIT(INT_730_WAKE_UP_REQ) |
+ OMAP_IRQ_BIT(INT_730_MPUIO_KEYPAD)),
+ OMAP_IH2_1_MIR);
+ } else if (cpu_is_omap15xx()) {
+ level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD);
+ omap_writel(~level2_wake, OMAP_IH2_MIR);
+ } else if (cpu_is_omap16xx()) {
+ level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD);
+ omap_writel(~level2_wake, OMAP_IH2_0_MIR);
+
+ /* INT_1610_WAKE_UP_REQ is needed for GPIO wakeup... */
+ omap_writel(~OMAP_IRQ_BIT(INT_1610_WAKE_UP_REQ),
+ OMAP_IH2_1_MIR);
+ omap_writel(~0x0, OMAP_IH2_2_MIR);
+ omap_writel(~0x0, OMAP_IH2_3_MIR);
+ }
+
+ /* New IRQ agreement, recalculate in cascade order */
+ omap_writel(1, OMAP_IH2_CONTROL);
+ omap_writel(1, OMAP_IH1_CONTROL);
+}
+
+#define EN_DSPCK 13 /* ARM_CKCTL */
+#define EN_APICK 6 /* ARM_IDLECT2 */
+#define DSP_EN 1 /* ARM_RSTCT1 */
+
+void omap_pm_suspend(void)
+{
+ unsigned long arg0 = 0, arg1 = 0;
+
+ printk("PM: OMAP%x is trying to enter deep sleep...\n", system_rev);
+
+ omap_serial_wake_trigger(1);
+
+ if (machine_is_omap_osk()) {
+ /* Stop LED1 (D9) blink */
+ tps65010_set_led(LED1, OFF);
+ }
+
+ omap_writew(0xffff, ULPD_SOFT_DISABLE_REQ_REG);
+
+ /*
+ * Step 1: turn off interrupts (FIXME: NOTE: already disabled)
+ */
+
+ local_irq_disable();
+ local_fiq_disable();
+
+ /*
+ * Step 2: save registers
+ *
+ * The omap is a strange/beautiful device. The caches, memory
+ * and register state are preserved across power saves.
+ * We have to save and restore very little register state to
+ * idle the omap.
+ *
+ * Save interrupt, MPUI, ARM and UPLD control registers.
+ */
+
+ if (cpu_is_omap730()) {
+ MPUI730_SAVE(OMAP_IH1_MIR);
+ MPUI730_SAVE(OMAP_IH2_0_MIR);
+ MPUI730_SAVE(OMAP_IH2_1_MIR);
+ MPUI730_SAVE(MPUI_CTRL);
+ MPUI730_SAVE(MPUI_DSP_BOOT_CONFIG);
+ MPUI730_SAVE(MPUI_DSP_API_CONFIG);
+ MPUI730_SAVE(EMIFS_CONFIG);
+ MPUI730_SAVE(EMIFF_SDRAM_CONFIG);
+
+ } else if (cpu_is_omap15xx()) {
+ MPUI1510_SAVE(OMAP_IH1_MIR);
+ MPUI1510_SAVE(OMAP_IH2_MIR);
+ MPUI1510_SAVE(MPUI_CTRL);
+ MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG);
+ MPUI1510_SAVE(MPUI_DSP_API_CONFIG);
+ MPUI1510_SAVE(EMIFS_CONFIG);
+ MPUI1510_SAVE(EMIFF_SDRAM_CONFIG);
+ } else if (cpu_is_omap16xx()) {
+ MPUI1610_SAVE(OMAP_IH1_MIR);
+ MPUI1610_SAVE(OMAP_IH2_0_MIR);
+ MPUI1610_SAVE(OMAP_IH2_1_MIR);
+ MPUI1610_SAVE(OMAP_IH2_2_MIR);
+ MPUI1610_SAVE(OMAP_IH2_3_MIR);
+ MPUI1610_SAVE(MPUI_CTRL);
+ MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG);
+ MPUI1610_SAVE(MPUI_DSP_API_CONFIG);
+ MPUI1610_SAVE(EMIFS_CONFIG);
+ MPUI1610_SAVE(EMIFF_SDRAM_CONFIG);
+ }
+
+ ARM_SAVE(ARM_CKCTL);
+ ARM_SAVE(ARM_IDLECT1);
+ ARM_SAVE(ARM_IDLECT2);
+ if (!(cpu_is_omap15xx()))
+ ARM_SAVE(ARM_IDLECT3);
+ ARM_SAVE(ARM_EWUPCT);
+ ARM_SAVE(ARM_RSTCT1);
+ ARM_SAVE(ARM_RSTCT2);
+ ARM_SAVE(ARM_SYSST);
+ ULPD_SAVE(ULPD_CLOCK_CTRL);
+ ULPD_SAVE(ULPD_STATUS_REQ);
+
+ /* (Step 3 removed - we now allow deep sleep by default) */
+
+ /*
+ * Step 4: OMAP DSP Shutdown
+ */
+
+ /* stop DSP */
+ omap_writew(omap_readw(ARM_RSTCT1) & ~(1 << DSP_EN), ARM_RSTCT1);
+
+ /* shut down dsp_ck */
+ omap_writew(omap_readw(ARM_CKCTL) & ~(1 << EN_DSPCK), ARM_CKCTL);
+
+ /* temporarily enabling api_ck to access DSP registers */
+ omap_writew(omap_readw(ARM_IDLECT2) | 1 << EN_APICK, ARM_IDLECT2);
+
+ /* save DSP registers */
+ DSP_SAVE(DSP_IDLECT2);
+
+ /* Stop all DSP domain clocks */
+ __raw_writew(0, DSP_IDLECT2);
+
+ /*
+ * Step 5: Wakeup Event Setup
+ */
+
+ omap_pm_wakeup_setup();
+
+ /*
+ * Step 6: ARM and Traffic controller shutdown
+ */
+
+ /* disable ARM watchdog */
+ omap_writel(0x00F5, OMAP_WDT_TIMER_MODE);
+ omap_writel(0x00A0, OMAP_WDT_TIMER_MODE);
+
+ /*
+ * Step 6b: ARM and Traffic controller shutdown
+ *
+ * Step 6 continues here. Prepare jump to power management
+ * assembly code in internal SRAM.
+ *
+ * Since the omap_cpu_suspend routine has been copied to
+ * SRAM, we'll do an indirect procedure call to it and pass the
+ * contents of arm_idlect1 and arm_idlect2 so it can restore
+ * them when it wakes up and it will return.
+ */
+
+ arg0 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT1];
+ arg1 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT2];
+
+ /*
+ * Step 6c: ARM and Traffic controller shutdown
+ *
+ * Jump to assembly code. The processor will stay there
+ * until wake up.
+ */
+ omap_sram_suspend(arg0, arg1);
+
+ /*
+ * If we are here, processor is woken up!
+ */
+
+ /*
+ * Restore DSP clocks
+ */
+
+ /* again temporarily enabling api_ck to access DSP registers */
+ omap_writew(omap_readw(ARM_IDLECT2) | 1 << EN_APICK, ARM_IDLECT2);
+
+ /* Restore DSP domain clocks */
+ DSP_RESTORE(DSP_IDLECT2);
+
+ /*
+ * Restore ARM state, except ARM_IDLECT1/2 which omap_cpu_suspend did
+ */
+
+ if (!(cpu_is_omap15xx()))
+ ARM_RESTORE(ARM_IDLECT3);
+ ARM_RESTORE(ARM_CKCTL);
+ ARM_RESTORE(ARM_EWUPCT);
+ ARM_RESTORE(ARM_RSTCT1);
+ ARM_RESTORE(ARM_RSTCT2);
+ ARM_RESTORE(ARM_SYSST);
+ ULPD_RESTORE(ULPD_CLOCK_CTRL);
+ ULPD_RESTORE(ULPD_STATUS_REQ);
+
+ if (cpu_is_omap730()) {
+ MPUI730_RESTORE(EMIFS_CONFIG);
+ MPUI730_RESTORE(EMIFF_SDRAM_CONFIG);
+ MPUI730_RESTORE(OMAP_IH1_MIR);
+ MPUI730_RESTORE(OMAP_IH2_0_MIR);
+ MPUI730_RESTORE(OMAP_IH2_1_MIR);
+ } else if (cpu_is_omap15xx()) {
+ MPUI1510_RESTORE(MPUI_CTRL);
+ MPUI1510_RESTORE(MPUI_DSP_BOOT_CONFIG);
+ MPUI1510_RESTORE(MPUI_DSP_API_CONFIG);
+ MPUI1510_RESTORE(EMIFS_CONFIG);
+ MPUI1510_RESTORE(EMIFF_SDRAM_CONFIG);
+ MPUI1510_RESTORE(OMAP_IH1_MIR);
+ MPUI1510_RESTORE(OMAP_IH2_MIR);
+ } else if (cpu_is_omap16xx()) {
+ MPUI1610_RESTORE(MPUI_CTRL);
+ MPUI1610_RESTORE(MPUI_DSP_BOOT_CONFIG);
+ MPUI1610_RESTORE(MPUI_DSP_API_CONFIG);
+ MPUI1610_RESTORE(EMIFS_CONFIG);
+ MPUI1610_RESTORE(EMIFF_SDRAM_CONFIG);
+
+ MPUI1610_RESTORE(OMAP_IH1_MIR);
+ MPUI1610_RESTORE(OMAP_IH2_0_MIR);
+ MPUI1610_RESTORE(OMAP_IH2_1_MIR);
+ MPUI1610_RESTORE(OMAP_IH2_2_MIR);
+ MPUI1610_RESTORE(OMAP_IH2_3_MIR);
+ }
+
+ omap_writew(0, ULPD_SOFT_DISABLE_REQ_REG);
+
+ /*
+ * Reenable interrupts
+ */
+
+ local_irq_enable();
+ local_fiq_enable();
+
+ omap_serial_wake_trigger(0);
+
+ printk("PM: OMAP%x is re-starting from deep sleep...\n", system_rev);
+
+ if (machine_is_omap_osk()) {
+ /* Let LED1 (D9) blink again */
+ tps65010_set_led(LED1, BLINK);
+ }
+}
+
+#if defined(DEBUG) && defined(CONFIG_PROC_FS)
+static int g_read_completed;
+
+/*
+ * Read system PM registers for debugging
+ */
+static int omap_pm_read_proc(
+ char *page_buffer,
+ char **my_first_byte,
+ off_t virtual_start,
+ int length,
+ int *eof,
+ void *data)
+{
+ int my_buffer_offset = 0;
+ char * const my_base = page_buffer;
+
+ ARM_SAVE(ARM_CKCTL);
+ ARM_SAVE(ARM_IDLECT1);
+ ARM_SAVE(ARM_IDLECT2);
+ if (!(cpu_is_omap15xx()))
+ ARM_SAVE(ARM_IDLECT3);
+ ARM_SAVE(ARM_EWUPCT);
+ ARM_SAVE(ARM_RSTCT1);
+ ARM_SAVE(ARM_RSTCT2);
+ ARM_SAVE(ARM_SYSST);
+
+ ULPD_SAVE(ULPD_IT_STATUS);
+ ULPD_SAVE(ULPD_CLOCK_CTRL);
+ ULPD_SAVE(ULPD_SOFT_REQ);
+ ULPD_SAVE(ULPD_STATUS_REQ);
+ ULPD_SAVE(ULPD_DPLL_CTRL);
+ ULPD_SAVE(ULPD_POWER_CTRL);
+
+ if (cpu_is_omap730()) {
+ MPUI730_SAVE(MPUI_CTRL);
+ MPUI730_SAVE(MPUI_DSP_STATUS);
+ MPUI730_SAVE(MPUI_DSP_BOOT_CONFIG);
+ MPUI730_SAVE(MPUI_DSP_API_CONFIG);
+ MPUI730_SAVE(EMIFF_SDRAM_CONFIG);
+ MPUI730_SAVE(EMIFS_CONFIG);
+ } else if (cpu_is_omap15xx()) {
+ MPUI1510_SAVE(MPUI_CTRL);
+ MPUI1510_SAVE(MPUI_DSP_STATUS);
+ MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG);
+ MPUI1510_SAVE(MPUI_DSP_API_CONFIG);
+ MPUI1510_SAVE(EMIFF_SDRAM_CONFIG);
+ MPUI1510_SAVE(EMIFS_CONFIG);
+ } else if (cpu_is_omap16xx()) {
+ MPUI1610_SAVE(MPUI_CTRL);
+ MPUI1610_SAVE(MPUI_DSP_STATUS);
+ MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG);
+ MPUI1610_SAVE(MPUI_DSP_API_CONFIG);
+ MPUI1610_SAVE(EMIFF_SDRAM_CONFIG);
+ MPUI1610_SAVE(EMIFS_CONFIG);
+ }
+
+ if (virtual_start == 0) {
+ g_read_completed = 0;
+
+ my_buffer_offset += sprintf(my_base + my_buffer_offset,
+ "ARM_CKCTL_REG: 0x%-8x \n"
+ "ARM_IDLECT1_REG: 0x%-8x \n"
+ "ARM_IDLECT2_REG: 0x%-8x \n"
+ "ARM_IDLECT3_REG: 0x%-8x \n"
+ "ARM_EWUPCT_REG: 0x%-8x \n"
+ "ARM_RSTCT1_REG: 0x%-8x \n"
+ "ARM_RSTCT2_REG: 0x%-8x \n"
+ "ARM_SYSST_REG: 0x%-8x \n"
+ "ULPD_IT_STATUS_REG: 0x%-4x \n"
+ "ULPD_CLOCK_CTRL_REG: 0x%-4x \n"
+ "ULPD_SOFT_REQ_REG: 0x%-4x \n"
+ "ULPD_DPLL_CTRL_REG: 0x%-4x \n"
+ "ULPD_STATUS_REQ_REG: 0x%-4x \n"
+ "ULPD_POWER_CTRL_REG: 0x%-4x \n",
+ ARM_SHOW(ARM_CKCTL),
+ ARM_SHOW(ARM_IDLECT1),
+ ARM_SHOW(ARM_IDLECT2),
+ ARM_SHOW(ARM_IDLECT3),
+ ARM_SHOW(ARM_EWUPCT),
+ ARM_SHOW(ARM_RSTCT1),
+ ARM_SHOW(ARM_RSTCT2),
+ ARM_SHOW(ARM_SYSST),
+ ULPD_SHOW(ULPD_IT_STATUS),
+ ULPD_SHOW(ULPD_CLOCK_CTRL),
+ ULPD_SHOW(ULPD_SOFT_REQ),
+ ULPD_SHOW(ULPD_DPLL_CTRL),
+ ULPD_SHOW(ULPD_STATUS_REQ),
+ ULPD_SHOW(ULPD_POWER_CTRL));
+
+ if (cpu_is_omap730()) {
+ my_buffer_offset += sprintf(my_base + my_buffer_offset,
+ "MPUI730_CTRL_REG 0x%-8x \n"
+ "MPUI730_DSP_STATUS_REG: 0x%-8x \n"
+ "MPUI730_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
+ "MPUI730_DSP_API_CONFIG_REG: 0x%-8x \n"
+ "MPUI730_SDRAM_CONFIG_REG: 0x%-8x \n"
+ "MPUI730_EMIFS_CONFIG_REG: 0x%-8x \n",
+ MPUI730_SHOW(MPUI_CTRL),
+ MPUI730_SHOW(MPUI_DSP_STATUS),
+ MPUI730_SHOW(MPUI_DSP_BOOT_CONFIG),
+ MPUI730_SHOW(MPUI_DSP_API_CONFIG),
+ MPUI730_SHOW(EMIFF_SDRAM_CONFIG),
+ MPUI730_SHOW(EMIFS_CONFIG));
+ } else if (cpu_is_omap15xx()) {
+ my_buffer_offset += sprintf(my_base + my_buffer_offset,
+ "MPUI1510_CTRL_REG 0x%-8x \n"
+ "MPUI1510_DSP_STATUS_REG: 0x%-8x \n"
+ "MPUI1510_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
+ "MPUI1510_DSP_API_CONFIG_REG: 0x%-8x \n"
+ "MPUI1510_SDRAM_CONFIG_REG: 0x%-8x \n"
+ "MPUI1510_EMIFS_CONFIG_REG: 0x%-8x \n",
+ MPUI1510_SHOW(MPUI_CTRL),
+ MPUI1510_SHOW(MPUI_DSP_STATUS),
+ MPUI1510_SHOW(MPUI_DSP_BOOT_CONFIG),
+ MPUI1510_SHOW(MPUI_DSP_API_CONFIG),
+ MPUI1510_SHOW(EMIFF_SDRAM_CONFIG),
+ MPUI1510_SHOW(EMIFS_CONFIG));
+ } else if (cpu_is_omap16xx()) {
+ my_buffer_offset += sprintf(my_base + my_buffer_offset,
+ "MPUI1610_CTRL_REG 0x%-8x \n"
+ "MPUI1610_DSP_STATUS_REG: 0x%-8x \n"
+ "MPUI1610_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
+ "MPUI1610_DSP_API_CONFIG_REG: 0x%-8x \n"
+ "MPUI1610_SDRAM_CONFIG_REG: 0x%-8x \n"
+ "MPUI1610_EMIFS_CONFIG_REG: 0x%-8x \n",
+ MPUI1610_SHOW(MPUI_CTRL),
+ MPUI1610_SHOW(MPUI_DSP_STATUS),
+ MPUI1610_SHOW(MPUI_DSP_BOOT_CONFIG),
+ MPUI1610_SHOW(MPUI_DSP_API_CONFIG),
+ MPUI1610_SHOW(EMIFF_SDRAM_CONFIG),
+ MPUI1610_SHOW(EMIFS_CONFIG));
+ }
+
+ g_read_completed++;
+ } else if (g_read_completed >= 1) {
+ *eof = 1;
+ return 0;
+ }
+ g_read_completed++;
+
+ *my_first_byte = page_buffer;
+ return my_buffer_offset;
+}
+
+static void omap_pm_init_proc(void)
+{
+ struct proc_dir_entry *entry;
+
+ entry = create_proc_read_entry("driver/omap_pm",
+ S_IWUSR | S_IRUGO, NULL,
+ omap_pm_read_proc, NULL);
+}
+
+#endif /* DEBUG && CONFIG_PROC_FS */
+
+static void (*saved_idle)(void) = NULL;
+
+/*
+ * omap_pm_prepare - Do preliminary suspend work.
+ * @state: suspend state we're entering.
+ *
+ */
+static int omap_pm_prepare(suspend_state_t state)
+{
+ int error = 0;
+
+ /* We cannot sleep in idle until we have resumed */
+ saved_idle = pm_idle;
+ pm_idle = NULL;
+
+ switch (state)
+ {
+ case PM_SUSPEND_STANDBY:
+ case PM_SUSPEND_MEM:
+ break;
+
+ case PM_SUSPEND_DISK:
+ return -ENOTSUPP;
+
+ default:
+ return -EINVAL;
+ }
+
+ return error;
+}
+
+
+/*
+ * omap_pm_enter - Actually enter a sleep state.
+ * @state: State we're entering.
+ *
+ */
+
+static int omap_pm_enter(suspend_state_t state)
+{
+ switch (state)
+ {
+ case PM_SUSPEND_STANDBY:
+ case PM_SUSPEND_MEM:
+ omap_pm_suspend();
+ break;
+
+ case PM_SUSPEND_DISK:
+ return -ENOTSUPP;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+/**
+ * omap_pm_finish - Finish up suspend sequence.
+ * @state: State we're coming out of.
+ *
+ * This is called after we wake back up (or if entering the sleep state
+ * failed).
+ */
+
+static int omap_pm_finish(suspend_state_t state)
+{
+ pm_idle = saved_idle;
+ return 0;
+}
+
+
+static irqreturn_t omap_wakeup_interrupt(int irq, void * dev,
+ struct pt_regs * regs)
+{
+ return IRQ_HANDLED;
+}
+
+static struct irqaction omap_wakeup_irq = {
+ .name = "peripheral wakeup",
+ .flags = SA_INTERRUPT,
+ .handler = omap_wakeup_interrupt
+};
+
+
+
+static struct pm_ops omap_pm_ops ={
+ .pm_disk_mode = 0,
+ .prepare = omap_pm_prepare,
+ .enter = omap_pm_enter,
+ .finish = omap_pm_finish,
+};
+
+static int __init omap_pm_init(void)
+{
+ printk("Power Management for TI OMAP.\n");
+
+ /*
+ * We copy the assembler sleep/wakeup routines to SRAM.
+ * These routines need to be in SRAM as that's the only
+ * memory the MPU can see when it wakes up.
+ */
+ if (cpu_is_omap730()) {
+ omap_sram_idle = omap_sram_push(omap730_idle_loop_suspend,
+ omap730_idle_loop_suspend_sz);
+ omap_sram_suspend = omap_sram_push(omap730_cpu_suspend,
+ omap730_cpu_suspend_sz);
+ } else if (cpu_is_omap15xx()) {
+ omap_sram_idle = omap_sram_push(omap1510_idle_loop_suspend,
+ omap1510_idle_loop_suspend_sz);
+ omap_sram_suspend = omap_sram_push(omap1510_cpu_suspend,
+ omap1510_cpu_suspend_sz);
+ } else if (cpu_is_omap16xx()) {
+ omap_sram_idle = omap_sram_push(omap1610_idle_loop_suspend,
+ omap1610_idle_loop_suspend_sz);
+ omap_sram_suspend = omap_sram_push(omap1610_cpu_suspend,
+ omap1610_cpu_suspend_sz);
+ }
+
+ if (omap_sram_idle == NULL || omap_sram_suspend == NULL) {
+ printk(KERN_ERR "PM not initialized: Missing SRAM support\n");
+ return -ENODEV;
+ }
+
+ pm_idle = omap_pm_idle;
+
+ if (cpu_is_omap730())
+ setup_irq(INT_730_WAKE_UP_REQ, &omap_wakeup_irq);
+ else if (cpu_is_omap16xx())
+ setup_irq(INT_1610_WAKE_UP_REQ, &omap_wakeup_irq);
+
+#if 0
+ /* --- BEGIN BOARD-DEPENDENT CODE --- */
+ /* Sleepx mask direction */
+ omap_writew((omap_readw(0xfffb5008) & ~2), 0xfffb5008);
+ /* Unmask sleepx signal */
+ omap_writew((omap_readw(0xfffb5004) & ~2), 0xfffb5004);
+ /* --- END BOARD-DEPENDENT CODE --- */
+#endif
+
+ /* Program new power ramp-up time
+ * (0 for most boards since we don't lower voltage when in deep sleep)
+ */
+ omap_writew(ULPD_SETUP_ANALOG_CELL_3_VAL, ULPD_SETUP_ANALOG_CELL_3);
+
+ /* Setup ULPD POWER_CTRL_REG - enter deep sleep whenever possible */
+ omap_writew(ULPD_POWER_CTRL_REG_VAL, ULPD_POWER_CTRL);
+
+ /* Configure IDLECT3 */
+ if (cpu_is_omap730())
+ omap_writel(OMAP730_IDLECT3_VAL, OMAP730_IDLECT3);
+ else if (cpu_is_omap16xx())
+ omap_writel(OMAP1610_IDLECT3_VAL, OMAP1610_IDLECT3);
+
+ pm_set_ops(&omap_pm_ops);
+
+#if defined(DEBUG) && defined(CONFIG_PROC_FS)
+ omap_pm_init_proc();
+#endif
+
+ subsys_create_file(&power_subsys, &sleep_while_idle_attr);
+
+ if (cpu_is_omap16xx()) {
+ /* configure LOW_PWR pin */
+ omap_cfg_reg(T20_1610_LOW_PWR);
+ }
+
+ return 0;
+}
+__initcall(omap_pm_init);
#include <asm/arch/pm.h>
#endif
-static struct clk * uart1_ck = NULL;
-static struct clk * uart2_ck = NULL;
-static struct clk * uart3_ck = NULL;
+static struct clk * uart1_ck;
+static struct clk * uart2_ck;
+static struct clk * uart3_ck;
static inline unsigned int omap_serial_in(struct plat_serial8250_port *up,
int offset)
/*
- * linux/arch/arm/plat-omap/sleep.S
+ * linux/arch/arm/mach-omap1/sleep.S
*
* Low-level OMAP730/1510/1610 sleep/wakeUp support
*
mcr p15, 0, r0, c7, c10, 4
nop
- @ load base address of Traffic Controller
+ @ Load base address of Traffic Controller
mov r6, #TCMIF_ASM_BASE & 0xff000000
orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000
orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00
- @ prepare to put SDRAM into self-refresh manually
+ @ Prepare to put SDRAM into self-refresh manually
ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
orr r9, r7, #SELF_REFRESH_MODE & 0xff000000
orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff
str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
- @ prepare to put EMIFS to Sleep
+ @ Prepare to put EMIFS to Sleep
ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff
str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
- @ load base address of ARM_IDLECT1 and ARM_IDLECT2
+ @ Load base address of ARM_IDLECT1 and ARM_IDLECT2
mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000
orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
- @ turn off clock domains
- @ do not disable PERCK (0x04)
+ @ Turn off clock domains
+ @ Do not disable PERCK (0x04)
mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff
orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00
strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
- @ request ARM idle
+ @ Request ARM idle
mov r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff
orr r3, r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff00
strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
- @ disable instruction cache
- mrc p15, 0, r9, c1, c0, 0
- bic r2, r9, #0x1000
- mcr p15, 0, r2, c1, c0, 0
- nop
-
/*
* Let's wait for the next wake up event to wake us up. r0 can't be
* used here because r0 holds ARM_IDLECT1
*/
mov r2, #0
mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt
+
+ @ Errata (HEL3SU467, section 1.4.4) specifies nop-instructions
+ @ according to this formula:
+ @ 2 + (4*DPLL_MULT)/DPLL_DIV/ARMDIV
+ @ Max DPLL_MULT = 18
+ @ DPLL_DIV = 1
+ @ ARMDIV = 1
+ @ => 74 nop-instructions
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop @10
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop @20
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop @30
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop @40
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop @50
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop @60
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop @70
+ nop
+ nop
+ nop
+ nop @74
/*
* omap1610_cpu_suspend()'s resume point.
*
* It will just start executing here, so we'll restore stuff from the
* stack.
*/
- @ re-enable Icache
- mcr p15, 0, r9, c1, c0, 0
-
- @ reset the ARM_IDLECT1 and ARM_IDLECT2.
+ @ Restore the ARM_IDLECT1 and ARM_IDLECT2.
strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
- @ restore regs and return
+ @ Restore regs and return
ldmfd sp!, {r0 - r12, pc}
ENTRY(omap1610_cpu_suspend_sz)
struct sys_timer omap_timer;
-#ifdef CONFIG_OMAP_MPU_TIMER
-
/*
* ---------------------------------------------------------------------------
* MPU timer
return cycles_2_ns(ticks64);
}
-#endif /* CONFIG_OMAP_MPU_TIMER */
-
-#ifdef CONFIG_OMAP_32K_TIMER
-
-#ifdef CONFIG_ARCH_OMAP15XX
-#error OMAP 32KHz timer does not currently work on 15XX!
-#endif
-
-/*
- * ---------------------------------------------------------------------------
- * 32KHz OS timer
- *
- * This currently works only on 16xx, as 1510 does not have the continuous
- * 32KHz synchronous timer. The 32KHz synchronous timer is used to keep track
- * of time in addition to the 32KHz OS timer. Using only the 32KHz OS timer
- * on 1510 would be possible, but the timer would not be as accurate as
- * with the 32KHz synchronized timer.
- * ---------------------------------------------------------------------------
- */
-#define OMAP_32K_TIMER_BASE 0xfffb9000
-#define OMAP_32K_TIMER_CR 0x08
-#define OMAP_32K_TIMER_TVR 0x00
-#define OMAP_32K_TIMER_TCR 0x04
-
-#define OMAP_32K_TICKS_PER_HZ (32768 / HZ)
-
-/*
- * TRM says 1 / HZ = ( TVR + 1) / 32768, so TRV = (32768 / HZ) - 1
- * so with HZ = 100, TVR = 327.68.
- */
-#define OMAP_32K_TIMER_TICK_PERIOD ((32768 / HZ) - 1)
-#define TIMER_32K_SYNCHRONIZED 0xfffbc410
-
-#define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \
- (((nr_jiffies) * (clock_rate)) / HZ)
-
-static inline void omap_32k_timer_write(int val, int reg)
-{
- omap_writew(val, reg + OMAP_32K_TIMER_BASE);
-}
-
-static inline unsigned long omap_32k_timer_read(int reg)
-{
- return omap_readl(reg + OMAP_32K_TIMER_BASE) & 0xffffff;
-}
-
-/*
- * The 32KHz synchronized timer is an additional timer on 16xx.
- * It is always running.
- */
-static inline unsigned long omap_32k_sync_timer_read(void)
-{
- return omap_readl(TIMER_32K_SYNCHRONIZED);
-}
-
-static inline void omap_32k_timer_start(unsigned long load_val)
-{
- omap_32k_timer_write(load_val, OMAP_32K_TIMER_TVR);
- omap_32k_timer_write(0x0f, OMAP_32K_TIMER_CR);
-}
-
-static inline void omap_32k_timer_stop(void)
-{
- omap_32k_timer_write(0x0, OMAP_32K_TIMER_CR);
-}
-
-/*
- * Rounds down to nearest usec. Note that this will overflow for larger values.
- */
-static inline unsigned long omap_32k_ticks_to_usecs(unsigned long ticks_32k)
-{
- return (ticks_32k * 5*5*5*5*5*5) >> 9;
-}
-
-/*
- * Rounds down to nearest nsec.
- */
-static inline unsigned long long
-omap_32k_ticks_to_nsecs(unsigned long ticks_32k)
-{
- return (unsigned long long) ticks_32k * 1000 * 5*5*5*5*5*5 >> 9;
-}
-
-static unsigned long omap_32k_last_tick = 0;
-
-/*
- * Returns elapsed usecs since last 32k timer interrupt
- */
-static unsigned long omap_32k_timer_gettimeoffset(void)
-{
- unsigned long now = omap_32k_sync_timer_read();
- return omap_32k_ticks_to_usecs(now - omap_32k_last_tick);
-}
-
-/*
- * Returns current time from boot in nsecs. It's OK for this to wrap
- * around for now, as it's just a relative time stamp.
- */
-unsigned long long sched_clock(void)
-{
- return omap_32k_ticks_to_nsecs(omap_32k_sync_timer_read());
-}
-
-/*
- * Timer interrupt for 32KHz timer. When dynamic tick is enabled, this
- * function is also called from other interrupts to remove latency
- * issues with dynamic tick. In the dynamic tick case, we need to lock
- * with irqsave.
- */
-static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
-{
- unsigned long flags;
- unsigned long now;
-
- write_seqlock_irqsave(&xtime_lock, flags);
- now = omap_32k_sync_timer_read();
-
- while (now - omap_32k_last_tick >= OMAP_32K_TICKS_PER_HZ) {
- omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ;
- timer_tick(regs);
- }
-
- /* Restart timer so we don't drift off due to modulo or dynamic tick.
- * By default we program the next timer to be continuous to avoid
- * latencies during high system load. During dynamic tick operation the
- * continuous timer can be overridden from pm_idle to be longer.
- */
- omap_32k_timer_start(omap_32k_last_tick + OMAP_32K_TICKS_PER_HZ - now);
- write_sequnlock_irqrestore(&xtime_lock, flags);
-
- return IRQ_HANDLED;
-}
-
-#ifdef CONFIG_NO_IDLE_HZ
-/*
- * Programs the next timer interrupt needed. Called when dynamic tick is
- * enabled, and to reprogram the ticks to skip from pm_idle. Note that
- * we can keep the timer continuous, and don't need to set it to run in
- * one-shot mode. This is because the timer will get reprogrammed again
- * after next interrupt.
- */
-void omap_32k_timer_reprogram(unsigned long next_tick)
-{
- omap_32k_timer_start(JIFFIES_TO_HW_TICKS(next_tick, 32768) + 1);
-}
-
-static struct irqaction omap_32k_timer_irq;
-extern struct timer_update_handler timer_update;
-
-static int omap_32k_timer_enable_dyn_tick(void)
-{
- /* No need to reprogram timer, just use the next interrupt */
- return 0;
-}
-
-static int omap_32k_timer_disable_dyn_tick(void)
-{
- omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD);
- return 0;
-}
-
-static struct dyn_tick_timer omap_dyn_tick_timer = {
- .enable = omap_32k_timer_enable_dyn_tick,
- .disable = omap_32k_timer_disable_dyn_tick,
- .reprogram = omap_32k_timer_reprogram,
- .handler = omap_32k_timer_interrupt,
-};
-#endif /* CONFIG_NO_IDLE_HZ */
-
-static struct irqaction omap_32k_timer_irq = {
- .name = "32KHz timer",
- .flags = SA_INTERRUPT | SA_TIMER,
- .handler = omap_32k_timer_interrupt,
-};
-
-static __init void omap_init_32k_timer(void)
-{
-
-#ifdef CONFIG_NO_IDLE_HZ
- omap_timer.dyn_tick = &omap_dyn_tick_timer;
-#endif
-
- setup_irq(INT_OS_TIMER, &omap_32k_timer_irq);
- omap_timer.offset = omap_32k_timer_gettimeoffset;
- omap_32k_last_tick = omap_32k_sync_timer_read();
- omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD);
-}
-#endif /* CONFIG_OMAP_32K_TIMER */
/*
* ---------------------------------------------------------------------------
*/
static void __init omap_timer_init(void)
{
-#if defined(CONFIG_OMAP_MPU_TIMER)
omap_init_mpu_timer();
-#elif defined(CONFIG_OMAP_32K_TIMER)
- omap_init_32k_timer();
-#else
-#error No system timer selected in Kconfig!
-#endif
}
struct sys_timer omap_timer = {
config MACH_OMAP_H4
bool "OMAP 2420 H4 board"
depends on ARCH_OMAP2 && ARCH_OMAP24XX
+ select GPIOEXPANDER_OMAP
+config MACH_OMAP_APOLLON
+ bool "OMAP 2420 Apollon board"
+ depends on ARCH_OMAP2 && ARCH_OMAP24XX
#
# Common support
-obj-y := irq.o id.o io.o sram-fn.o clock.o mux.o devices.o serial.o
+obj-y := irq.o id.o io.o sram-fn.o memory.o prcm.o clock.o mux.o devices.o serial.o
obj-$(CONFIG_OMAP_MPU_TIMER) += timer-gp.o
+# Power Management
+obj-$(CONFIG_PM) += pm.o sleep.o
+
# Specific board support
obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o
obj-$(CONFIG_MACH_OMAP_H4) += board-h4.o
+obj-$(CONFIG_MACH_OMAP_APOLLON) += board-apollon.o
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap/omap2/board-apollon.c
+ *
+ * Copyright (C) 2005,2006 Samsung Electronics
+ * Author: Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * Modified from mach-omap/omap2/board-h4.c
+ *
+ * Code for apollon OMAP2 board. Should work on many OMAP2 systems where
+ * the bootloader passes the board-specific data to the kernel.
+ * Do not put any board specific code to this file; create a new machine
+ * type if you need custom low-level initializations.
+ *
+ * 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/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/onenand.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/usb.h>
+#include <asm/arch/board.h>
+#include <asm/arch/common.h>
+#include "prcm-regs.h"
+
+/* LED & Switch macros */
+#define LED0_GPIO13 13
+#define LED1_GPIO14 14
+#define LED2_GPIO15 15
+#define SW_ENTER_GPIO16 16
+#define SW_UP_GPIO17 17
+#define SW_DOWN_GPIO58 58
+
+static struct mtd_partition apollon_partitions[] = {
+ {
+ .name = "X-Loader + U-Boot",
+ .offset = 0,
+ .size = SZ_128K,
+ .mask_flags = MTD_WRITEABLE,
+ },
+ {
+ .name = "params",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_128K,
+ },
+ {
+ .name = "kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_2M,
+ },
+ {
+ .name = "rootfs",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_16M,
+ },
+ {
+ .name = "filesystem00",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_32M,
+ },
+ {
+ .name = "filesystem01",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+static struct flash_platform_data apollon_flash_data = {
+ .parts = apollon_partitions,
+ .nr_parts = ARRAY_SIZE(apollon_partitions),
+};
+
+static struct resource apollon_flash_resource = {
+ .start = APOLLON_CS0_BASE,
+ .end = APOLLON_CS0_BASE + SZ_128K,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device apollon_onenand_device = {
+ .name = "onenand",
+ .id = -1,
+ .dev = {
+ .platform_data = &apollon_flash_data,
+ },
+ .num_resources = ARRAY_SIZE(&apollon_flash_resource),
+ .resource = &apollon_flash_resource,
+};
+
+static struct resource apollon_smc91x_resources[] = {
+ [0] = {
+ .start = APOLLON_ETHR_START, /* Physical */
+ .end = APOLLON_ETHR_START + 0xf,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = OMAP_GPIO_IRQ(APOLLON_ETHR_GPIO_IRQ),
+ .end = OMAP_GPIO_IRQ(APOLLON_ETHR_GPIO_IRQ),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device apollon_smc91x_device = {
+ .name = "smc91x",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(apollon_smc91x_resources),
+ .resource = apollon_smc91x_resources,
+};
+
+static struct platform_device apollon_lcd_device = {
+ .name = "apollon_lcd",
+ .id = -1,
+};
+
+static struct platform_device *apollon_devices[] __initdata = {
+ &apollon_onenand_device,
+ &apollon_smc91x_device,
+ &apollon_lcd_device,
+};
+
+static inline void __init apollon_init_smc91x(void)
+{
+ /* Make sure CS1 timings are correct */
+ GPMC_CONFIG1_1 = 0x00011203;
+ GPMC_CONFIG2_1 = 0x001f1f01;
+ GPMC_CONFIG3_1 = 0x00080803;
+ GPMC_CONFIG4_1 = 0x1c091c09;
+ GPMC_CONFIG5_1 = 0x041f1f1f;
+ GPMC_CONFIG6_1 = 0x000004c4;
+ GPMC_CONFIG7_1 = 0x00000f40 | (APOLLON_CS1_BASE >> 24);
+ udelay(100);
+
+ omap_cfg_reg(W4__24XX_GPIO74);
+ if (omap_request_gpio(APOLLON_ETHR_GPIO_IRQ) < 0) {
+ printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n",
+ APOLLON_ETHR_GPIO_IRQ);
+ return;
+ }
+ omap_set_gpio_direction(APOLLON_ETHR_GPIO_IRQ, 1);
+}
+
+static void __init omap_apollon_init_irq(void)
+{
+ omap2_init_common_hw();
+ omap_init_irq();
+ omap_gpio_init();
+ apollon_init_smc91x();
+}
+
+static struct omap_uart_config apollon_uart_config __initdata = {
+ .enabled_uarts = (1 << 0) | (0 << 1) | (0 << 2),
+};
+
+static struct omap_mmc_config apollon_mmc_config __initdata = {
+ .mmc [0] = {
+ .enabled = 0,
+ .wire4 = 0,
+ .wp_pin = -1,
+ .power_pin = -1,
+ .switch_pin = -1,
+ },
+};
+
+static struct omap_lcd_config apollon_lcd_config __initdata = {
+ .ctrl_name = "internal",
+};
+
+static struct omap_board_config_kernel apollon_config[] = {
+ { OMAP_TAG_UART, &apollon_uart_config },
+ { OMAP_TAG_MMC, &apollon_mmc_config },
+ { OMAP_TAG_LCD, &apollon_lcd_config },
+};
+
+static void __init apollon_led_init(void)
+{
+ /* LED0 - AA10 */
+ omap_cfg_reg(AA10_242X_GPIO13);
+ omap_request_gpio(LED0_GPIO13);
+ omap_set_gpio_direction(LED0_GPIO13, 0);
+ omap_set_gpio_dataout(LED0_GPIO13, 0);
+ /* LED1 - AA6 */
+ omap_cfg_reg(AA6_242X_GPIO14);
+ omap_request_gpio(LED1_GPIO14);
+ omap_set_gpio_direction(LED1_GPIO14, 0);
+ omap_set_gpio_dataout(LED1_GPIO14, 0);
+ /* LED2 - AA4 */
+ omap_cfg_reg(AA4_242X_GPIO15);
+ omap_request_gpio(LED2_GPIO15);
+ omap_set_gpio_direction(LED2_GPIO15, 0);
+ omap_set_gpio_dataout(LED2_GPIO15, 0);
+}
+
+static irqreturn_t apollon_sw_interrupt(int irq, void *ignored, struct pt_regs *regs)
+{
+ static unsigned int led0, led1, led2;
+
+ if (irq == OMAP_GPIO_IRQ(SW_ENTER_GPIO16))
+ omap_set_gpio_dataout(LED0_GPIO13, led0 ^= 1);
+ else if (irq == OMAP_GPIO_IRQ(SW_UP_GPIO17))
+ omap_set_gpio_dataout(LED1_GPIO14, led1 ^= 1);
+ else if (irq == OMAP_GPIO_IRQ(SW_DOWN_GPIO58))
+ omap_set_gpio_dataout(LED2_GPIO15, led2 ^= 1);
+
+ return IRQ_HANDLED;
+}
+
+static void __init apollon_sw_init(void)
+{
+ /* Enter SW - Y11 */
+ omap_cfg_reg(Y11_242X_GPIO16);
+ omap_request_gpio(SW_ENTER_GPIO16);
+ omap_set_gpio_direction(SW_ENTER_GPIO16, 1);
+ /* Up SW - AA12 */
+ omap_cfg_reg(AA12_242X_GPIO17);
+ omap_request_gpio(SW_UP_GPIO17);
+ omap_set_gpio_direction(SW_UP_GPIO17, 1);
+ /* Down SW - AA8 */
+ omap_cfg_reg(AA8_242X_GPIO58);
+ omap_request_gpio(SW_DOWN_GPIO58);
+ omap_set_gpio_direction(SW_DOWN_GPIO58, 1);
+
+ set_irq_type(OMAP_GPIO_IRQ(SW_ENTER_GPIO16), IRQT_RISING);
+ if (request_irq(OMAP_GPIO_IRQ(SW_ENTER_GPIO16), &apollon_sw_interrupt,
+ SA_SHIRQ, "enter sw",
+ &apollon_sw_interrupt))
+ return;
+ set_irq_type(OMAP_GPIO_IRQ(SW_UP_GPIO17), IRQT_RISING);
+ if (request_irq(OMAP_GPIO_IRQ(SW_UP_GPIO17), &apollon_sw_interrupt,
+ SA_SHIRQ, "up sw",
+ &apollon_sw_interrupt))
+ return;
+ set_irq_type(OMAP_GPIO_IRQ(SW_DOWN_GPIO58), IRQT_RISING);
+ if (request_irq(OMAP_GPIO_IRQ(SW_DOWN_GPIO58), &apollon_sw_interrupt,
+ SA_SHIRQ, "down sw",
+ &apollon_sw_interrupt))
+ return;
+}
+
+static void __init omap_apollon_init(void)
+{
+ apollon_led_init();
+ apollon_sw_init();
+
+ /* REVISIT: where's the correct place */
+ omap_cfg_reg(W19_24XX_SYS_NIRQ);
+
+ /*
+ * Make sure the serial ports are muxed on at this point.
+ * You have to mux them off in device drivers later on
+ * if not needed.
+ */
+ platform_add_devices(apollon_devices, ARRAY_SIZE(apollon_devices));
+ omap_board_config = apollon_config;
+ omap_board_config_size = ARRAY_SIZE(apollon_config);
+ omap_serial_init();
+}
+
+static void __init omap_apollon_map_io(void)
+{
+ omap2_map_common_io();
+}
+
+MACHINE_START(OMAP_APOLLON, "OMAP24xx Apollon")
+ /* Maintainer: Kyungmin Park <kyungmin.park@samsung.com> */
+ .phys_io = 0x48000000,
+ .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .boot_params = 0x80000100,
+ .map_io = omap_apollon_map_io,
+ .init_irq = omap_apollon_init_irq,
+ .init_machine = omap_apollon_init,
+ .timer = &omap_timer,
+MACHINE_END
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/input.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/flash.h>
#include <asm/arch/gpio.h>
+#include <asm/arch/gpioexpander.h>
#include <asm/arch/mux.h>
#include <asm/arch/usb.h>
+#include <asm/arch/irda.h>
#include <asm/arch/board.h>
#include <asm/arch/common.h>
-#include <asm/arch/prcm.h>
+#include <asm/arch/keypad.h>
+#include <asm/arch/menelaus.h>
+#include <asm/arch/dma.h>
+#include "prcm-regs.h"
#include <asm/io.h>
#include <asm/delay.h>
+static unsigned int row_gpios[6] = { 88, 89, 124, 11, 6, 96 };
+static unsigned int col_gpios[7] = { 90, 91, 100, 36, 12, 97, 98 };
+
+static int h4_keymap[] = {
+ KEY(0, 0, KEY_LEFT),
+ KEY(0, 1, KEY_RIGHT),
+ KEY(0, 2, KEY_A),
+ KEY(0, 3, KEY_B),
+ KEY(0, 4, KEY_C),
+ KEY(1, 0, KEY_DOWN),
+ KEY(1, 1, KEY_UP),
+ KEY(1, 2, KEY_E),
+ KEY(1, 3, KEY_F),
+ KEY(1, 4, KEY_G),
+ KEY(2, 0, KEY_ENTER),
+ KEY(2, 1, KEY_I),
+ KEY(2, 2, KEY_J),
+ KEY(2, 3, KEY_K),
+ KEY(2, 4, KEY_3),
+ KEY(3, 0, KEY_M),
+ KEY(3, 1, KEY_N),
+ KEY(3, 2, KEY_O),
+ KEY(3, 3, KEY_P),
+ KEY(3, 4, KEY_Q),
+ KEY(4, 0, KEY_R),
+ KEY(4, 1, KEY_4),
+ KEY(4, 2, KEY_T),
+ KEY(4, 3, KEY_U),
+ KEY(4, 4, KEY_ENTER),
+ KEY(5, 0, KEY_V),
+ KEY(5, 1, KEY_W),
+ KEY(5, 2, KEY_L),
+ KEY(5, 3, KEY_S),
+ KEY(5, 4, KEY_ENTER),
+ 0
+};
+
static struct mtd_partition h4_partitions[] = {
/* bootloader (U-Boot, etc) in first sector */
{
.resource = h4_smc91x_resources,
};
+/* Select between the IrDA and aGPS module
+ */
+static int h4_select_irda(struct device *dev, int state)
+{
+ unsigned char expa;
+ int err = 0;
+
+ if ((err = read_gpio_expa(&expa, 0x21))) {
+ printk(KERN_ERR "Error reading from I/O expander\n");
+ return err;
+ }
+
+ /* 'P6' enable/disable IRDA_TX and IRDA_RX */
+ if (state & IR_SEL) { /* IrDa */
+ if ((err = write_gpio_expa(expa | 0x01, 0x21))) {
+ printk(KERN_ERR "Error writing to I/O expander\n");
+ return err;
+ }
+ } else {
+ if ((err = write_gpio_expa(expa & ~0x01, 0x21))) {
+ printk(KERN_ERR "Error writing to I/O expander\n");
+ return err;
+ }
+ }
+ return err;
+}
+
+static void set_trans_mode(void *data)
+{
+ int *mode = data;
+ unsigned char expa;
+ int err = 0;
+
+ if ((err = read_gpio_expa(&expa, 0x20)) != 0) {
+ printk(KERN_ERR "Error reading from I/O expander\n");
+ }
+
+ expa &= ~0x01;
+
+ if (!(*mode & IR_SIRMODE)) { /* MIR/FIR */
+ expa |= 0x01;
+ }
+
+ if ((err = write_gpio_expa(expa, 0x20)) != 0) {
+ printk(KERN_ERR "Error writing to I/O expander\n");
+ }
+}
+
+static int h4_transceiver_mode(struct device *dev, int mode)
+{
+ struct omap_irda_config *irda_config = dev->platform_data;
+
+ cancel_delayed_work(&irda_config->gpio_expa);
+ PREPARE_WORK(&irda_config->gpio_expa, set_trans_mode, &mode);
+ schedule_work(&irda_config->gpio_expa);
+
+ return 0;
+}
+
+static struct omap_irda_config h4_irda_data = {
+ .transceiver_cap = IR_SIRMODE | IR_MIRMODE | IR_FIRMODE,
+ .transceiver_mode = h4_transceiver_mode,
+ .select_irda = h4_select_irda,
+ .rx_channel = OMAP24XX_DMA_UART3_RX,
+ .tx_channel = OMAP24XX_DMA_UART3_TX,
+ .dest_start = OMAP_UART3_BASE,
+ .src_start = OMAP_UART3_BASE,
+ .tx_trigger = OMAP24XX_DMA_UART3_TX,
+ .rx_trigger = OMAP24XX_DMA_UART3_RX,
+};
+
+static struct resource h4_irda_resources[] = {
+ [0] = {
+ .start = INT_24XX_UART3_IRQ,
+ .end = INT_24XX_UART3_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device h4_irda_device = {
+ .name = "omapirda",
+ .id = -1,
+ .dev = {
+ .platform_data = &h4_irda_data,
+ },
+ .num_resources = 1,
+ .resource = h4_irda_resources,
+};
+
+static struct omap_kp_platform_data h4_kp_data = {
+ .rows = 6,
+ .cols = 7,
+ .keymap = h4_keymap,
+ .rep = 1,
+ .row_gpios = row_gpios,
+ .col_gpios = col_gpios,
+};
+
+static struct platform_device h4_kp_device = {
+ .name = "omap-keypad",
+ .id = -1,
+ .dev = {
+ .platform_data = &h4_kp_data,
+ },
+};
+
+static struct platform_device h4_lcd_device = {
+ .name = "lcd_h4",
+ .id = -1,
+};
+
static struct platform_device *h4_devices[] __initdata = {
&h4_smc91x_device,
&h4_flash_device,
+ &h4_irda_device,
+ &h4_kp_device,
+ &h4_lcd_device,
};
static inline void __init h4_init_smc91x(void)
};
static struct omap_lcd_config h4_lcd_config __initdata = {
- .panel_name = "h4",
.ctrl_name = "internal",
};
* You have to mux them off in device drivers later on
* if not needed.
*/
+#if defined(CONFIG_OMAP_IR) || defined(CONFIG_OMAP_IR_MODULE)
+ omap_cfg_reg(K15_24XX_UART3_TX);
+ omap_cfg_reg(K14_24XX_UART3_RX);
+#endif
+
+#if defined(CONFIG_KEYBOARD_OMAP) || defined(CONFIG_KEYBOARD_OMAP_MODULE)
+ if (omap_has_menelaus()) {
+ row_gpios[5] = 0;
+ col_gpios[2] = 15;
+ col_gpios[6] = 18;
+ }
+#endif
+
platform_add_devices(h4_devices, ARRAY_SIZE(h4_devices));
omap_board_config = h4_config;
omap_board_config_size = ARRAY_SIZE(h4_config);
#include <asm/arch/clock.h>
#include <asm/arch/sram.h>
-#include <asm/arch/prcm.h>
+#include "prcm-regs.h"
+#include "memory.h"
#include "clock.h"
//#define DOWN_VARIABLE_DPLL 1 /* Experimental */
static struct prcm_config *curr_prcm_set;
-static struct memory_timings mem_timings;
static u32 curr_perf_level = PRCM_FULL_SPEED;
/*-------------------------------------------------------------------------
static u32 omap2_get_dpll_rate(struct clk * tclk)
{
- int dpll_clk, dpll_mult, dpll_div, amult;
+ long long dpll_clk;
+ int dpll_mult, dpll_div, amult;
dpll_mult = (CM_CLKSEL1_PLL >> 12) & 0x03ff; /* 10 bits */
dpll_div = (CM_CLKSEL1_PLL >> 8) & 0x0f; /* 4 bits */
- dpll_clk = (tclk->parent->rate * dpll_mult) / (dpll_div + 1);
+ dpll_clk = (long long)tclk->parent->rate * dpll_mult;
+ do_div(dpll_clk, dpll_div + 1);
amult = CM_CLKSEL2_PLL & 0x3;
dpll_clk *= amult;
return 0;
}
-static void omap2_init_memory_params(u32 force_lock_to_unlock_mode)
-{
- unsigned long dll_cnt;
- u32 fast_dll = 0;
-
- mem_timings.m_type = !((SDRC_MR_0 & 0x3) == 0x1); /* DDR = 1, SDR = 0 */
-
- /* 2422 es2.05 and beyond has a single SIP DDR instead of 2 like others.
- * In the case of 2422, its ok to use CS1 instead of CS0.
- */
-
-#if 0 /* FIXME: Enable after 24xx cpu detection works */
- ctype = get_cpu_type();
- if (cpu_is_omap2422())
- mem_timings.base_cs = 1;
- else
-#endif
- mem_timings.base_cs = 0;
-
- if (mem_timings.m_type != M_DDR)
- return;
-
- /* With DDR we need to determine the low frequency DLL value */
- if (((mem_timings.fast_dll_ctrl & (1 << 2)) == M_LOCK_CTRL))
- mem_timings.dll_mode = M_UNLOCK;
- else
- mem_timings.dll_mode = M_LOCK;
-
- if (mem_timings.base_cs == 0) {
- fast_dll = SDRC_DLLA_CTRL;
- dll_cnt = SDRC_DLLA_STATUS & 0xff00;
- } else {
- fast_dll = SDRC_DLLB_CTRL;
- dll_cnt = SDRC_DLLB_STATUS & 0xff00;
- }
- if (force_lock_to_unlock_mode) {
- fast_dll &= ~0xff00;
- fast_dll |= dll_cnt; /* Current lock mode */
- }
- mem_timings.fast_dll_ctrl = fast_dll;
-
- /* No disruptions, DDR will be offline & C-ABI not followed */
- omap2_sram_ddr_init(&mem_timings.slow_dll_ctrl,
- mem_timings.fast_dll_ctrl,
- mem_timings.base_cs,
- force_lock_to_unlock_mode);
- mem_timings.slow_dll_ctrl &= 0xff00; /* Keep lock value */
-
- /* Turn status into unlock ctrl */
- mem_timings.slow_dll_ctrl |=
- ((mem_timings.fast_dll_ctrl & 0xF) | (1 << 2));
-
- /* 90 degree phase for anything below 133Mhz */
- mem_timings.slow_dll_ctrl |= (1 << 1);
-}
-
static u32 omap2_reprogram_sdrc(u32 level, u32 force)
{
+ u32 slow_dll_ctrl, fast_dll_ctrl, m_type;
u32 prev = curr_perf_level, flags;
if ((curr_perf_level == level) && !force)
return prev;
+ m_type = omap2_memory_get_type();
+ slow_dll_ctrl = omap2_memory_get_slow_dll_ctrl();
+ fast_dll_ctrl = omap2_memory_get_fast_dll_ctrl();
+
if (level == PRCM_HALF_SPEED) {
local_irq_save(flags);
PRCM_VOLTSETUP = 0xffff;
omap2_sram_reprogram_sdrc(PRCM_HALF_SPEED,
- mem_timings.slow_dll_ctrl,
- mem_timings.m_type);
+ slow_dll_ctrl, m_type);
curr_perf_level = PRCM_HALF_SPEED;
local_irq_restore(flags);
}
local_irq_save(flags);
PRCM_VOLTSETUP = 0xffff;
omap2_sram_reprogram_sdrc(PRCM_FULL_SPEED,
- mem_timings.fast_dll_ctrl,
- mem_timings.m_type);
+ fast_dll_ctrl, m_type);
curr_perf_level = PRCM_FULL_SPEED;
local_irq_restore(flags);
}
case 13: /* dss2 */
mask = 0x1; break;
case 25: /* usb */
- mask = 0xf; break;
+ mask = 0x7; break;
}
}
#define RATE_IN_242X (1 << 0)
#define RATE_IN_243X (1 << 1)
-/* Memory timings */
-#define M_DDR 1
-#define M_LOCK_CTRL (1 << 2)
-#define M_UNLOCK 0
-#define M_LOCK 1
-
-struct memory_timings {
- u32 m_type; /* ddr = 1, sdr = 0 */
- u32 dll_mode; /* use lock mode = 1, unlock mode = 0 */
- u32 slow_dll_ctrl; /* unlock mode, dll value for slow speed */
- u32 fast_dll_ctrl; /* unlock mode, dll value for fast speed */
- u32 base_cs; /* base chip select to use for calculations */
-};
-
/* Key dividers which make up a PRCM set. Ratio's for a PRCM are mandated.
* xtal_speed, dpll_speed, mpu_speed, CM_CLKSEL_MPU,CM_CLKSEL_DSP
* CM_CLKSEL_GFX, CM_CLKSEL1_CORE, CM_CLKSEL1_PLL CM_CLKSEL2_PLL, CM_CLKSEL_MDM
.recalc = &omap2_clksel_recalc,
};
+static struct clk emul_ck = {
+ .name = "emul_ck",
+ .parent = &func_54m_ck,
+ .flags = CLOCK_IN_OMAP242X,
+ .enable_reg = (void __iomem *)&PRCM_CLKEMUL_CTRL,
+ .enable_bit = 0,
+ .recalc = &omap2_propagate_rate,
+
+};
+
/*
* MPU clock domain
* Clocks:
};
static struct clk i2c2_ick = {
- .name = "i2c2_ick",
+ .name = "i2c_ick",
+ .id = 2,
.parent = &l4_ck,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
.enable_reg = (void __iomem *)&CM_ICLKEN1_CORE,
};
static struct clk i2c2_fck = {
- .name = "i2c2_fck",
+ .name = "i2c_fck",
+ .id = 2,
.parent = &func_12m_ck,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
.enable_reg = (void __iomem *)&CM_FCLKEN1_CORE,
};
static struct clk i2c1_ick = {
- .name = "i2c1_ick",
+ .name = "i2c_ick",
+ .id = 1,
.parent = &l4_ck,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
.enable_reg = (void __iomem *)&CM_ICLKEN1_CORE,
};
static struct clk i2c1_fck = {
- .name = "i2c1_fck",
+ .name = "i2c_fck",
+ .id = 1,
.parent = &func_12m_ck,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
.enable_reg = (void __iomem *)&CM_FCLKEN1_CORE,
&wdt1_osc_ck,
&sys_clkout,
&sys_clkout2,
+ &emul_ck,
/* mpu domain clocks */
&mpu_ck,
/* dsp domain clocks */
#endif
+#if defined(CONFIG_OMAP_STI)
+
+#define OMAP2_STI_BASE IO_ADDRESS(0x48068000)
+#define OMAP2_STI_CHANNEL_BASE 0x54000000
+#define OMAP2_STI_IRQ 4
+
+static struct resource sti_resources[] = {
+ {
+ .start = OMAP2_STI_BASE,
+ .end = OMAP2_STI_BASE + 0x7ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = OMAP2_STI_CHANNEL_BASE,
+ .end = OMAP2_STI_CHANNEL_BASE + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = OMAP2_STI_IRQ,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device sti_device = {
+ .name = "sti",
+ .id = -1,
+ .dev = {
+ .release = omap_nop_release,
+ },
+ .num_resources = ARRAY_SIZE(sti_resources),
+ .resource = sti_resources,
+};
+
+static inline void omap_init_sti(void)
+{
+ platform_device_register(&sti_device);
+}
+#else
+static inline void omap_init_sti(void) {}
+#endif
+
/*-------------------------------------------------------------------------*/
static int __init omap2_init_devices(void)
* in alphabetical order so they're easier to sort through.
*/
omap_init_i2c();
+ omap_init_sti();
return 0;
}
#include <linux/kernel.h>
#include <linux/init.h>
-#include <asm/mach/map.h>
+#include <asm/tlb.h>
#include <asm/io.h>
+
+#include <asm/mach/map.h>
+
#include <asm/arch/mux.h>
+#include <asm/arch/omapfb.h>
extern void omap_sram_init(void);
extern int omap2_clk_init(void);
}
};
-void __init omap_map_common_io(void)
+void __init omap2_map_common_io(void)
{
iotable_init(omap2_io_desc, ARRAY_SIZE(omap2_io_desc));
+
+ /* Normally devicemaps_init() would flush caches and tlb after
+ * mdesc->map_io(), but we must also do it here because of the CPU
+ * revision check below.
+ */
+ local_flush_tlb_all();
+ flush_cache_all();
+
omap2_check_revision();
omap_sram_init();
+ omapfb_reserve_mem();
+}
+
+void __init omap2_init_common_hw(void)
+{
omap2_mux_init();
omap2_clk_init();
}
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/memory.c
+ *
+ * Memory timing related functions for OMAP24XX
+ *
+ * Copyright (C) 2005 Texas Instruments Inc.
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * Copyright (C) 2005 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/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+
+#include <asm/arch/clock.h>
+#include <asm/arch/sram.h>
+
+#include "prcm-regs.h"
+#include "memory.h"
+
+static struct memory_timings mem_timings;
+
+u32 omap2_memory_get_slow_dll_ctrl(void)
+{
+ return mem_timings.slow_dll_ctrl;
+}
+
+u32 omap2_memory_get_fast_dll_ctrl(void)
+{
+ return mem_timings.fast_dll_ctrl;
+}
+
+u32 omap2_memory_get_type(void)
+{
+ return mem_timings.m_type;
+}
+
+void omap2_init_memory_params(u32 force_lock_to_unlock_mode)
+{
+ unsigned long dll_cnt;
+ u32 fast_dll = 0;
+
+ mem_timings.m_type = !((SDRC_MR_0 & 0x3) == 0x1); /* DDR = 1, SDR = 0 */
+
+ /* 2422 es2.05 and beyond has a single SIP DDR instead of 2 like others.
+ * In the case of 2422, its ok to use CS1 instead of CS0.
+ */
+ if (cpu_is_omap2422())
+ mem_timings.base_cs = 1;
+ else
+ mem_timings.base_cs = 0;
+
+ if (mem_timings.m_type != M_DDR)
+ return;
+
+ /* With DDR we need to determine the low frequency DLL value */
+ if (((mem_timings.fast_dll_ctrl & (1 << 2)) == M_LOCK_CTRL))
+ mem_timings.dll_mode = M_UNLOCK;
+ else
+ mem_timings.dll_mode = M_LOCK;
+
+ if (mem_timings.base_cs == 0) {
+ fast_dll = SDRC_DLLA_CTRL;
+ dll_cnt = SDRC_DLLA_STATUS & 0xff00;
+ } else {
+ fast_dll = SDRC_DLLB_CTRL;
+ dll_cnt = SDRC_DLLB_STATUS & 0xff00;
+ }
+ if (force_lock_to_unlock_mode) {
+ fast_dll &= ~0xff00;
+ fast_dll |= dll_cnt; /* Current lock mode */
+ }
+ /* set fast timings with DLL filter disabled */
+ mem_timings.fast_dll_ctrl = (fast_dll | (3 << 8));
+
+ /* No disruptions, DDR will be offline & C-ABI not followed */
+ omap2_sram_ddr_init(&mem_timings.slow_dll_ctrl,
+ mem_timings.fast_dll_ctrl,
+ mem_timings.base_cs,
+ force_lock_to_unlock_mode);
+ mem_timings.slow_dll_ctrl &= 0xff00; /* Keep lock value */
+
+ /* Turn status into unlock ctrl */
+ mem_timings.slow_dll_ctrl |=
+ ((mem_timings.fast_dll_ctrl & 0xF) | (1 << 2));
+
+ /* 90 degree phase for anything below 133Mhz + disable DLL filter */
+ mem_timings.slow_dll_ctrl |= ((1 << 1) | (3 << 8));
+}
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/memory.h
+ *
+ * Interface for memory timing related functions for OMAP24XX
+ *
+ * Copyright (C) 2005 Texas Instruments Inc.
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * Copyright (C) 2005 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.
+ */
+
+/* Memory timings */
+#define M_DDR 1
+#define M_LOCK_CTRL (1 << 2)
+#define M_UNLOCK 0
+#define M_LOCK 1
+
+struct memory_timings {
+ u32 m_type; /* ddr = 1, sdr = 0 */
+ u32 dll_mode; /* use lock mode = 1, unlock mode = 0 */
+ u32 slow_dll_ctrl; /* unlock mode, dll value for slow speed */
+ u32 fast_dll_ctrl; /* unlock mode, dll value for fast speed */
+ u32 base_cs; /* base chip select to use for calculations */
+};
+
+extern void omap2_init_memory_params(u32 force_lock_to_unlock_mode);
+extern u32 omap2_memory_get_slow_dll_ctrl(void);
+extern u32 omap2_memory_get_fast_dll_ctrl(void);
+extern u32 omap2_memory_get_type(void);
/* Menelaus interrupt */
MUX_CFG_24XX("W19_24XX_SYS_NIRQ", 0x12c, 0, 1, 1, 1)
+/* 24xx clocks */
+MUX_CFG_24XX("W14_24XX_SYS_CLKOUT", 0x137, 0, 1, 1, 1)
+
+/* 24xx McBSP */
+MUX_CFG_24XX("Y15_24XX_MCBSP2_CLKX", 0x124, 1, 1, 0, 1)
+MUX_CFG_24XX("R14_24XX_MCBSP2_FSX", 0x125, 1, 1, 0, 1)
+MUX_CFG_24XX("W15_24XX_MCBSP2_DR", 0x126, 1, 1, 0, 1)
+MUX_CFG_24XX("V15_24XX_MCBSP2_DX", 0x127, 1, 1, 0, 1)
+
/* 24xx GPIO */
+MUX_CFG_24XX("M21_242X_GPIO11", 0x0c9, 3, 1, 1, 1)
+MUX_CFG_24XX("AA10_242X_GPIO13", 0x0e5, 3, 0, 0, 1)
+MUX_CFG_24XX("AA6_242X_GPIO14", 0x0e6, 3, 0, 0, 1)
+MUX_CFG_24XX("AA4_242X_GPIO15", 0x0e7, 3, 0, 0, 1)
+MUX_CFG_24XX("Y11_242X_GPIO16", 0x0e8, 3, 0, 0, 1)
+MUX_CFG_24XX("AA12_242X_GPIO17", 0x0e9, 3, 0, 0, 1)
+MUX_CFG_24XX("AA8_242X_GPIO58", 0x0ea, 3, 0, 0, 1)
MUX_CFG_24XX("Y20_24XX_GPIO60", 0x12c, 3, 0, 0, 1)
+MUX_CFG_24XX("W4__24XX_GPIO74", 0x0f2, 3, 0, 0, 1)
MUX_CFG_24XX("M15_24XX_GPIO92", 0x10a, 3, 0, 0, 1)
+MUX_CFG_24XX("V14_24XX_GPIO117", 0x128, 3, 1, 0, 1)
+
+/* TSC IRQ */
+MUX_CFG_24XX("P20_24XX_TSC_IRQ", 0x108, 0, 0, 0, 1)
+
+/* UART3 */
+MUX_CFG_24XX("K15_24XX_UART3_TX", 0x118, 0, 0, 0, 1)
+MUX_CFG_24XX("K14_24XX_UART3_RX", 0x119, 0, 0, 0, 1)
+
+/* Keypad GPIO*/
+MUX_CFG_24XX("T19_24XX_KBR0", 0x106, 3, 1, 1, 1)
+MUX_CFG_24XX("R19_24XX_KBR1", 0x107, 3, 1, 1, 1)
+MUX_CFG_24XX("V18_24XX_KBR2", 0x139, 3, 1, 1, 1)
+MUX_CFG_24XX("M21_24XX_KBR3", 0xc9, 3, 1, 1, 1)
+MUX_CFG_24XX("E5__24XX_KBR4", 0x138, 3, 1, 1, 1)
+MUX_CFG_24XX("M18_24XX_KBR5", 0x10e, 3, 1, 1, 1)
+MUX_CFG_24XX("R20_24XX_KBC0", 0x108, 3, 0, 0, 1)
+MUX_CFG_24XX("M14_24XX_KBC1", 0x109, 3, 0, 0, 1)
+MUX_CFG_24XX("H19_24XX_KBC2", 0x114, 3, 0, 0, 1)
+MUX_CFG_24XX("V17_24XX_KBC3", 0x135, 3, 0, 0, 1)
+MUX_CFG_24XX("P21_24XX_KBC4", 0xca, 3, 0, 0, 1)
+MUX_CFG_24XX("L14_24XX_KBC5", 0x10f, 3, 0, 0, 1)
+MUX_CFG_24XX("N19_24XX_KBC6", 0x110, 3, 0, 0, 1)
+
+/* 24xx Menelaus Keypad GPIO */
+MUX_CFG_24XX("B3__24XX_KBR5", 0x30, 3, 1, 1, 1)
+MUX_CFG_24XX("AA4_24XX_KBC2", 0xe7, 3, 0, 0, 1)
+MUX_CFG_24XX("B13_24XX_KBC6", 0x110, 3, 0, 0, 1)
};
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/pm.c
+ *
+ * OMAP2 Power Management Routines
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Tony Lindgren <tony@atomide.com>
+ *
+ * Copyright (C) 2005 Texas Instruments, Inc.
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * Based on pm.c for omap1
+ *
+ * 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/pm.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/pm.h>
+#include <linux/interrupt.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+#include <asm/mach/time.h>
+#include <asm/mach/irq.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/irqs.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/sram.h>
+#include <asm/arch/pm.h>
+
+static struct clk *vclk;
+static void (*omap2_sram_idle)(void);
+static void (*omap2_sram_suspend)(int dllctrl, int cpu_rev);
+static void (*saved_idle)(void);
+
+void omap2_pm_idle(void)
+{
+ local_irq_disable();
+ local_fiq_disable();
+ if (need_resched()) {
+ local_fiq_enable();
+ local_irq_enable();
+ return;
+ }
+
+ /*
+ * Since an interrupt may set up a timer, we don't want to
+ * reprogram the hardware timer with interrupts enabled.
+ * Re-enable interrupts only after returning from idle.
+ */
+ timer_dyn_reprogram();
+
+ omap2_sram_idle();
+ local_fiq_enable();
+ local_irq_enable();
+}
+
+static int omap2_pm_prepare(suspend_state_t state)
+{
+ int error = 0;
+
+ /* We cannot sleep in idle until we have resumed */
+ saved_idle = pm_idle;
+ pm_idle = NULL;
+
+ switch (state)
+ {
+ case PM_SUSPEND_STANDBY:
+ case PM_SUSPEND_MEM:
+ break;
+
+ case PM_SUSPEND_DISK:
+ return -ENOTSUPP;
+
+ default:
+ return -EINVAL;
+ }
+
+ return error;
+}
+
+static int omap2_pm_enter(suspend_state_t state)
+{
+ switch (state)
+ {
+ case PM_SUSPEND_STANDBY:
+ case PM_SUSPEND_MEM:
+ /* FIXME: Add suspend */
+ break;
+
+ case PM_SUSPEND_DISK:
+ return -ENOTSUPP;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int omap2_pm_finish(suspend_state_t state)
+{
+ pm_idle = saved_idle;
+ return 0;
+}
+
+static struct pm_ops omap_pm_ops = {
+ .pm_disk_mode = 0,
+ .prepare = omap2_pm_prepare,
+ .enter = omap2_pm_enter,
+ .finish = omap2_pm_finish,
+};
+
+int __init omap2_pm_init(void)
+{
+ printk("Power Management for TI OMAP.\n");
+
+ vclk = clk_get(NULL, "virt_prcm_set");
+ if (IS_ERR(vclk)) {
+ printk(KERN_ERR "Could not get PM vclk\n");
+ return -ENODEV;
+ }
+
+ /*
+ * We copy the assembler sleep/wakeup routines to SRAM.
+ * These routines need to be in SRAM as that's the only
+ * memory the MPU can see when it wakes up.
+ */
+ omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend,
+ omap24xx_idle_loop_suspend_sz);
+
+ omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend,
+ omap24xx_cpu_suspend_sz);
+
+ pm_set_ops(&omap_pm_ops);
+ pm_idle = omap2_pm_idle;
+
+ return 0;
+}
+
+__initcall(omap2_pm_init);
/*
- * prcm.h - Access definations for use in OMAP24XX clock and power management
+ * linux/arch/arm/mach-omap2/prcm-reg.h
+ *
+ * OMAP24XX Power Reset and Clock Management (PRCM) registers
*
* Copyright (C) 2005 Texas Instruments, Inc.
*
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef __ASM_ARM_ARCH_DPM_PRCM_H
-#define __ASM_ARM_ARCH_DPM_PRCM_H
+#ifndef __ARCH_ARM_MACH_OMAP2_PRCM_H
+#define __ARCH_ARM_MACH_OMAP2_PRCM_H
/* SET_PERFORMANCE_LEVEL PARAMETERS */
#define PRCM_HALF_SPEED 1
#define CM_FCLKEN_MDM PRCM_REG32(0xC00)
#define CM_ICLKEN_MDM PRCM_REG32(0xC10)
#define CM_IDLEST_MDM PRCM_REG32(0xC20)
+#define CM_AUTOIDLE_MDM PRCM_REG32(0xC30)
#define CM_CLKSEL_MDM PRCM_REG32(0xC40)
-
-/* FIXME: Move to header for 2430 */
-#define DISP_BASE (OMAP24XX_L4_IO_BASE+0x50000)
+#define CM_CLKSTCTRL_MDM PRCM_REG32(0xC48)
+#define RM_RSTCTRL_MDM PRCM_REG32(0xC50)
+#define RM_RSTST_MDM PRCM_REG32(0xC58)
+#define PM_WKEN_MDM PRCM_REG32(0xCA0)
+#define PM_WKST_MDM PRCM_REG32(0xCB0)
+#define PM_WKDEP_MDM PRCM_REG32(0xCC8)
+#define PM_PWSTCTRL_MDM PRCM_REG32(0xCE0)
+#define PM_PWSTST_MDM PRCM_REG32(0xCE4)
+
+#define OMAP24XX_L4_IO_BASE 0x48000000
+
+#define DISP_BASE (OMAP24XX_L4_IO_BASE + 0x50000)
#define DISP_REG32(offset) __REG32(DISP_BASE + (offset))
-#define GPMC_BASE (OMAP24XX_GPMC_BASE)
-#define GPMC_REG32(offset) __REG32(GPMC_BASE + (offset))
+#define OMAP24XX_GPMC_BASE (L3_24XX_BASE + 0xa000)
+#define GPMC_REG32(offset) __REG32(OMAP24XX_GPMC_BASE + (offset))
-#define GPT1_BASE (OMAP24XX_GPT1)
+/* FIXME: Move these to timer code */
+#define GPT1_BASE (0x48028000)
#define GPT1_REG32(offset) __REG32(GPT1_BASE + (offset))
/* Misc sysconfig */
#define DISPC_SYSCONFIG DISP_REG32(0x410)
-#define SPI_BASE (OMAP24XX_L4_IO_BASE+0x98000)
+#define SPI_BASE (OMAP24XX_L4_IO_BASE + 0x98000)
#define MCSPI1_SYSCONFIG __REG32(SPI_BASE + 0x10)
-#define MCSPI2_SYSCONFIG __REG32(SPI_BASE+0x2000 + 0x10)
-
-//#define DSP_MMU_SYSCONFIG 0x5A000010
-#define CAMERA_MMU_SYSCONFIG __REG32(DISP_BASE+0x2C10)
-//#define IVA_MMU_SYSCONFIG 0x5D000010
-//#define DSP_DMA_SYSCONFIG 0x00FCC02C
-#define CAMERA_DMA_SYSCONFIG __REG32(DISP_BASE+0x282C)
-#define SYSTEM_DMA_SYSCONFIG __REG32(DISP_BASE+0x602C)
+#define MCSPI2_SYSCONFIG __REG32(SPI_BASE + 0x2000 + 0x10)
+#define MCSPI3_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE + 0xb8010)
+
+#define CAMERA_MMU_SYSCONFIG __REG32(DISP_BASE + 0x2C10)
+#define CAMERA_DMA_SYSCONFIG __REG32(DISP_BASE + 0x282C)
+#define SYSTEM_DMA_SYSCONFIG __REG32(DISP_BASE + 0x602C)
#define GPMC_SYSCONFIG GPMC_REG32(0x010)
-#define MAILBOXES_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x94010)
-#define UART1_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x6A054)
-#define UART2_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x6C054)
-#define UART3_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x6E054)
-//#define IVA_SYSCONFIG 0x5C060010
-#define SDRC_SYSCONFIG __REG32(OMAP24XX_SDRC_BASE+0x10)
-#define SMS_SYSCONFIG __REG32(OMAP24XX_SMS_BASE+0x10)
-#define SSI_SYSCONFIG __REG32(DISP_BASE+0x8010)
-//#define VLYNQ_SYSCONFIG 0x67FFFE10
+#define MAILBOXES_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE + 0x94010)
+#define UART1_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE + 0x6A054)
+#define UART2_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE + 0x6C054)
+#define UART3_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE + 0x6E054)
+#define SDRC_SYSCONFIG __REG32(OMAP24XX_SDRC_BASE + 0x10)
+#define OMAP24XX_SMS_BASE (L3_24XX_BASE + 0x8000)
+#define SMS_SYSCONFIG __REG32(OMAP24XX_SMS_BASE + 0x10)
+#define SSI_SYSCONFIG __REG32(DISP_BASE + 0x8010)
/* rkw - good cannidates for PM_ to start what nm was trying */
-#define OMAP24XX_GPT2 (OMAP24XX_L4_IO_BASE+0x2A000)
-#define OMAP24XX_GPT3 (OMAP24XX_L4_IO_BASE+0x78000)
-#define OMAP24XX_GPT4 (OMAP24XX_L4_IO_BASE+0x7A000)
-#define OMAP24XX_GPT5 (OMAP24XX_L4_IO_BASE+0x7C000)
-#define OMAP24XX_GPT6 (OMAP24XX_L4_IO_BASE+0x7E000)
-#define OMAP24XX_GPT7 (OMAP24XX_L4_IO_BASE+0x80000)
-#define OMAP24XX_GPT8 (OMAP24XX_L4_IO_BASE+0x82000)
-#define OMAP24XX_GPT9 (OMAP24XX_L4_IO_BASE+0x84000)
-#define OMAP24XX_GPT10 (OMAP24XX_L4_IO_BASE+0x86000)
-#define OMAP24XX_GPT11 (OMAP24XX_L4_IO_BASE+0x88000)
-#define OMAP24XX_GPT12 (OMAP24XX_L4_IO_BASE+0x8A000)
-
+#define OMAP24XX_GPT2 (OMAP24XX_L4_IO_BASE + 0x2A000)
+#define OMAP24XX_GPT3 (OMAP24XX_L4_IO_BASE + 0x78000)
+#define OMAP24XX_GPT4 (OMAP24XX_L4_IO_BASE + 0x7A000)
+#define OMAP24XX_GPT5 (OMAP24XX_L4_IO_BASE + 0x7C000)
+#define OMAP24XX_GPT6 (OMAP24XX_L4_IO_BASE + 0x7E000)
+#define OMAP24XX_GPT7 (OMAP24XX_L4_IO_BASE + 0x80000)
+#define OMAP24XX_GPT8 (OMAP24XX_L4_IO_BASE + 0x82000)
+#define OMAP24XX_GPT9 (OMAP24XX_L4_IO_BASE + 0x84000)
+#define OMAP24XX_GPT10 (OMAP24XX_L4_IO_BASE + 0x86000)
+#define OMAP24XX_GPT11 (OMAP24XX_L4_IO_BASE + 0x88000)
+#define OMAP24XX_GPT12 (OMAP24XX_L4_IO_BASE + 0x8A000)
+
+/* FIXME: Move these to timer code */
#define GPTIMER1_SYSCONFIG GPT1_REG32(0x010)
#define GPTIMER2_SYSCONFIG __REG32(OMAP24XX_GPT2 + 0x10)
#define GPTIMER3_SYSCONFIG __REG32(OMAP24XX_GPT3 + 0x10)
#define GPTIMER11_SYSCONFIG __REG32(OMAP24XX_GPT11 + 0x10)
#define GPTIMER12_SYSCONFIG __REG32(OMAP24XX_GPT12 + 0x10)
-#define GPIOX_BASE(X) (OMAP24XX_GPIO_BASE+(0x2000*((X)-1)))
+/* FIXME: Move these to gpio code */
+#define OMAP24XX_GPIO_BASE 0x48018000
+#define GPIOX_BASE(X) (OMAP24XX_GPIO_BASE + (0x2000 * ((X) - 1)))
+
+#define GPIO1_SYSCONFIG __REG32((GPIOX_BASE(1) + 0x10))
+#define GPIO2_SYSCONFIG __REG32((GPIOX_BASE(2) + 0x10))
+#define GPIO3_SYSCONFIG __REG32((GPIOX_BASE(3) + 0x10))
+#define GPIO4_SYSCONFIG __REG32((GPIOX_BASE(4) + 0x10))
-#define GPIO1_SYSCONFIG __REG32((GPIOX_BASE(1)+0x10))
-#define GPIO2_SYSCONFIG __REG32((GPIOX_BASE(2)+0x10))
-#define GPIO3_SYSCONFIG __REG32((GPIOX_BASE(3)+0x10))
-#define GPIO4_SYSCONFIG __REG32((GPIOX_BASE(4)+0x10))
+#if defined(CONFIG_ARCH_OMAP243X)
+#define GPIO5_SYSCONFIG __REG32((OMAP24XX_GPIO5_BASE + 0x10))
+#endif
/* GP TIMER 1 */
#define GPTIMER1_TISTAT GPT1_REG32(0x014)
#define GPTIMER1_TCAR2 GPT1_REG32(0x044)
/* rkw -- base fix up please... */
-#define GPTIMER3_TISR __REG32(OMAP24XX_L4_IO_BASE+0x78018)
+#define GPTIMER3_TISR __REG32(OMAP24XX_L4_IO_BASE + 0x78018)
/* SDRC */
-#define SDRC_DLLA_CTRL __REG32(OMAP24XX_SDRC_BASE+0x060)
-#define SDRC_DLLA_STATUS __REG32(OMAP24XX_SDRC_BASE+0x064)
-#define SDRC_DLLB_CTRL __REG32(OMAP24XX_SDRC_BASE+0x068)
-#define SDRC_DLLB_STATUS __REG32(OMAP24XX_SDRC_BASE+0x06C)
-#define SDRC_POWER __REG32(OMAP24XX_SDRC_BASE+0x070)
-#define SDRC_MR_0 __REG32(OMAP24XX_SDRC_BASE+0x084)
+#define SDRC_DLLA_CTRL __REG32(OMAP24XX_SDRC_BASE + 0x060)
+#define SDRC_DLLA_STATUS __REG32(OMAP24XX_SDRC_BASE + 0x064)
+#define SDRC_DLLB_CTRL __REG32(OMAP24XX_SDRC_BASE + 0x068)
+#define SDRC_DLLB_STATUS __REG32(OMAP24XX_SDRC_BASE + 0x06C)
+#define SDRC_POWER __REG32(OMAP24XX_SDRC_BASE + 0x070)
+#define SDRC_MR_0 __REG32(OMAP24XX_SDRC_BASE + 0x084)
/* GPIO 1 */
#define GPIO1_BASE GPIOX_BASE(1)
#define GPIO2_DATAIN GPIO2_REG32(0x038)
#define GPIO2_OE GPIO2_REG32(0x034)
#define GPIO2_DATAOUT GPIO2_REG32(0x03C)
+#define GPIO2_DEBOUNCENABLE GPIO2_REG32(0x050)
+#define GPIO2_DEBOUNCINGTIME GPIO2_REG32(0x054)
/* GPIO 3 */
#define GPIO3_BASE GPIOX_BASE(3)
#define GPIO3_DATAOUT GPIO3_REG32(0x03C)
#define GPIO3_DEBOUNCENABLE GPIO3_REG32(0x050)
#define GPIO3_DEBOUNCINGTIME GPIO3_REG32(0x054)
+#define GPIO3_DEBOUNCENABLE GPIO3_REG32(0x050)
+#define GPIO3_DEBOUNCINGTIME GPIO3_REG32(0x054)
/* GPIO 4 */
#define GPIO4_BASE GPIOX_BASE(4)
#define GPIO4_DEBOUNCENABLE GPIO4_REG32(0x050)
#define GPIO4_DEBOUNCINGTIME GPIO4_REG32(0x054)
+#if defined(CONFIG_ARCH_OMAP243X)
+/* GPIO 5 */
+#define GPIO5_REG32(offset) __REG32((OMAP24XX_GPIO5_BASE + (offset)))
+#define GPIO5_IRQENABLE1 GPIO5_REG32(0x01C)
+#define GPIO5_IRQSTATUS1 GPIO5_REG32(0x018)
+#define GPIO5_IRQENABLE2 GPIO5_REG32(0x02C)
+#define GPIO5_IRQSTATUS2 GPIO5_REG32(0x028)
+#define GPIO5_WAKEUPENABLE GPIO5_REG32(0x020)
+#define GPIO5_RISINGDETECT GPIO5_REG32(0x048)
+#define GPIO5_FALLINGDETECT GPIO5_REG32(0x04C)
+#define GPIO5_DATAIN GPIO5_REG32(0x038)
+#define GPIO5_OE GPIO5_REG32(0x034)
+#define GPIO5_DATAOUT GPIO5_REG32(0x03C)
+#define GPIO5_DEBOUNCENABLE GPIO5_REG32(0x050)
+#define GPIO5_DEBOUNCINGTIME GPIO5_REG32(0x054)
+#endif
/* IO CONFIG */
-#define CONTROL_BASE (OMAP24XX_CTRL_BASE)
-#define CONTROL_REG32(offset) __REG32(CONTROL_BASE + (offset))
+#define OMAP24XX_CTRL_BASE (L4_24XX_BASE)
+#define CONTROL_REG32(offset) __REG32(OMAP24XX_CTRL_BASE + (offset))
#define CONTROL_PADCONF_SPI1_NCS2 CONTROL_REG32(0x104)
#define CONTROL_PADCONF_SYS_XTALOUT CONTROL_REG32(0x134)
#define CONTROL_PADCONF_MCBSP1_DX CONTROL_REG32(0x10C)
#define CONTROL_PADCONF_GPMC_NCS4 CONTROL_REG32(0x090)
#define CONTROL_PADCONF_DSS_D5 CONTROL_REG32(0x0B8)
-#define CONTROL_PADCONF_DSS_D9 CONTROL_REG32(0x0BC)
+#define CONTROL_PADCONF_DSS_D9 CONTROL_REG32(0x0BC) /* 2420 */
#define CONTROL_PADCONF_DSS_D13 CONTROL_REG32(0x0C0)
#define CONTROL_PADCONF_DSS_VSYNC CONTROL_REG32(0x0CC)
+#define CONTROL_PADCONF_SYS_NIRQW0 CONTROL_REG32(0x0BC) /* 2430 */
+#define CONTROL_PADCONF_SSI1_FLAG_TX CONTROL_REG32(0x108) /* 2430 */
/* CONTROL */
#define CONTROL_DEVCONF CONTROL_REG32(0x274)
+#define CONTROL_DEVCONF1 CONTROL_REG32(0x2E8)
/* INTERRUPT CONTROLLER */
-#define INTC_BASE (OMAP24XX_L4_IO_BASE+0xfe000)
+#define INTC_BASE ((L4_24XX_BASE) + 0xfe000)
#define INTC_REG32(offset) __REG32(INTC_BASE + (offset))
#define INTC1_U_BASE INTC_REG32(0x000)
#define INTC_ISR_CLEAR2 INTC_REG32(0x0D4)
#define INTC_SIR_IRQ INTC_REG32(0x040)
#define INTC_CONTROL INTC_REG32(0x048)
-#define INTC_ILR11 INTC_REG32(0x12C)
+#define INTC_ILR11 INTC_REG32(0x12C) /* PRCM on MPU PIC */
+#define INTC_ILR30 INTC_REG32(0x178)
+#define INTC_ILR31 INTC_REG32(0x17C)
#define INTC_ILR32 INTC_REG32(0x180)
-#define INTC_ILR37 INTC_REG32(0x194)
-#define INTC_SYSCONFIG INTC_REG32(0x010)
+#define INTC_ILR37 INTC_REG32(0x194) /* GPIO4 on MPU PIC */
+#define INTC_SYSCONFIG INTC_REG32(0x010) /* GPT1 on MPU PIC */
/* RAM FIREWALL */
#define RAMFW_BASE (0x68005000)
#define GPMC_CONFIG6_0 GPMC_REG32(0x074)
#define GPMC_CONFIG7_0 GPMC_REG32(0x078)
+/* GPMC CS1 */
+#define GPMC_CONFIG1_1 GPMC_REG32(0x090)
+#define GPMC_CONFIG2_1 GPMC_REG32(0x094)
+#define GPMC_CONFIG3_1 GPMC_REG32(0x098)
+#define GPMC_CONFIG4_1 GPMC_REG32(0x09C)
+#define GPMC_CONFIG5_1 GPMC_REG32(0x0a0)
+#define GPMC_CONFIG6_1 GPMC_REG32(0x0a4)
+#define GPMC_CONFIG7_1 GPMC_REG32(0x0a8)
+
+/* GPMC CS3 */
+#define GPMC_CONFIG1_3 GPMC_REG32(0x0F0)
+#define GPMC_CONFIG2_3 GPMC_REG32(0x0F4)
+#define GPMC_CONFIG3_3 GPMC_REG32(0x0F8)
+#define GPMC_CONFIG4_3 GPMC_REG32(0x0FC)
+#define GPMC_CONFIG5_3 GPMC_REG32(0x100)
+#define GPMC_CONFIG6_3 GPMC_REG32(0x104)
+#define GPMC_CONFIG7_3 GPMC_REG32(0x108)
+
/* DSS */
#define DSS_CONTROL DISP_REG32(0x040)
#define DISPC_CONTROL DISP_REG32(0x440)
#define DISPC_DATA_CYCLE2 DISP_REG32(0x5D8)
#define DISPC_DATA_CYCLE3 DISP_REG32(0x5DC)
-/* Wake up define for board */
-#define GPIO97 (1 << 1)
-#define GPIO88 (1 << 24)
+/* HSUSB Suspend */
+#define HSUSB_CTRL __REG8(0x480AC001)
+#define USBOTG_POWER __REG32(0x480AC000)
+
+/* HS MMC */
+#define MMCHS1_SYSCONFIG __REG32(0x4809C010)
+#define MMCHS2_SYSCONFIG __REG32(0x480b4010)
-#endif /* __ASSEMBLER__ */
+#endif /* __ASSEMBLER__ */
#endif
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/prcm.c
+ *
+ * OMAP 24xx Power Reset and Clock Management (PRCM) functions
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ *
+ * Written by Tony Lindgren <tony.lindgren@nokia.com>
+ *
+ * Some pieces of code Copyright (C) 2005 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.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+
+#include "prcm-regs.h"
+
+u32 omap_prcm_get_reset_sources(void)
+{
+ return RM_RSTST_WKUP & 0x7f;
+}
+EXPORT_SYMBOL(omap_prcm_get_reset_sources);
+
+/* Resets clock rates and reboots the system. Only called from system.h */
+void omap_prcm_arch_reset(char mode)
+{
+ u32 rate;
+ struct clk *vclk, *sclk;
+
+ vclk = clk_get(NULL, "virt_prcm_set");
+ sclk = clk_get(NULL, "sys_ck");
+ rate = clk_get_rate(sclk);
+ clk_set_rate(vclk, rate); /* go to bypass for OMAP limitation */
+ RM_RSTCTRL_WKUP |= 2;
+}
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap2/sleep.S
+ *
+ * (C) Copyright 2004
+ * Texas Instruments, <www.ti.com>
+ * Richard Woodruff <r-woodruff2@ti.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/config.h>
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/arch/io.h>
+#include <asm/arch/pm.h>
+
+#define A_32KSYNC_CR_V IO_ADDRESS(OMAP_TIMER32K_BASE+0x10)
+#define A_PRCM_VOLTCTRL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x50)
+#define A_PRCM_CLKCFG_CTRL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x80)
+#define A_CM_CLKEN_PLL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x500)
+#define A_CM_IDLEST_CKGEN_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x520)
+#define A_CM_CLKSEL1_PLL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x540)
+#define A_CM_CLKSEL2_PLL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x544)
+
+#define A_SDRC_DLLA_CTRL_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0x60)
+#define A_SDRC_POWER_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0x70)
+#define A_SDRC_RFR_CTRL_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0xA4)
+#define A_SDRC0_V (0xC0000000)
+#define A_SDRC_MANUAL_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0xA8)
+
+ .text
+
+/*
+ * Forces OMAP into idle state
+ *
+ * omap24xx_idle_loop_suspend() - This bit of code just executes the WFI
+ * for normal idles.
+ *
+ * Note: This code get's copied to internal SRAM at boot. When the OMAP
+ * wakes up it continues execution at the point it went to sleep.
+ */
+ENTRY(omap24xx_idle_loop_suspend)
+ stmfd sp!, {r0, lr} @ save registers on stack
+ mov r0, #0 @ clear for mcr setup
+ mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt
+ ldmfd sp!, {r0, pc} @ restore regs and return
+
+ENTRY(omap24xx_idle_loop_suspend_sz)
+ .word . - omap24xx_idle_loop_suspend
+
+/*
+ * omap242x_cpu_suspend() - Forces OMAP into deep sleep state by completing
+ * SDRC shutdown then ARM shutdown. Upon wake MPU is back on so just restore
+ * SDRC.
+ *
+ * Input:
+ * R0 : DLL ctrl value pre-Sleep
+ * R1 : Processor+Revision
+ * 2420: 0x21 = 242xES1, 0x26 = 242xES2.2
+ * 2430: 0x31 = 2430ES1, 0x32 = 2430ES2
+ *
+ * The if the DPLL is going to AutoIdle. It seems like the DPLL may be back on
+ * when we get called, but the DLL probably isn't. We will wait a bit more in
+ * case the DPLL isn't quite there yet. The code will wait on DLL for DDR even
+ * if in unlocked mode.
+ *
+ * For less than 242x-ES2.2 upon wake from a sleep mode where the external
+ * oscillator was stopped, a timing bug exists where a non-stabilized 12MHz
+ * clock can pass into the PRCM can cause problems at DSP and IVA.
+ * To work around this the code will switch to the 32kHz source prior to sleep.
+ * Post sleep we will shift back to using the DPLL. Apparently,
+ * CM_IDLEST_CLKGEN does not reflect the full clock change so you need to wait
+ * 3x12MHz + 3x32kHz clocks for a full switch.
+ *
+ * The DLL load value is not kept in RETENTION or OFF. It needs to be restored
+ * at wake
+ */
+ENTRY(omap24xx_cpu_suspend)
+ stmfd sp!, {r0 - r12, lr} @ save registers on stack
+ mov r3, #0x0 @ clear for mrc call
+ mcr p15, 0, r3, c7, c10, 4 @ memory barrier, hope SDR/DDR finished
+ nop
+ nop
+ ldr r3, A_SDRC_POWER @ addr of sdrc power
+ ldr r4, [r3] @ value of sdrc power
+ orr r4, r4, #0x40 @ enable self refresh on idle req
+ mov r5, #0x2000 @ set delay (DPLL relock + DLL relock)
+ str r4, [r3] @ make it so
+ mov r2, #0
+ nop
+ mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt
+ nop
+loop:
+ subs r5, r5, #0x1 @ awake, wait just a bit
+ bne loop
+
+ /* The DPLL has on before we take the DDR out of self refresh */
+ bic r4, r4, #0x40 @ now clear self refresh bit.
+ str r4, [r3] @ put vlaue back.
+ ldr r4, A_SDRC0 @ make a clock happen
+ ldr r4, [r4]
+ nop @ start auto refresh only after clk ok
+ movs r0, r0 @ see if DDR or SDR
+ ldrne r1, A_SDRC_DLLA_CTRL_S @ get addr of DLL ctrl
+ strne r0, [r1] @ rewrite DLLA to force DLL reload
+ addne r1, r1, #0x8 @ move to DLLB
+ strne r0, [r1] @ rewrite DLLB to force DLL reload
+
+ mov r5, #0x1000
+loop2:
+ subs r5, r5, #0x1
+ bne loop2
+ /* resume*/
+ ldmfd sp!, {r0 - r12, pc} @ restore regs and return
+
+A_SDRC_POWER:
+ .word A_SDRC_POWER_V
+A_SDRC0:
+ .word A_SDRC0_V
+A_CM_CLKSEL2_PLL_S:
+ .word A_CM_CLKSEL2_PLL_V
+A_CM_CLKEN_PLL:
+ .word A_CM_CLKEN_PLL_V
+A_SDRC_DLLA_CTRL_S:
+ .word A_SDRC_DLLA_CTRL_V
+A_SDRC_MANUAL_S:
+ .word A_SDRC_MANUAL_V
+
+ENTRY(omap24xx_cpu_suspend_sz)
+ .word . - omap24xx_cpu_suspend
+
/*
- * linux/arch/arm/mach-omap1/sram.S
+ * linux/arch/arm/mach-omap2/sram.S
*
* Omap2 specific functions that need to be run in internal SRAM
*
#include <asm/arch/io.h>
#include <asm/hardware.h>
-#include <asm/arch/prcm.h>
+#include "prcm-regs.h"
#define TIMER_32KSYNCT_CR_V IO_ADDRESS(OMAP24XX_32KSYNCT_BASE + 0x010)
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"
+ depends on OMAP_BOOT_TAG
+ default n
+ help
+ Say Y, if you want to have support for input layer reporting
+ of GPIO switches (e.g. cover switches). Your bootloader has to
+ provide information about the switches to the kernel via the
+ ATAG_BOARD mechanism.
+
config OMAP_MUX
bool "OMAP multiplexing support"
depends on ARCH_OMAP
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.
+
choice
prompt "System timer"
default OMAP_MPU_TIMER
config OMAP_32K_TIMER
bool "Use 32KHz timer"
- depends on ARCH_OMAP16XX
+ depends on ARCH_OMAP16XX || ARCH_OMAP24XX
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
support for no tick during idle. The 32KHz timer provides less
intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is
- currently only available for OMAP-16xx.
+ currently only available for OMAP16XX and 24XX.
endchoice
#
# Common support
-obj-y := common.o sram.o sram-fn.o clock.o devices.o dma.o mux.o gpio.o mcbsp.o usb.o
+obj-y := common.o sram.o sram-fn.o clock.o devices.o dma.o mux.o gpio.o mcbsp.o usb.o fb.o
obj-m :=
obj-n :=
obj- :=
+obj-$(CONFIG_OMAP_32K_TIMER) += timer32k.o
+
# OCPI interconnect support for 1710, 1610 and 5912
obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
-# Power Management
-obj-$(CONFIG_PM) += pm.o sleep.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
+# DSP subsystem
+obj-y += dsp/
--- /dev/null
+/*
+ * 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/config.h>
+#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);
#include <linux/string.h>
#include <linux/clk.h>
#include <linux/mutex.h>
+#include <linux/platform_device.h>
#include <asm/io.h>
#include <asm/semaphore.h>
* Standard clock functions defined in include/linux/clk.h
*-------------------------------------------------------------------------*/
+/*
+ * Returns a clock. Note that we first try to use device id on the bus
+ * and clock name. If this fails, we try to use clock name only.
+ */
struct clk * clk_get(struct device *dev, const char *id)
{
struct clk *p, *clk = ERR_PTR(-ENOENT);
+ int idno;
+
+ if (dev == NULL || dev->bus != &platform_bus_type)
+ idno = -1;
+ else
+ idno = to_platform_device(dev)->id;
mutex_lock(&clocks_mutex);
+
list_for_each_entry(p, &clocks, node) {
- if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
+ if (p->id == idno &&
+ strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
clk = p;
break;
}
}
+
+ list_for_each_entry(p, &clocks, node) {
+ if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
+ clk = p;
+ break;
+ }
+ }
+
mutex_unlock(&clocks_mutex);
return clk;
unsigned long flags;
int ret = 0;
+ if (clk == NULL || IS_ERR(clk))
+ return -EINVAL;
+
spin_lock_irqsave(&clockfw_lock, flags);
if (arch_clock->clk_enable)
ret = arch_clock->clk_enable(clk);
{
unsigned long flags;
+ if (clk == NULL || IS_ERR(clk))
+ return;
+
spin_lock_irqsave(&clockfw_lock, flags);
if (arch_clock->clk_disable)
arch_clock->clk_disable(clk);
unsigned long flags;
int ret = 0;
+ if (clk == NULL || IS_ERR(clk))
+ return 0;
+
spin_lock_irqsave(&clockfw_lock, flags);
ret = clk->usecount;
spin_unlock_irqrestore(&clockfw_lock, flags);
unsigned long flags;
unsigned long ret = 0;
+ if (clk == NULL || IS_ERR(clk))
+ return 0;
+
spin_lock_irqsave(&clockfw_lock, flags);
ret = clk->rate;
spin_unlock_irqrestore(&clockfw_lock, flags);
unsigned long flags;
long ret = 0;
+ if (clk == NULL || IS_ERR(clk))
+ return ret;
+
spin_lock_irqsave(&clockfw_lock, flags);
if (arch_clock->clk_round_rate)
ret = arch_clock->clk_round_rate(clk, rate);
int clk_set_rate(struct clk *clk, unsigned long rate)
{
unsigned long flags;
- int ret = 0;
+ int ret = -EINVAL;
+
+ if (clk == NULL || IS_ERR(clk))
+ return ret;
spin_lock_irqsave(&clockfw_lock, flags);
if (arch_clock->clk_set_rate)
int clk_set_parent(struct clk *clk, struct clk *parent)
{
unsigned long flags;
- int ret = 0;
+ int ret = -EINVAL;
+
+ if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent))
+ return ret;
spin_lock_irqsave(&clockfw_lock, flags);
if (arch_clock->clk_set_parent)
unsigned long flags;
struct clk * ret = NULL;
+ if (clk == NULL || IS_ERR(clk))
+ return ret;
+
spin_lock_irqsave(&clockfw_lock, flags);
if (arch_clock->clk_get_parent)
ret = arch_clock->clk_get_parent(clk);
/* Used for clocks that always have same value as the parent clock */
void followparent_recalc(struct clk *clk)
{
+ if (clk == NULL || IS_ERR(clk))
+ return;
+
clk->rate = clk->parent->rate;
}
{
struct clk *clkp;
+ if (tclk == NULL || IS_ERR(tclk))
+ return;
+
list_for_each_entry(clkp, &clocks, node) {
if (likely(clkp->parent != tclk))
continue;
int clk_register(struct clk *clk)
{
+ if (clk == NULL || IS_ERR(clk))
+ return -EINVAL;
+
mutex_lock(&clocks_mutex);
list_add(&clk->node, &clocks);
if (clk->init)
void clk_unregister(struct clk *clk)
{
+ if (clk == NULL || IS_ERR(clk))
+ return;
+
mutex_lock(&clocks_mutex);
list_del(&clk->node);
mutex_unlock(&clocks_mutex);
{
unsigned long flags;
+ if (clk == NULL || IS_ERR(clk))
+ return;
+
spin_lock_irqsave(&clockfw_lock, flags);
if (arch_clock->clk_deny_idle)
arch_clock->clk_deny_idle(clk);
{
unsigned long flags;
+ if (clk == NULL || IS_ERR(clk))
+ return;
+
spin_lock_irqsave(&clockfw_lock, flags);
if (arch_clock->clk_allow_idle)
arch_clock->clk_allow_idle(clk);
return 0;
}
+
+#ifdef 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 /* CONFIG_DEBUG_PROC_FS */
+
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;
--- /dev/null
+/*
+ * 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");
#include <asm/arch/board.h>
#include <asm/arch/mux.h>
#include <asm/arch/gpio.h>
+#include <asm/arch/menelaus.h>
void omap_nop_release(struct device *dev)
static inline void omap_init_i2c(void) {}
#endif
+/*-------------------------------------------------------------------------*/
+#if defined(CONFIG_KEYBOARD_OMAP) || defined(CONFIG_KEYBOARD_OMAP_MODULE)
+
+static void omap_init_kp(void)
+{
+ if (machine_is_omap_h2() || machine_is_omap_h3()) {
+ omap_cfg_reg(F18_1610_KBC0);
+ omap_cfg_reg(D20_1610_KBC1);
+ omap_cfg_reg(D19_1610_KBC2);
+ omap_cfg_reg(E18_1610_KBC3);
+ omap_cfg_reg(C21_1610_KBC4);
+
+ omap_cfg_reg(G18_1610_KBR0);
+ omap_cfg_reg(F19_1610_KBR1);
+ omap_cfg_reg(H14_1610_KBR2);
+ omap_cfg_reg(E20_1610_KBR3);
+ omap_cfg_reg(E19_1610_KBR4);
+ omap_cfg_reg(N19_1610_KBR5);
+ } else if (machine_is_omap_perseus2()) {
+ omap_cfg_reg(E2_730_KBR0);
+ omap_cfg_reg(J7_730_KBR1);
+ omap_cfg_reg(E1_730_KBR2);
+ omap_cfg_reg(F3_730_KBR3);
+ omap_cfg_reg(D2_730_KBR4);
+
+ omap_cfg_reg(C2_730_KBC0);
+ omap_cfg_reg(D3_730_KBC1);
+ omap_cfg_reg(E4_730_KBC2);
+ omap_cfg_reg(F4_730_KBC3);
+ omap_cfg_reg(E3_730_KBC4);
+ } else if (machine_is_omap_h4()) {
+ omap_cfg_reg(T19_24XX_KBR0);
+ omap_cfg_reg(R19_24XX_KBR1);
+ omap_cfg_reg(V18_24XX_KBR2);
+ omap_cfg_reg(M21_24XX_KBR3);
+ omap_cfg_reg(E5__24XX_KBR4);
+ if (omap_has_menelaus()) {
+ omap_cfg_reg(B3__24XX_KBR5);
+ omap_cfg_reg(AA4_24XX_KBC2);
+ omap_cfg_reg(B13_24XX_KBC6);
+ } else {
+ omap_cfg_reg(M18_24XX_KBR5);
+ omap_cfg_reg(H19_24XX_KBC2);
+ omap_cfg_reg(N19_24XX_KBC6);
+ }
+ omap_cfg_reg(R20_24XX_KBC0);
+ omap_cfg_reg(M14_24XX_KBC1);
+ omap_cfg_reg(V17_24XX_KBC3);
+ omap_cfg_reg(P21_24XX_KBC4);
+ omap_cfg_reg(L14_24XX_KBC5);
+ }
+}
+#else
+static inline void omap_init_kp(void) {}
+#endif
+
/*-------------------------------------------------------------------------*/
#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
static inline void omap_init_mmc(void) {}
#endif
+/*-------------------------------------------------------------------------*/
+
+/* Numbering for the SPI-capable controllers when used for SPI:
+ * spi = 1
+ * uwire = 2
+ * mmc1..2 = 3..4
+ * mcbsp1..3 = 5..7
+ */
+
+#if defined(CONFIG_SPI_OMAP_UWIRE) || defined(CONFIG_SPI_OMAP_UWIRE_MODULE)
+
+#define OMAP_UWIRE_BASE 0xfffb3000
+
+static struct resource uwire_resources[] = {
+ {
+ .start = OMAP_UWIRE_BASE,
+ .end = OMAP_UWIRE_BASE + 0x20,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device omap_uwire_device = {
+ .name = "omap_uwire",
+ .id = -1,
+ .dev = {
+ .release = omap_nop_release,
+ },
+ .num_resources = ARRAY_SIZE(uwire_resources),
+ .resource = uwire_resources,
+};
+
+static void omap_init_uwire(void)
+{
+ /* FIXME define and use a boot tag; not all boards will be hooking
+ * up devices to the microwire controller, and multi-board configs
+ * mean that CONFIG_SPI_OMAP_UWIRE may be configured anyway...
+ */
+
+ /* board-specific code must configure chipselects (only a few
+ * are normally used) and SCLK/SDI/SDO (each has two choices).
+ */
+ (void) platform_device_register(&omap_uwire_device);
+}
+#else
+static inline void omap_init_uwire(void) {}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
#if defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE)
#ifdef CONFIG_ARCH_OMAP24XX
static inline void omap_init_rng(void) {}
#endif
-#if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE)
-
-static struct omap_lcd_config omap_fb_conf;
-
-static u64 omap_fb_dma_mask = ~(u32)0;
-
-static struct platform_device omap_fb_device = {
- .name = "omapfb",
- .id = -1,
- .dev = {
- .release = omap_nop_release,
- .dma_mask = &omap_fb_dma_mask,
- .coherent_dma_mask = ~(u32)0,
- .platform_data = &omap_fb_conf,
- },
- .num_resources = 0,
-};
-
-static inline void omap_init_fb(void)
-{
- const struct omap_lcd_config *conf;
-
- conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
- if (conf != NULL)
- omap_fb_conf = *conf;
- platform_device_register(&omap_fb_device);
-}
-
-#else
-
-static inline void omap_init_fb(void) {}
-
-#endif
-
/*
* This gets called after board-specific INIT_MACHINE, and initializes most
* on-chip peripherals accessible on this board (except for few like USB):
/* please keep these calls, and their implementations above,
* in alphabetical order so they're easier to sort through.
*/
- omap_init_fb();
omap_init_i2c();
+ omap_init_kp();
omap_init_mmc();
+ omap_init_uwire();
omap_init_wdt();
omap_init_rng();
omap_writew(w, OMAP1610_DMA_LCD_CTRL);
}
+int omap_lcd_dma_ext_running(void)
+{
+ return lcd_dma.ext_ctrl && lcd_dma.active;
+}
+
/*----------------------------------------------------------------------------*/
static int __init omap_init_dma(void)
EXPORT_SYMBOL(omap_enable_lcd_dma);
EXPORT_SYMBOL(omap_setup_lcd_dma);
EXPORT_SYMBOL(omap_stop_lcd_dma);
+EXPORT_SYMBOL(omap_lcd_dma_ext_running);
EXPORT_SYMBOL(omap_set_lcd_dma_b1);
EXPORT_SYMBOL(omap_set_lcd_dma_single_transfer);
EXPORT_SYMBOL(omap_set_lcd_dma_ext_controller);
}
+/**
+ * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR
+ * @inputmask: current value of idlect mask
+ */
+__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
+{
+ int n;
+
+ /* If ARMXOR cannot be idled this function call is unnecessary */
+ if (!(inputmask & (1 << 1)))
+ return inputmask;
+
+ /* If any active timer is using ARMXOR return modified mask */
+ for (n = 0; dm_timers[n].base; ++n)
+ if (omap_dm_timer_read_reg(&dm_timers[n], OMAP_TIMER_CTRL_REG)&
+ OMAP_TIMER_CTRL_ST) {
+ if (((omap_readl(MOD_CONF_CTRL_1)>>(n*2)) & 0x03) == 0)
+ inputmask &= ~(1 << 1);
+ else
+ inputmask &= ~(1 << 2);
+ }
+
+ return inputmask;
+}
+
+
void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
{
int n = (timer - dm_timers) << 1;
--- /dev/null
+
+config OMAP_DSP
+ tristate "OMAP DSP driver (DSP Gateway)"
+ depends on ARCH_OMAP15XX || ARCH_OMAP16XX
+ help
+ This enables OMAP DSP driver, DSP Gateway.
+
+config OMAP_DSP_MBCMD_VERBOSE
+ bool "Mailbox Command Verbose LOG"
+ depends on OMAP_DSP
+ help
+ This enables kernel log output in the Mailbox command exchanges
+ in the DSP Gateway driver.
+
+config OMAP_DSP_TASK_MULTIOPEN
+ bool "DSP Task Multiopen Capability"
+ depends on OMAP_DSP
+ help
+ This enables DSP tasks to be opened by multiple times at a time.
+ Otherwise, they can be opened only once at a time.
+
+config OMAP_DSP_FBEXPORT
+ bool "Framebuffer export to DSP"
+ depends on OMAP_DSP
+ help
+ This enables to map the frame buffer to DSP.
+ By doing this, DSP can access the frame buffer directly without
+ bothering ARM.
+
--- /dev/null
+#
+# Makefile for the OMAP DSP driver.
+#
+
+# The target object and module list name.
+
+obj-y := dsp_common.o
+
+obj-$(CONFIG_OMAP_DSP) += dsp.o
+
+# Declare multi-part drivers
+
+dsp-objs := dsp_core.o ipbuf.o mblog.o task.o \
+ dsp_ctl_core.o dsp_ctl.o taskwatch.o error.o dsp_mem.o \
+ uaccess_dsp.o
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap/dsp/dsp.h
+ *
+ * Header for OMAP DSP driver
+ *
+ * Copyright (C) 2002-2005 Nokia Corporation
+ *
+ * Written by 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 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
+ *
+ * 2005/06/09: DSP Gateway version 3.3
+ */
+
+#include "hardware_dsp.h"
+#include "dsp_common.h"
+
+#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
+/* idle program will be placed at IDLEPG_BASE. */
+#define IDLEPG_BASE 0xfffe00
+#define IDLEPG_SIZE 0x100
+
+/* 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,
+};
+
+enum arm_dsp_dir {
+ DIR_A2D,
+ DIR_D2A,
+};
+
+/*
+ * INT_D2A_MB value definition
+ * INT_DSP_MAILBOX1: use Mailbox 1 (INT 10) for DSP->ARM mailbox
+ * INT_DSP_MAILBOX2: use Mailbox 2 (INT 11) for DSP->ARM mailbox
+ */
+#define INT_D2A_MB1 INT_DSP_MAILBOX1
+
+/* keep 2 entries for OMAP_DSP_TID_FREE and OMAP_DSP_TID_ANON */
+#define TASKDEV_MAX 254
+
+#define MKLONG(uw,lw) (((unsigned long)(uw)) << 16 | (lw))
+#define MKVIRT(uw,lw) dspword_to_virt(MKLONG((uw), (lw)));
+#define MBCMD(nm) OMAP_DSP_MBCMD_##nm
+
+struct sync_seq {
+ unsigned short da_dsp;
+ unsigned short da_arm;
+ unsigned short ad_dsp;
+ unsigned short ad_arm;
+};
+
+struct mem_sync_struct {
+ struct sync_seq *DARAM;
+ struct sync_seq *SARAM;
+ struct sync_seq *SDRAM;
+};
+
+/* struct mbcmd and struct mbcmd_hw must be compatible */
+struct mbcmd {
+ unsigned short cmd_l:8;
+ unsigned short cmd_h:7;
+ unsigned short seq:1;
+ unsigned short data;
+};
+
+struct mbcmd_hw {
+ unsigned short cmd;
+ unsigned short data;
+};
+
+#define mbcmd_set(mb, h, l, d) \
+ do { \
+ (mb).cmd_h = (h); \
+ (mb).cmd_l = (l); \
+ (mb).data = (d); \
+ } while(0)
+
+struct mb_exarg {
+ unsigned char tid;
+ int argc;
+ unsigned short *argv;
+};
+
+extern void dsp_mb_start(void);
+extern void dsp_mb_stop(void);
+extern int dsp_mb_config(void *p);
+extern int sync_with_dsp(unsigned short *syncwd, unsigned short tid,
+ int try_cnt);
+extern int __mbcmd_send(struct mbcmd *mb);
+extern int __dsp_mbcmd_send(struct mbcmd *mb, struct mb_exarg *arg,
+ int recovery_flag);
+#define dsp_mbcmd_send(mb) __dsp_mbcmd_send(mb, NULL, 0)
+#define dsp_mbcmd_send_exarg(mb, arg) __dsp_mbcmd_send(mb, arg, 0)
+extern int __dsp_mbcmd_send_and_wait(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(mb, NULL, q)
+#define dsp_mbcmd_send_and_wait_exarg(mb, arg, q) \
+ __dsp_mbcmd_send_and_wait(mb, arg, q)
+int __dsp_mbsend(unsigned char cmdh, unsigned char cmdl, unsigned short data,
+ int recovery_flag);
+#define dsp_mbsend(cmdh, cmdl, data) \
+ __dsp_mbsend(cmdh, cmdl, data, 0)
+#define dsp_mbsend_recovery(cmdh, cmdl, data) \
+ __dsp_mbsend(cmdh, cmdl, data, 1)
+
+extern void ipbuf_start(void);
+extern void ipbuf_stop(void);
+extern int ipbuf_config(unsigned short ln, unsigned short lsz, void *base);
+extern int ipbuf_sys_config(void *p, enum arm_dsp_dir dir);
+extern int ipbuf_p_validate(void *p, enum arm_dsp_dir dir);
+extern unsigned short get_free_ipbuf(unsigned char tid);
+extern void unuse_ipbuf_nowait(unsigned short bid);
+extern void unuse_ipbuf(unsigned short bid);
+extern void release_ipbuf(unsigned short bid);
+extern void balance_ipbuf(void);
+
+#define release_ipbuf_pvt(ipbuf_pvt) \
+ do { \
+ (ipbuf_pvt)->s = OMAP_DSP_TID_FREE; \
+ } while(0)
+
+extern int mbx_revision;
+
+extern int dsp_is_ready(void);
+extern int dspuncfg(void);
+extern void dsp_runlevel(unsigned char level);
+extern int dsp_suspend(void);
+extern int dsp_resume(void);
+
+extern int dsp_task_config_all(unsigned char n);
+extern void dsp_task_unconfig_all(void);
+extern unsigned char 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(unsigned char minor, unsigned long adr);
+extern int dsp_tdel(unsigned char minor);
+extern int dsp_tkill(unsigned char minor);
+extern long taskdev_state_stale(unsigned char minor);
+extern int dsp_dbg_config(short *buf, unsigned short sz, unsigned short lsz);
+extern void dsp_dbg_stop(void);
+
+extern int ipbuf_is_held(unsigned char tid, unsigned short bid);
+
+extern void dsp_mem_sync_inc(void);
+extern int dsp_mem_sync_config(struct mem_sync_struct *sync);
+extern enum dsp_mem_type_e dsp_mem_type(void *vadr, size_t len);
+extern int dsp_address_validate(void *p, size_t len, char *fmt, ...);
+extern int dsp_mem_enable(void *adr);
+extern void dsp_mem_disable(void *adr);
+extern void dsp_mem_usecount_clear(void);
+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_mmu_set(unsigned long adr);
+extern void dsp_err_mmu_clear(void);
+extern int dsp_err_mmu_isset(void);
+extern void dsp_err_wdt_clear(void);
+extern int dsp_err_wdt_isset(void);
+
+enum cmd_l_type {
+ CMD_L_TYPE_NULL,
+ CMD_L_TYPE_TID,
+ CMD_L_TYPE_SUBCMD,
+};
+
+struct cmdinfo {
+ char *name;
+ enum cmd_l_type 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, enum arm_dsp_dir dir);
+#ifdef CONFIG_OMAP_DSP_MBCMD_VERBOSE
+extern void mblog_printcmd(struct mbcmd *mb, enum arm_dsp_dir dir);
+#else /* CONFIG_OMAP_DSP_MBCMD_VERBOSE */
+#define mblog_printcmd(mb, dir) do {} while(0)
+#endif /* CONFIG_OMAP_DSP_MBCMD_VERBOSE */
+
+#ifdef CONFIG_PROC_FS
+extern struct proc_dir_entry *procdir_dsp;
+#endif /* CONFIG_PROC_FS */
+
+extern struct platform_device dsp_device;
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap/dsp/dsp_common.c
+ *
+ * OMAP DSP driver static part
+ *
+ * Copyright (C) 2002-2005 Nokia Corporation
+ *
+ * Written by 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 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
+ *
+ * 2005/06/13: DSP Gateway version 3.3
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/clk.h>
+#include <asm/io.h>
+#include <asm/tlbflush.h>
+#include <asm/irq.h>
+#include <asm/arch/dsp.h>
+#include <asm/arch/tc.h>
+#include "dsp_common.h"
+
+struct clk *dsp_ck_handle;
+struct clk *api_ck_handle;
+unsigned long dspmem_base, dspmem_size,
+ daram_base, daram_size,
+ saram_base, saram_size;
+
+struct cpustat {
+ struct semaphore sem;
+ enum e_cpustat stat;
+ enum e_cpustat req;
+ unsigned short icrmask;
+ struct {
+ int mpui;
+ int mem;
+ int mem_delayed;
+ } usecount;
+ int (*mem_req_cb)(void);
+ void (*mem_rel_cb)(void);
+};
+struct cpustat cpustat = {
+ .sem = __SEMAPHORE_INIT(cpustat.sem, 1),
+ .stat = CPUSTAT_RESET,
+ .icrmask = 0xffff,
+};
+
+int dsp_set_rstvect(unsigned long adr)
+{
+ unsigned long *dst_adr;
+
+ if (adr >= DSPSPACE_SIZE)
+ return -EINVAL;
+
+ dst_adr = dspbyte_to_virt(DSP_BOOT_ADR_DIRECT);
+ /* word swap */
+ *dst_adr = ((adr & 0xffff) << 16) | (adr >> 16);
+ /* fill 8 bytes! */
+ *(dst_adr+1) = 0;
+ /* direct boot */
+ omap_writew(MPUI_DSP_BOOT_CONFIG_DIRECT, MPUI_DSP_BOOT_CONFIG);
+
+ return 0;
+}
+
+static void simple_load_code(unsigned char *src_c, unsigned short *dst, int len)
+{
+ int i;
+ unsigned short *src = (unsigned short *)src_c;
+ int len_w;
+
+ /* len must be multiple of 2. */
+ if (len & 1)
+ BUG();
+
+ len_w = len / 2;
+ for (i = 0; i < len_w; i++) {
+ /* byte swap copy */
+ *dst = ((*src & 0x00ff) << 8) |
+ ((*src & 0xff00) >> 8);
+ src++;
+ dst++;
+ }
+}
+
+/* program size must be multiple of 2 */
+#define GBL_IDLE_TEXT_SIZE 52
+#define GBL_IDLE_TEXT_INIT { \
+ /* SAM */ \
+ 0x3c, 0x4a, /* 0x3c4a: MOV 0x4, AR2 */ \
+ 0xf4, 0x41, 0xfc, 0xff, /* 0xf441fcff: AND 0xfcff, *AR2 */ \
+ /* disable WDT */ \
+ 0x76, 0x34, 0x04, 0xb8, /* 0x763404b8: MOV 0x3404, AR3 */ \
+ 0xfb, 0x61, 0x00, 0xf5, /* 0xfb6100f5: MOV 0x00f5, *AR3 */ \
+ 0x9a, /* 0x9a: PORT */ \
+ 0xfb, 0x61, 0x00, 0xa0, /* 0xfb6100a0: MOV 0x00a0, *AR3 */ \
+ 0x9a, /* 0x9a: PORT */ \
+ /* *IER0 = 0, *IER1 = 0 */ \
+ 0x3c, 0x0b, /* 0x3c0b: MOV 0x0, AR3 */ \
+ 0xe6, 0x61, 0x00, /* 0xe66100: MOV 0, *AR3 */ \
+ 0x76, 0x00, 0x45, 0xb8, /* 0x76004508: MOV 0x45, AR3 */ \
+ 0xe6, 0x61, 0x00, /* 0xe66100: MOV 0, *AR3 */ \
+ /* *ICR = 0xffff */ \
+ 0x3c, 0x1b, /* 0x3c1b: MOV 0x1, AR3 */ \
+ 0xfb, 0x61, 0xff, 0xff, /* 0xfb61ffff: MOV 0xffff, *AR3 */ \
+ 0x9a, /* 0x9a: PORT */ \
+ /* HOM */ \
+ 0xf5, 0x41, 0x03, 0x00, /* 0xf5410300: OR 0x0300, *AR2 */ \
+ /* idle and loop forever */ \
+ 0x7a, 0x00, 0x00, 0x0c, /* 0x7a00000c: IDLE */ \
+ 0x4a, 0x7a, /* 0x4a7a: B -6 (infinite loop) */ \
+ 0x20, 0x20, 0x20, /* 0x20: NOP */ \
+}
+
+/* program size must be multiple of 2 */
+#define CPU_IDLE_TEXT_SIZE 48
+#define CPU_IDLE_TEXT_INIT(icrh, icrl) { \
+ /* SAM */ \
+ 0x3c, 0x4b, /* 0x3c4b: MOV 0x4, AR3 */ \
+ 0xf4, 0x61, 0xfc, 0xff, /* 0xf461fcff: AND 0xfcff, *AR3 */ \
+ /* disable WDT */ \
+ 0x76, 0x34, 0x04, 0xb8, /* 0x763404b8: MOV 0x3404, AR3 */ \
+ 0xfb, 0x61, 0x00, 0xf5, /* 0xfb6100f5: MOV 0x00f5, *AR3 */ \
+ 0x9a, /* 0x9a: PORT */ \
+ 0xfb, 0x61, 0x00, 0xa0, /* 0xfb6100a0: MOV 0x00a0, *AR3 */ \
+ 0x9a, /* 0x9a: PORT */ \
+ /* *IER0 = 0, *IER1 = 0 */ \
+ 0x3c, 0x0b, /* 0x3c0b: MOV 0x0, AR3 */ \
+ 0xe6, 0x61, 0x00, /* 0xe66100: MOV 0, *AR3 */ \
+ 0x76, 0x00, 0x45, 0xb8, /* 0x76004508: MOV 0x45, AR3 */ \
+ 0xe6, 0x61, 0x00, /* 0xe66100: MOV 0, *AR3 */ \
+ /* set ICR = icr */ \
+ 0x3c, 0x1b, /* 0x3c1b: MOV AR3 0x1 */ \
+ 0xfb, 0x61, (icrh), (icrl), /* 0xfb61****: MOV *AR3, icr */ \
+ 0x9a, /* 0x9a: PORT */ \
+ /* idle and loop forever */ \
+ 0x7a, 0x00, 0x00, 0x0c, /* 0x7a00000c: IDLE */ \
+ 0x4a, 0x7a, /* 0x4a7a: B -6 (infinite loop) */ \
+ 0x20, 0x20, 0x20 /* 0x20: nop */ \
+}
+
+/*
+ * idle_boot base:
+ * Initialized with DSP_BOOT_ADR_MPUI (=0x010000).
+ * This value is used before DSP Gateway driver is initialized.
+ * DSP Gateway driver will overwrite this value with other value,
+ * to avoid confliction with the user program.
+ */
+static unsigned long idle_boot_base = DSP_BOOT_ADR_MPUI;
+
+static void dsp_gbl_idle(void)
+{
+ unsigned char idle_text[GBL_IDLE_TEXT_SIZE] = GBL_IDLE_TEXT_INIT;
+
+ __dsp_reset();
+ clk_enable(api_ck_handle);
+
+#if 0
+ omap_writew(MPUI_DSP_BOOT_CONFIG_IDLE, MPUI_DSP_BOOT_CONFIG);
+#endif
+ simple_load_code(idle_text, dspbyte_to_virt(idle_boot_base),
+ GBL_IDLE_TEXT_SIZE);
+ if (idle_boot_base == DSP_BOOT_ADR_MPUI)
+ omap_writew(MPUI_DSP_BOOT_CONFIG_MPUI, MPUI_DSP_BOOT_CONFIG);
+ else
+ dsp_set_rstvect(idle_boot_base);
+
+ __dsp_run();
+ udelay(100); /* to make things stable */
+ clk_disable(api_ck_handle);
+}
+
+static void dsp_cpu_idle(void)
+{
+ unsigned short icr_tmp;
+ unsigned char icrh, icrl;
+
+ __dsp_reset();
+ clk_enable(api_ck_handle);
+
+ /*
+ * icr settings:
+ * DMA should not sleep for DARAM/SARAM access
+ * DPLL should not sleep while any other domain is active
+ */
+ icr_tmp = cpustat.icrmask & ~(DSPREG_ICR_DMA_IDLE_DOMAIN |
+ DSPREG_ICR_DPLL_IDLE_DOMAIN);
+ icrh = icr_tmp >> 8;
+ icrl = icr_tmp & 0xff;
+ {
+ unsigned char idle_text[CPU_IDLE_TEXT_SIZE] = CPU_IDLE_TEXT_INIT(icrh, icrl);
+ simple_load_code(idle_text, dspbyte_to_virt(idle_boot_base),
+ CPU_IDLE_TEXT_SIZE);
+ }
+ if (idle_boot_base == DSP_BOOT_ADR_MPUI)
+ omap_writew(MPUI_DSP_BOOT_CONFIG_MPUI, MPUI_DSP_BOOT_CONFIG);
+ else
+ dsp_set_rstvect(idle_boot_base);
+ __dsp_run();
+ udelay(100); /* to make things stable */
+ clk_disable(api_ck_handle);
+}
+
+void dsp_set_idle_boot_base(unsigned long adr, size_t size)
+{
+ if (adr == idle_boot_base)
+ return;
+ idle_boot_base = adr;
+ if ((size < GBL_IDLE_TEXT_SIZE) ||
+ (size < CPU_IDLE_TEXT_SIZE)) {
+ printk(KERN_ERR
+ "omapdsp: size for idle program is not enough!\n");
+ BUG();
+ }
+
+ /* restart idle program with new base address */
+ if (cpustat.stat == CPUSTAT_GBL_IDLE)
+ dsp_gbl_idle();
+ if (cpustat.stat == CPUSTAT_CPU_IDLE)
+ dsp_cpu_idle();
+}
+
+static int init_done;
+
+static int __init omap_dsp_init(void)
+{
+ dspmem_size = 0;
+#ifdef CONFIG_ARCH_OMAP15XX
+ if (cpu_is_omap1510()) {
+ dspmem_base = OMAP1510_DSP_BASE;
+ dspmem_size = OMAP1510_DSP_SIZE;
+ daram_base = OMAP1510_DARAM_BASE;
+ daram_size = OMAP1510_DARAM_SIZE;
+ saram_base = OMAP1510_SARAM_BASE;
+ saram_size = OMAP1510_SARAM_SIZE;
+ }
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
+ if (cpu_is_omap16xx()) {
+ dspmem_base = OMAP16XX_DSP_BASE;
+ dspmem_size = OMAP16XX_DSP_SIZE;
+ daram_base = OMAP16XX_DARAM_BASE;
+ daram_size = OMAP16XX_DARAM_SIZE;
+ saram_base = OMAP16XX_SARAM_BASE;
+ saram_size = OMAP16XX_SARAM_SIZE;
+ }
+#endif
+ if (dspmem_size == 0) {
+ printk(KERN_ERR "omapdsp: unsupported omap architecture.\n");
+ return -ENODEV;
+ }
+
+ dsp_ck_handle = clk_get(0, "dsp_ck");
+ if (IS_ERR(dsp_ck_handle)) {
+ printk(KERN_ERR "omapdsp: could not acquire dsp_ck handle.\n");
+ return PTR_ERR(dsp_ck_handle);
+ }
+
+ api_ck_handle = clk_get(0, "api_ck");
+ if (IS_ERR(api_ck_handle)) {
+ printk(KERN_ERR "omapdsp: could not acquire api_ck handle.\n");
+ return PTR_ERR(api_ck_handle);
+ }
+
+ /* This is needed for McBSP init, released in late_initcall */
+ clk_enable(api_ck_handle);
+
+ __dsp_enable();
+ mpui_byteswap_off();
+ mpui_wordswap_on();
+ tc_wordswap();
+
+ init_done = 1;
+ printk(KERN_INFO "omap_dsp_init() done\n");
+ return 0;
+}
+
+static int dsp_late_init(void)
+{
+ clk_disable(api_ck_handle);
+ return 0;
+}
+late_initcall(dsp_late_init);
+
+static void dsp_cpustat_update(void)
+{
+ if (!init_done)
+ omap_dsp_init();
+
+ if (cpustat.req == CPUSTAT_RUN) {
+ if (cpustat.stat < CPUSTAT_RUN) {
+ __dsp_reset();
+ clk_enable(api_ck_handle);
+ udelay(10);
+ __dsp_run();
+ cpustat.stat = CPUSTAT_RUN;
+ enable_irq(INT_DSP_MMU);
+ }
+ return;
+ }
+
+ /* cpustat.stat < CPUSTAT_RUN */
+
+ if (cpustat.stat == CPUSTAT_RUN) {
+ disable_irq(INT_DSP_MMU);
+ clk_disable(api_ck_handle);
+ }
+
+ /*
+ * (1) when ARM wants DARAM access, MPUI should be SAM and
+ * DSP needs to be on.
+ * (2) if any bits of icr is masked, we can not enter global idle.
+ */
+ if ((cpustat.req == CPUSTAT_CPU_IDLE) ||
+ (cpustat.usecount.mem > 0) ||
+ (cpustat.usecount.mem_delayed > 0) ||
+ ((cpustat.usecount.mpui > 0) && (cpustat.icrmask != 0xffff))) {
+ if (cpustat.stat != CPUSTAT_CPU_IDLE) {
+ dsp_cpu_idle();
+ cpustat.stat = CPUSTAT_CPU_IDLE;
+ }
+ return;
+ }
+
+ /*
+ * when ARM only needs MPUI access, MPUI can be HOM and
+ * DSP can be idling.
+ */
+ if ((cpustat.req == CPUSTAT_GBL_IDLE) ||
+ (cpustat.usecount.mpui > 0)) {
+ if (cpustat.stat != CPUSTAT_GBL_IDLE) {
+ dsp_gbl_idle();
+ cpustat.stat = CPUSTAT_GBL_IDLE;
+ }
+ return;
+ }
+
+ /*
+ * no user, no request
+ */
+ if (cpustat.stat != CPUSTAT_RESET) {
+ __dsp_reset();
+ cpustat.stat = CPUSTAT_RESET;
+ }
+}
+
+void dsp_cpustat_request(enum e_cpustat req)
+{
+ down(&cpustat.sem);
+ cpustat.req = req;
+ dsp_cpustat_update();
+ up(&cpustat.sem);
+}
+
+enum e_cpustat dsp_cpustat_get_stat(void)
+{
+ return cpustat.stat;
+}
+
+unsigned short dsp_cpustat_get_icrmask(void)
+{
+ return cpustat.icrmask;
+}
+
+void dsp_cpustat_set_icrmask(unsigned short mask)
+{
+ down(&cpustat.sem);
+ cpustat.icrmask = mask;
+ dsp_cpustat_update();
+ up(&cpustat.sem);
+}
+
+void omap_dsp_request_mpui(void)
+{
+ down(&cpustat.sem);
+ if (cpustat.usecount.mpui++ == 0)
+ dsp_cpustat_update();
+ up(&cpustat.sem);
+}
+
+void omap_dsp_release_mpui(void)
+{
+ down(&cpustat.sem);
+ if (cpustat.usecount.mpui-- == 0) {
+ printk(KERN_ERR
+ "omapdsp: unbalanced mpui request/release detected.\n"
+ " cpustat.usecount.mpui is going to be "
+ "less than zero! ... fixed to be zero.\n");
+ cpustat.usecount.mpui = 0;
+ }
+ if (cpustat.usecount.mpui == 0)
+ dsp_cpustat_update();
+ up(&cpustat.sem);
+}
+
+int omap_dsp_request_mem(void)
+{
+ int ret = 0;
+
+ down(&cpustat.sem);
+ if ((cpustat.usecount.mem++ == 0) &&
+ (cpustat.usecount.mem_delayed == 0)) {
+ if (cpustat.mem_req_cb) {
+ if ((ret = cpustat.mem_req_cb()) < 0) {
+ cpustat.usecount.mem--;
+ goto out;
+ }
+ }
+ dsp_cpustat_update();
+ }
+out:
+ up(&cpustat.sem);
+
+ return ret;
+}
+
+/*
+ * release_mem will be delayed.
+ */
+static void do_release_mem(void) {
+ down(&cpustat.sem);
+ cpustat.usecount.mem_delayed = 0;
+ if (cpustat.usecount.mem == 0) {
+ dsp_cpustat_update();
+ if (cpustat.mem_rel_cb)
+ cpustat.mem_rel_cb();
+ }
+ up(&cpustat.sem);
+}
+
+static DECLARE_WORK(mem_rel_work, (void (*)(void *))do_release_mem, NULL);
+
+int omap_dsp_release_mem(void)
+{
+ down(&cpustat.sem);
+
+ /* cancel previous release work */
+ cancel_delayed_work(&mem_rel_work);
+ cpustat.usecount.mem_delayed = 0;
+
+ if (cpustat.usecount.mem-- == 0) {
+ printk(KERN_ERR
+ "omapdsp: unbalanced memory request/release detected.\n"
+ " cpustat.usecount.mem is going to be "
+ "less than zero! ... fixed to be zero.\n");
+ cpustat.usecount.mem = 0;
+ }
+ if (cpustat.usecount.mem == 0) {
+ cpustat.usecount.mem_delayed = 1;
+ schedule_delayed_work(&mem_rel_work, HZ);
+ }
+
+ up(&cpustat.sem);
+
+ return 0;
+}
+
+void dsp_register_mem_cb(int (*req_cb)(void), void (*rel_cb)(void))
+{
+ down(&cpustat.sem);
+
+ cpustat.mem_req_cb = req_cb;
+ cpustat.mem_rel_cb = rel_cb;
+
+ /*
+ * This function must be called while mem is enabled!
+ */
+ BUG_ON(cpustat.usecount.mem == 0);
+
+ up(&cpustat.sem);
+}
+
+void dsp_unregister_mem_cb(void)
+{
+ down(&cpustat.sem);
+ cpustat.mem_req_cb = NULL;
+ cpustat.mem_rel_cb = NULL;
+ up(&cpustat.sem);
+}
+
+/*
+ * Audio power control function prototypes and defaults
+ * (To be overridden with board specific functions)
+ */
+static void generic_audio_pwr_up_request(int stage)
+{
+ printk(KERN_ERR "audio power-up request function is not defined.\n");
+}
+
+void (*omap_dsp_audio_pwr_up_request)(int stage) = generic_audio_pwr_up_request;
+EXPORT_SYMBOL(omap_dsp_audio_pwr_up_request);
+
+static void generic_audio_pwr_down_request(int stage)
+{
+ printk(KERN_ERR "audio power-down request function is not defined.\n");
+}
+
+void (*omap_dsp_audio_pwr_down_request)(int stage) = generic_audio_pwr_down_request;
+EXPORT_SYMBOL(omap_dsp_audio_pwr_down_request);
+
+arch_initcall(omap_dsp_init);
+
+EXPORT_SYMBOL(omap_dsp_request_mpui);
+EXPORT_SYMBOL(omap_dsp_release_mpui);
+EXPORT_SYMBOL(omap_dsp_request_mem);
+EXPORT_SYMBOL(omap_dsp_release_mem);
+
+#ifdef CONFIG_OMAP_DSP_MODULE
+EXPORT_SYMBOL(dsp_ck_handle);
+EXPORT_SYMBOL(api_ck_handle);
+EXPORT_SYMBOL(dspmem_base);
+EXPORT_SYMBOL(dspmem_size);
+EXPORT_SYMBOL(daram_base);
+EXPORT_SYMBOL(daram_size);
+EXPORT_SYMBOL(saram_base);
+EXPORT_SYMBOL(saram_size);
+EXPORT_SYMBOL(dsp_set_rstvect);
+EXPORT_SYMBOL(dsp_set_idle_boot_base);
+EXPORT_SYMBOL(dsp_cpustat_request);
+EXPORT_SYMBOL(dsp_cpustat_get_stat);
+EXPORT_SYMBOL(dsp_cpustat_get_icrmask);
+EXPORT_SYMBOL(dsp_cpustat_set_icrmask);
+EXPORT_SYMBOL(dsp_register_mem_cb);
+EXPORT_SYMBOL(dsp_unregister_mem_cb);
+
+EXPORT_SYMBOL(__cpu_flush_kern_tlb_range);
+#endif
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap/dsp/dsp_common.h
+ *
+ * Header for OMAP DSP driver static part
+ *
+ * Copyright (C) 2002-2005 Nokia Corporation
+ *
+ * Written by 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 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
+ *
+ * 2005/06/13: DSP Gateway version 3.3
+ */
+
+#include "hardware_dsp.h"
+
+#define DSPSPACE_SIZE 0x1000000
+
+#define omap_set_bit_regw(b,r) \
+ do { omap_writew(omap_readw(r) | (b), (r)); } while(0)
+#define omap_clr_bit_regw(b,r) \
+ do { omap_writew(omap_readw(r) & ~(b), (r)); } while(0)
+#define omap_set_bit_regl(b,r) \
+ do { omap_writel(omap_readl(r) | (b), (r)); } while(0)
+#define omap_clr_bit_regl(b,r) \
+ do { omap_writel(omap_readl(r) & ~(b), (r)); } while(0)
+
+#define dspword_to_virt(dw) ((void *)(dspmem_base + ((dw) << 1)))
+#define dspbyte_to_virt(db) ((void *)(dspmem_base + (db)))
+#define virt_to_dspword(va) (((unsigned long)(va) - dspmem_base) >> 1)
+#define virt_to_dspbyte(va) ((unsigned long)(va) - dspmem_base)
+#define is_dsp_internal_mem(va) \
+ (((unsigned long)(va) >= dspmem_base) && \
+ ((unsigned long)(va) < dspmem_base + dspmem_size))
+#define is_dspbyte_internal_mem(db) ((db) < dspmem_size)
+#define is_dspword_internal_mem(dw) (((dw) << 1) < dspmem_size)
+
+/*
+ * MPUI byteswap/wordswap on/off
+ * default setting: wordswap = all, byteswap = APIMEM only
+ */
+#define mpui_wordswap_on() \
+ do { \
+ omap_writel( \
+ (omap_readl(MPUI_CTRL) & ~MPUI_CTRL_WORDSWAP_MASK) | \
+ MPUI_CTRL_WORDSWAP_ALL, MPUI_CTRL); \
+ } while(0)
+
+#define mpui_wordswap_off() \
+ do { \
+ omap_writel( \
+ (omap_readl(MPUI_CTRL) & ~MPUI_CTRL_WORDSWAP_MASK) | \
+ MPUI_CTRL_WORDSWAP_NONE, MPUI_CTRL); \
+ } while(0)
+
+#define mpui_byteswap_on() \
+ do { \
+ omap_writel( \
+ (omap_readl(MPUI_CTRL) & ~MPUI_CTRL_BYTESWAP_MASK) | \
+ MPUI_CTRL_BYTESWAP_API, MPUI_CTRL); \
+ } while(0)
+
+#define mpui_byteswap_off() \
+ do { \
+ omap_writel( \
+ (omap_readl(MPUI_CTRL) & ~MPUI_CTRL_BYTESWAP_MASK) | \
+ MPUI_CTRL_BYTESWAP_NONE, MPUI_CTRL); \
+ } while(0)
+
+/*
+ * TC wordswap on / off
+ */
+#define tc_wordswap() \
+ do { \
+ omap_writel(TC_ENDIANISM_SWAP_WORD | TC_ENDIANISM_EN, \
+ TC_ENDIANISM); \
+ } while(0)
+
+#define tc_noswap() \
+ do { \
+ omap_writel(omap_readl(TC_ENDIANISM) & ~TC_ENDIANISM_EN, \
+ TC_ENDIANISM); \
+ } while(0)
+
+/*
+ * enable priority registers, EMIF, MPUI control logic
+ */
+#define __dsp_enable() omap_set_bit_regw(ARM_RSTCT1_DSP_RST, ARM_RSTCT1)
+#define __dsp_disable() omap_clr_bit_regw(ARM_RSTCT1_DSP_RST, ARM_RSTCT1)
+#define __dsp_run() omap_set_bit_regw(ARM_RSTCT1_DSP_EN, ARM_RSTCT1)
+#define __dsp_reset() omap_clr_bit_regw(ARM_RSTCT1_DSP_EN, ARM_RSTCT1)
+
+extern struct clk *dsp_ck_handle;
+extern struct clk *api_ck_handle;
+extern unsigned long dspmem_base, dspmem_size,
+ daram_base, daram_size,
+ saram_base, saram_size;
+
+enum e_cpustat {
+ CPUSTAT_RESET = 0,
+ CPUSTAT_GBL_IDLE = 1,
+ CPUSTAT_CPU_IDLE = 2,
+ CPUSTAT_RUN = 3
+};
+
+#define cpustat_name(stat) \
+ ((stat == CPUSTAT_RESET) ? "RESET" :\
+ (stat == CPUSTAT_GBL_IDLE) ? "GBL_IDLE" :\
+ (stat == CPUSTAT_CPU_IDLE) ? "CPU_IDLE" :\
+ (stat == CPUSTAT_RUN) ? "RUN" :\
+ "unknown")
+
+int dsp_set_rstvect(unsigned long adr);
+void dsp_set_idle_boot_base(unsigned long adr, size_t size);
+void dsp_cpustat_request(enum e_cpustat req);
+enum e_cpustat dsp_cpustat_get_stat(void);
+unsigned short dsp_cpustat_get_icrmask(void);
+void dsp_cpustat_set_icrmask(unsigned short mask);
+void dsp_register_mem_cb(int (*req_cb)(void), void (*rel_cb)(void));
+void dsp_unregister_mem_cb(void);
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap/dsp/dsp_core.c
+ *
+ * OMAP DSP driver
+ *
+ * Copyright (C) 2002-2005 Nokia Corporation
+ *
+ * Written by 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 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
+ *
+ * 2005/06/07: DSP Gateway version 3.3
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/signal.h>
+#include <asm/delay.h>
+#include <asm/irq.h>
+#include <asm/arch/dsp_common.h>
+#include <asm/arch/dsp.h>
+#include "hardware_dsp.h"
+#include "dsp.h"
+#include "ipbuf.h"
+
+
+MODULE_AUTHOR("Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>");
+MODULE_DESCRIPTION("OMAP DSP driver module");
+MODULE_LICENSE("GPL");
+
+enum mbseq_check_level {
+ MBSEQ_CHECK_NONE, /* no check */
+ MBSEQ_CHECK_VERBOSE, /* discard the illegal command and
+ error report */
+ MBSEQ_CHECK_SILENT, /* discard the illegal command */
+};
+
+static enum mbseq_check_level mbseq_check_level = MBSEQ_CHECK_VERBOSE;
+
+static int mbx1_valid;
+static struct sync_seq *mbseq;
+static unsigned short mbseq_expect_tmp;
+static unsigned short *mbseq_expect = &mbseq_expect_tmp;
+
+/*
+ * mailbox commands
+ */
+extern void mbx1_wdsnd(struct mbcmd *mb);
+extern void mbx1_wdreq(struct mbcmd *mb);
+extern void mbx1_bksnd(struct mbcmd *mb);
+extern void mbx1_bkreq(struct mbcmd *mb);
+extern void mbx1_bkyld(struct mbcmd *mb);
+extern void mbx1_bksndp(struct mbcmd *mb);
+extern void mbx1_bkreqp(struct mbcmd *mb);
+extern void mbx1_tctl(struct mbcmd *mb);
+extern void mbx1_poll(struct mbcmd *mb);
+#ifdef OLD_BINARY_SUPPORT
+/* v3.3 obsolete */
+extern void mbx1_wdt(struct mbcmd *mb);
+#endif
+extern void mbx1_suspend(struct mbcmd *mb);
+static void mbx1_kfunc(struct mbcmd *mb);
+extern void mbx1_tcfg(struct mbcmd *mb);
+extern void mbx1_tadd(struct mbcmd *mb);
+extern void mbx1_tdel(struct mbcmd *mb);
+extern void mbx1_dspcfg(struct mbcmd *mb);
+extern void mbx1_regrw(struct mbcmd *mb);
+extern void mbx1_getvar(struct mbcmd *mb);
+extern void mbx1_err(struct mbcmd *mb);
+extern void mbx1_dbg(struct mbcmd *mb);
+
+static const struct cmdinfo
+ cif_null = { "Unknown", CMD_L_TYPE_NULL, NULL },
+ cif_wdsnd = { "WDSND", CMD_L_TYPE_TID, mbx1_wdsnd },
+ cif_wdreq = { "WDREQ", CMD_L_TYPE_TID, mbx1_wdreq },
+ cif_bksnd = { "BKSND", CMD_L_TYPE_TID, mbx1_bksnd },
+ cif_bkreq = { "BKREQ", CMD_L_TYPE_TID, mbx1_bkreq },
+ cif_bkyld = { "BKYLD", CMD_L_TYPE_NULL, mbx1_bkyld },
+ cif_bksndp = { "BKSNDP", CMD_L_TYPE_TID, mbx1_bksndp },
+ cif_bkreqp = { "BKREQP", CMD_L_TYPE_TID, mbx1_bkreqp },
+ cif_tctl = { "TCTL", CMD_L_TYPE_TID, mbx1_tctl },
+ cif_poll = { "POLL", CMD_L_TYPE_NULL, mbx1_poll },
+#ifdef OLD_BINARY_SUPPORT
+ /* v3.3 obsolete */
+ cif_wdt = { "WDT", CMD_L_TYPE_NULL, mbx1_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, mbx1_suspend },
+ cif_kfunc = { "KFUNC", CMD_L_TYPE_SUBCMD, mbx1_kfunc },
+ cif_tcfg = { "TCFG", CMD_L_TYPE_TID, mbx1_tcfg },
+ cif_tadd = { "TADD", CMD_L_TYPE_TID, mbx1_tadd },
+ cif_tdel = { "TDEL", CMD_L_TYPE_TID, mbx1_tdel },
+ cif_tstop = { "TSTOP", CMD_L_TYPE_TID, NULL },
+ cif_dspcfg = { "DSPCFG", CMD_L_TYPE_SUBCMD, mbx1_dspcfg },
+ cif_regrw = { "REGRW", CMD_L_TYPE_SUBCMD, mbx1_regrw },
+ cif_getvar = { "GETVAR", CMD_L_TYPE_SUBCMD, mbx1_getvar },
+ cif_setvar = { "SETVAR", CMD_L_TYPE_SUBCMD, NULL },
+ cif_err = { "ERR", CMD_L_TYPE_SUBCMD, mbx1_err },
+ cif_dbg = { "DBG", CMD_L_TYPE_NULL, mbx1_dbg };
+
+const struct cmdinfo *cmdinfo[128] = {
+/*00*/ &cif_null, &cif_null, &cif_null, &cif_null,
+ &cif_null, &cif_null, &cif_null, &cif_null,
+ &cif_null, &cif_null, &cif_null, &cif_null,
+ &cif_null, &cif_null, &cif_null, &cif_null,
+/*10*/ &cif_wdsnd, &cif_wdreq, &cif_null, &cif_null,
+ &cif_null, &cif_null, &cif_null, &cif_null,
+ &cif_null, &cif_null, &cif_null, &cif_null,
+ &cif_null, &cif_null, &cif_null, &cif_null,
+/*20*/ &cif_bksnd, &cif_bkreq, &cif_null, &cif_bkyld,
+ &cif_bksndp, &cif_bkreqp, &cif_null, &cif_null,
+ &cif_null, &cif_null, &cif_null, &cif_null,
+ &cif_null, &cif_null, &cif_null, &cif_null,
+/*30*/ &cif_tctl, &cif_null, &cif_poll, &cif_null,
+ &cif_null, &cif_null, &cif_null, &cif_null,
+ &cif_null, &cif_null, &cif_null, &cif_null,
+ &cif_null, &cif_null, &cif_null, &cif_null,
+/*40*/ &cif_null, &cif_null, &cif_null, &cif_null,
+ &cif_null, &cif_null, &cif_null, &cif_null,
+ &cif_null, &cif_null, &cif_null, &cif_null,
+ &cif_null, &cif_null, &cif_null, &cif_null,
+#ifdef OLD_BINARY_SUPPORT
+ /* v3.3 obsolete */
+/*50*/ &cif_wdt, &cif_runlevel, &cif_pm, &cif_suspend,
+#else
+/*50*/ &cif_null, &cif_runlevel, &cif_pm, &cif_suspend,
+#endif
+ &cif_kfunc, &cif_null, &cif_null, &cif_null,
+ &cif_null, &cif_null, &cif_null, &cif_null,
+ &cif_null, &cif_null, &cif_null, &cif_null,
+/*60*/ &cif_tcfg, &cif_null, &cif_tadd, &cif_tdel,
+ &cif_null, &cif_tstop, &cif_null, &cif_null,
+ &cif_null, &cif_null, &cif_null, &cif_null,
+ &cif_null, &cif_null, &cif_null, &cif_null,
+/*70*/ &cif_dspcfg, &cif_null, &cif_regrw, &cif_null,
+ &cif_getvar, &cif_setvar, &cif_null, &cif_null,
+ &cif_err, &cif_dbg, &cif_null, &cif_null,
+ &cif_null, &cif_null, &cif_null, &cif_null
+};
+
+int sync_with_dsp(unsigned short *syncwd, unsigned short tid, int try_cnt)
+{
+ int try;
+
+ if (*(volatile unsigned short *)syncwd == tid)
+ return 0;
+
+ for (try = 0; try < try_cnt; try++) {
+ udelay(1);
+ if (*(volatile unsigned short *)syncwd == tid) {
+ /* success! */
+ printk(KERN_INFO
+ "omapdsp: sync_with_dsp(): try = %d\n", try);
+ return 0;
+ }
+ }
+
+ /* fail! */
+ return -1;
+}
+
+static __inline__ int mbsync_irq_save(unsigned long *flags, int try_cnt)
+{
+ int cnt;
+
+ local_irq_save(*flags);
+ if (omap_readw(MAILBOX_ARM2DSP1_Flag) == 0)
+ return 0;
+ /*
+ * mailbox is busy. wait for some usecs...
+ */
+ local_irq_restore(*flags);
+ for (cnt = 0; cnt < try_cnt; cnt++) {
+ udelay(1);
+ local_irq_save(*flags);
+ if (omap_readw(MAILBOX_ARM2DSP1_Flag) == 0) /* success! */
+ return 0;
+ local_irq_restore(*flags);
+ }
+
+ /* fail! */
+ return -1;
+}
+
+#ifdef CONFIG_OMAP_DSP_MBCMD_VERBOSE
+#define print_mb_busy_abort(mb) \
+ printk(KERN_DEBUG \
+ "mbx: mailbox is busy. %s is aborting.\n", cmd_name(*mb))
+#define print_mb_mmu_abort(mb) \
+ printk(KERN_DEBUG \
+ "mbx: mmu interrupt is set. %s is aborting.\n", cmd_name(*mb))
+#else /* CONFIG_OMAP_DSP_MBCMD_VERBOSE */
+#define print_mb_busy_abort(mb) do {} while(0)
+#define print_mb_mmu_abort(mb) do {} while(0)
+#endif /* !CONFIG_OMAP_DSP_MBCMD_VERBOSE */
+
+int __mbcmd_send(struct mbcmd *mb)
+{
+ struct mbcmd_hw *mb_hw = (struct mbcmd_hw *)mb;
+ unsigned long flags;
+
+ /*
+ * DSP mailbox interrupt latency must be less than 1ms.
+ */
+ if (mbsync_irq_save(&flags, 1000) < 0) {
+ print_mb_busy_abort(mb);
+ return -1;
+ }
+
+ if (mbseq) {
+ mb->seq = mbseq->ad_arm;
+ mbseq->ad_arm++;
+ } else
+ mb->seq = 0;
+ mblog_add(mb, DIR_A2D);
+ mblog_printcmd(mb, DIR_A2D);
+
+ omap_writew(mb_hw->data, MAILBOX_ARM2DSP1);
+ omap_writew(mb_hw->cmd, MAILBOX_ARM2DSP1b);
+
+ local_irq_restore(flags);
+ return 0;
+}
+
+/*
+ * __dsp_mbcmd_send(): mailbox dispatcher
+ */
+int __dsp_mbcmd_send(struct mbcmd *mb, struct mb_exarg *arg, int recovery_flag)
+{
+ static DECLARE_MUTEX(mbsend_sem);
+ int ret = 0;
+
+ /*
+ * while MMU fault is set,
+ * only recovery command can be executed
+ */
+ if (dsp_err_mmu_isset() && !recovery_flag) {
+ print_mb_mmu_abort(mb);
+ return -1;
+ }
+
+ if (down_interruptible(&mbsend_sem) < 0)
+ return -1;
+
+ if (arg) { /* we have extra argument */
+ int i;
+
+ /*
+ * 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, OMAP_DSP_TID_FREE, 10) < 0) {
+ printk(KERN_ERR "omapdsp: ipbuf_sys_ad is busy.\n");
+ dsp_mem_disable(ipbuf_sys_ad);
+ 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;
+ dsp_mem_disable(ipbuf_sys_ad);
+ }
+
+ ret = __mbcmd_send(mb);
+
+out:
+ up(&mbsend_sem);
+ return ret;
+}
+
+int __dsp_mbcmd_send_and_wait(struct mbcmd *mb, struct mb_exarg *arg,
+ wait_queue_head_t *q)
+{
+ long current_state;
+ DECLARE_WAITQUEUE(wait, current);
+
+ add_wait_queue(q, &wait);
+ current_state = current->state;
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (dsp_mbcmd_send_exarg(mb, arg) < 0) {
+ set_current_state(current_state);
+ remove_wait_queue(q, &wait);
+ return -1;
+ }
+ schedule_timeout(DSP_TIMEOUT);
+ set_current_state(current_state);
+ remove_wait_queue(q, &wait);
+
+ return 0;
+}
+
+int __dsp_mbsend(unsigned char cmdh, unsigned char cmdl, unsigned short data,
+ int recovery_flag)
+{
+ struct mbcmd mb;
+
+ mbcmd_set(mb, cmdh, cmdl, data);
+ return __dsp_mbcmd_send(&mb, NULL, recovery_flag);
+}
+
+static int mbsync_hold_mem_active;
+
+void dsp_mb_start(void)
+{
+ mbx1_valid = 1; /* start interpreting */
+ mbseq_expect_tmp = 0;
+}
+
+void dsp_mb_stop(void)
+{
+ mbx1_valid = 0; /* stop interpreting */
+ if (mbsync_hold_mem_active) {
+ dsp_mem_disable((void *)daram_base);
+ mbsync_hold_mem_active = 0;
+ }
+ mbseq = NULL;
+ mbseq_expect = &mbseq_expect_tmp;
+}
+
+int dsp_mb_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;
+}
+
+/*
+ * mbq: mailbox queue
+ */
+#define MBQ_DEPTH 16
+struct mbq {
+ struct mbcmd mb[MBQ_DEPTH];
+ int rp, wp, full;
+} mbq = {
+ .rp = 0,
+ .wp = 0,
+};
+
+#define mbq_inc(p) do { if (++(p) == MBQ_DEPTH) (p) = 0; } while(0)
+
+/*
+ * workqueue for mbx1
+ */
+static void do_mbx1(void)
+{
+ int empty = 0;
+
+ disable_irq(INT_D2A_MB1);
+ if ((mbq.rp == mbq.wp) && !mbq.full)
+ empty = 1;
+ enable_irq(INT_D2A_MB1);
+
+ while (!empty) {
+ struct mbcmd *mb;
+
+ mb = &mbq.mb[mbq.rp];
+
+ mblog_add(mb, DIR_D2A);
+ mblog_printcmd(mb, DIR_D2A);
+
+ /*
+ * call handler for each command
+ */
+ if (cmdinfo[mb->cmd_h]->handler)
+ cmdinfo[mb->cmd_h]->handler(mb);
+ else if (cmdinfo[mb->cmd_h] != &cif_null)
+ printk(KERN_ERR "mbx: %s is not allowed from DSP.\n",
+ cmd_name(*mb));
+ else
+ printk(KERN_ERR
+ "mbx: Unrecognized command: "
+ "cmd=0x%04x, data=0x%04x\n",
+ ((struct mbcmd_hw *)mb)->cmd & 0x7fff, mb->data);
+
+ disable_irq(INT_D2A_MB1);
+ mbq_inc(mbq.rp);
+ if (mbq.rp == mbq.wp)
+ empty = 1;
+ /* if mbq has been full, now we have a room. */
+ if (mbq.full) {
+ mbq.full = 0;
+ enable_irq(INT_D2A_MB1);
+ }
+ enable_irq(INT_D2A_MB1);
+ }
+}
+
+static DECLARE_WORK(mbx1_work, (void (*)(void *))do_mbx1, NULL);
+
+/*
+ * kernel function dispatcher
+ */
+extern void mbx1_fbctl_upd(void);
+extern void mbx1_fbctl_disable(void);
+
+static void mbx1_kfunc_fbctl(unsigned short data)
+{
+ switch (data) {
+ case OMAP_DSP_MBCMD_FBCTL_UPD:
+ mbx1_fbctl_upd();
+ break;
+ case OMAP_DSP_MBCMD_FBCTL_DISABLE:
+ mbx1_fbctl_disable();
+ break;
+ default:
+ printk(KERN_ERR
+ "mailbox: Unknown FBCTL from DSP: 0x%04x\n", data);
+ }
+}
+
+static void mbx1_kfunc_audio_pwr(unsigned short data)
+{
+ struct mbcmd mb;
+
+ switch (data) {
+ case OMAP_DSP_MBCMD_AUDIO_PWR_UP:
+ omap_dsp_audio_pwr_up_request(0);
+ /* send back ack */
+ mbcmd_set(mb, MBCMD(KFUNC), OMAP_DSP_MBCMD_KFUNC_AUDIO_PWR,
+ OMAP_DSP_MBCMD_AUDIO_PWR_UP);
+ dsp_mbcmd_send(&mb);
+ break;
+ case OMAP_DSP_MBCMD_AUDIO_PWR_DOWN1:
+ omap_dsp_audio_pwr_down_request(1);
+ break;
+ case OMAP_DSP_MBCMD_AUDIO_PWR_DOWN2:
+ omap_dsp_audio_pwr_down_request(2);
+ break;
+ default:
+ printk(KERN_ERR
+ "mailbox: Unknown AUDIO_PWR from DSP: 0x%04x\n", data);
+ }
+}
+
+static void mbx1_kfunc(struct mbcmd *mb)
+{
+ switch (mb->cmd_l) {
+ case OMAP_DSP_MBCMD_KFUNC_FBCTL:
+ mbx1_kfunc_fbctl(mb->data);
+ break;
+ case OMAP_DSP_MBCMD_KFUNC_AUDIO_PWR:
+ mbx1_kfunc_audio_pwr(mb->data);
+ break;
+ default:
+ printk(KERN_ERR
+ "mailbox: Unknown kfunc from DSP: 0x%02x\n", mb->cmd_l);
+ }
+}
+
+/*
+ * mailbox interrupt handler
+ */
+static irqreturn_t mbx1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ union {
+ struct mbcmd sw;
+ struct mbcmd_hw hw;
+ } *mb = (void *)&mbq.mb[mbq.wp];
+
+#if (INT_D2A_MB1 == INT_DSP_MAILBOX1)
+ mb->hw.data = omap_readw(MAILBOX_DSP2ARM1);
+ mb->hw.cmd = omap_readw(MAILBOX_DSP2ARM1b);
+#elif (INT_D2A_MB1 == INT_DSP_MAILBOX2)
+ mb->hw.data = omap_readw(MAILBOX_DSP2ARM2);
+ mb->hw.cmd = omap_readw(MAILBOX_DSP2ARM2b);
+#endif
+
+ /* if mbx1 has not been validated yet, discard. */
+ if (!mbx1_valid)
+ return IRQ_HANDLED;
+
+ if (mb->sw.seq != (*mbseq_expect & 1)) {
+ switch (mbseq_check_level) {
+ case MBSEQ_CHECK_NONE:
+ break;
+ case MBSEQ_CHECK_VERBOSE:
+ printk(KERN_INFO
+ "mbx: illegal seq bit!!! ignoring this command."
+ " (%04x:%04x)\n", mb->hw.cmd, mb->hw.data);
+ return IRQ_HANDLED;
+ case MBSEQ_CHECK_SILENT:
+ return IRQ_HANDLED;
+ }
+ }
+
+ (*mbseq_expect)++;
+
+ mbq_inc(mbq.wp);
+ if (mbq.wp == mbq.rp) { /* mbq is full */
+ mbq.full = 1;
+ disable_irq(INT_D2A_MB1);
+ }
+ schedule_work(&mbx1_work);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mbx2_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned short cmd, data;
+
+#if (INT_D2A_MB1 == INT_DSP_MAILBOX1)
+ data = omap_readw(MAILBOX_DSP2ARM2);
+ cmd = omap_readw(MAILBOX_DSP2ARM2b);
+#elif (INT_D2A_MB1 == INT_DSP_MAILBOX2)
+ data = omap_readw(MAILBOX_DSP2ARM1);
+ cmd = omap_readw(MAILBOX_DSP2ARM1b);
+#endif
+ printk(KERN_DEBUG
+ "mailbox2 interrupt! cmd=%04x, data=%04x\n", cmd, data);
+
+ return IRQ_HANDLED;
+}
+
+#if 0
+static void mpuio_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ printk(KERN_INFO "MPUIO interrupt!\n");
+}
+#endif
+
+#ifdef CONFIG_PROC_FS
+struct proc_dir_entry *procdir_dsp = NULL;
+
+static void dsp_create_procdir_dsp(void)
+{
+ procdir_dsp = proc_mkdir("dsp", 0);
+ if (procdir_dsp == NULL) {
+ printk(KERN_ERR
+ "omapdsp: failed to register proc directory: dsp\n");
+ }
+}
+
+static void dsp_remove_procdir_dsp(void)
+{
+ procdir_dsp = NULL;
+ remove_proc_entry("dsp", 0);
+}
+#else /* CONFIG_PROC_FS */
+#define dsp_create_procdir_dsp() do { } while (0)
+#define dsp_remove_procdir_dsp() do { } while (0)
+#endif /* CONFIG_PROC_FS */
+
+extern irqreturn_t dsp_mmu_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs);
+
+extern int dsp_ctl_core_init(void);
+extern void dsp_ctl_core_exit(void);
+extern void dsp_ctl_init(void);
+extern void dsp_ctl_exit(void);
+extern int dsp_mem_init(void);
+extern void dsp_mem_exit(void);
+extern void mblog_init(void);
+extern void mblog_exit(void);
+extern int dsp_taskmod_init(void);
+extern void dsp_taskmod_exit(void);
+
+/*
+ * device functions
+ */
+static void dsp_dev_release(struct device *dev)
+{
+}
+
+/*
+ * driver functions
+ */
+#if (INT_D2A_MB1 == INT_DSP_MAILBOX1)
+# define INT_D2A_MB2 INT_DSP_MAILBOX2
+#elif(INT_D2A_MB1 == INT_DSP_MAILBOX2) /* swap MB1 and MB2 */
+# define INT_D2A_MB2 INT_DSP_MAILBOX1
+#endif
+
+static int __init dsp_drv_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ printk(KERN_INFO "OMAP DSP driver initialization\n");
+
+ //__dsp_enable(); // XXX
+
+ dsp_create_procdir_dsp();
+
+ if ((ret = dsp_ctl_core_init()) < 0)
+ goto fail1;
+ if ((ret = dsp_mem_init()) < 0)
+ goto fail2;
+ dsp_ctl_init();
+ mblog_init();
+ if ((ret = dsp_taskmod_init()) < 0)
+ goto fail3;
+
+ /*
+ * mailbox interrupt handlers registration
+ */
+ ret = request_irq(INT_D2A_MB1, mbx1_interrupt, SA_INTERRUPT, "dsp",
+ &pdev->dev);
+ if (ret) {
+ printk(KERN_ERR
+ "failed to register mailbox1 interrupt: %d\n", ret);
+ goto fail4;
+ }
+
+ ret = request_irq(INT_D2A_MB2, mbx2_interrupt, SA_INTERRUPT, "dsp",
+ &pdev->dev);
+ if (ret) {
+ printk(KERN_ERR
+ "failed to register mailbox2 interrupt: %d\n", ret);
+ goto fail5;
+ }
+
+ ret = request_irq(INT_DSP_MMU, dsp_mmu_interrupt, SA_INTERRUPT, "dsp",
+ &pdev->dev);
+ if (ret) {
+ printk(KERN_ERR
+ "failed to register DSP MMU interrupt: %d\n", ret);
+ goto fail6;
+ }
+
+ /* MMU interrupt is not enabled until DSP runs */
+ disable_irq(INT_DSP_MMU);
+
+#if 0
+ ret = request_irq(INT_MPUIO, mpuio_interrupt, SA_INTERRUPT, "dsp", dev);
+ if (ret) {
+ printk(KERN_ERR
+ "failed to register MPUIO interrupt: %d\n", ret);
+ goto fail7;
+ }
+#endif
+
+ return 0;
+
+fail6:
+ free_irq(INT_D2A_MB2, &pdev->dev);
+fail5:
+ free_irq(INT_D2A_MB1, &pdev->dev);
+fail4:
+ dsp_taskmod_exit();
+fail3:
+ mblog_exit();
+ dsp_ctl_exit();
+ dsp_mem_exit();
+fail2:
+ dsp_ctl_core_exit();
+fail1:
+ dsp_remove_procdir_dsp();
+
+ //__dsp_disable(); // XXX
+ return ret;
+}
+
+static int dsp_drv_remove(struct platform_device *pdev)
+{
+ dsp_cpustat_request(CPUSTAT_RESET);
+
+#if 0
+ free_irq(INT_MPUIO, dev);
+#endif
+ free_irq(INT_DSP_MMU, &pdev->dev);
+ free_irq(INT_D2A_MB2, &pdev->dev);
+ free_irq(INT_D2A_MB1, &pdev->dev);
+
+ /* recover disable_depth */
+ enable_irq(INT_DSP_MMU);
+
+ dspuncfg();
+ dsp_taskmod_exit();
+ mblog_exit();
+ dsp_ctl_exit();
+ dsp_mem_exit();
+
+ dsp_ctl_core_exit();
+ dsp_remove_procdir_dsp();
+
+ //__dsp_disable(); // XXX
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int dsp_drv_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ dsp_suspend();
+
+ return 0;
+}
+
+static int dsp_drv_resume(struct platform_device *pdev)
+{
+ dsp_resume();
+
+ return 0;
+}
+#else
+#define dsp_drv_suspend NULL
+#define dsp_drv_resume NULL
+#endif /* CONFIG_PM */
+
+static struct resource dsp_resources[] = {
+ {
+ .start = INT_DSP_MAILBOX1,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = INT_DSP_MAILBOX2,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = INT_DSP_MMU,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device dsp_device = {
+ .name = "dsp",
+ .id = -1,
+ .dev = {
+ .release = dsp_dev_release,
+ },
+ .num_resources = ARRAY_SIZE(&dsp_resources),
+ .resource = dsp_resources,
+};
+
+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)
+{
+ int ret;
+
+ ret = platform_device_register(&dsp_device);
+ if (ret) {
+ printk(KERN_ERR "failed to register the DSP device: %d\n", ret);
+ goto fail1;
+ }
+
+ ret = platform_driver_register(&dsp_driver);
+ if (ret) {
+ printk(KERN_ERR "failed to register the DSP driver: %d\n", ret);
+ goto fail2;
+ }
+
+ return 0;
+
+fail2:
+ platform_device_unregister(&dsp_device);
+fail1:
+ return -ENODEV;
+}
+
+static void __exit omap_dsp_mod_exit(void)
+{
+ platform_driver_unregister(&dsp_driver);
+ platform_device_unregister(&dsp_device);
+}
+
+module_init(omap_dsp_mod_init);
+module_exit(omap_dsp_mod_exit);
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap/dsp/dsp_ctl.c
+ *
+ * OMAP DSP control device driver
+ *
+ * Copyright (C) 2002-2005 Nokia Corporation
+ *
+ * Written by 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 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
+ *
+ * 2005/06/09: DSP Gateway version 3.3
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/ioctls.h>
+#include <asm/arch/dsp.h>
+#include "hardware_dsp.h"
+#include "dsp.h"
+#include "ipbuf.h"
+
+static ssize_t loadinfo_show(struct device *dev, struct device_attribute *attr,
+ char *buf);
+static struct device_attribute dev_attr_loadinfo = __ATTR_RO(loadinfo);
+extern struct device_attribute dev_attr_ipbuf;
+
+static enum cfgstat {
+ CFG_ERR,
+ CFG_READY,
+ CFG_SUSPEND
+} cfgstat;
+int mbx_revision;
+static DECLARE_WAIT_QUEUE_HEAD(ioctl_wait_q);
+static unsigned short ioctl_wait_cmd;
+static DECLARE_MUTEX(ioctl_sem);
+
+static unsigned char n_stask;
+
+/*
+ * control functions
+ */
+static short varread_val[5]; /* maximum */
+
+static int dsp_regread(unsigned short cmd_l, unsigned short adr,
+ unsigned short *val)
+{
+ struct mbcmd mb;
+ int ret = 0;
+
+ if (down_interruptible(&ioctl_sem))
+ return -ERESTARTSYS;
+
+ ioctl_wait_cmd = MBCMD(REGRW);
+ mbcmd_set(mb, MBCMD(REGRW), cmd_l, adr);
+ dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
+
+ if (ioctl_wait_cmd != 0) {
+ printk(KERN_ERR "omapdsp: register read error!\n");
+ ret = -EINVAL;
+ goto up_out;
+ }
+
+ *val = varread_val[0];
+
+up_out:
+ up(&ioctl_sem);
+ return ret;
+}
+
+static int dsp_regwrite(unsigned short cmd_l, unsigned short adr,
+ unsigned short val)
+{
+ struct mbcmd mb;
+ struct mb_exarg arg = {
+ .tid = OMAP_DSP_TID_ANON,
+ .argc = 1,
+ .argv = &val,
+ };
+
+ mbcmd_set(mb, MBCMD(REGRW), cmd_l, adr);
+ dsp_mbcmd_send_exarg(&mb, &arg);
+ return 0;
+}
+
+static int dsp_getvar(unsigned char varid, unsigned short *val, int sz)
+{
+ struct mbcmd mb;
+ int ret = 0;
+
+ if (down_interruptible(&ioctl_sem))
+ return -ERESTARTSYS;
+
+ ioctl_wait_cmd = MBCMD(GETVAR);
+ mbcmd_set(mb, MBCMD(GETVAR), varid, 0);
+ dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
+
+ if (ioctl_wait_cmd != 0) {
+ printk(KERN_ERR "omapdsp: variable read error!\n");
+ ret = -EINVAL;
+ goto up_out;
+ }
+
+ memcpy(val, varread_val, sz * sizeof(short));
+
+up_out:
+ up(&ioctl_sem);
+ return ret;
+}
+
+static int dsp_setvar(unsigned char varid, unsigned short val)
+{
+ dsp_mbsend(MBCMD(SETVAR), varid, val);
+ return 0;
+}
+
+static int dspcfg(void)
+{
+ struct mbcmd mb;
+ int ret = 0;
+
+ if (down_interruptible(&ioctl_sem))
+ return -ERESTARTSYS;
+
+ if (cfgstat != CFG_ERR) {
+ printk(KERN_ERR
+ "omapdsp: DSP has been already configured. "
+ "do unconfig!\n");
+ ret = -EBUSY;
+ goto up_out;
+ }
+
+ /* for safety */
+ dsp_mem_usecount_clear();
+
+ /*
+ * DSPCFG command and dsp_mem_start() must be called
+ * while internal mem is on.
+ */
+ dsp_mem_enable((void *)dspmem_base);
+
+ dsp_mb_start();
+ dsp_twch_start();
+ dsp_mem_start();
+ dsp_err_start();
+
+ mbx_revision = -1;
+ ioctl_wait_cmd = MBCMD(DSPCFG);
+ mbcmd_set(mb, MBCMD(DSPCFG), OMAP_DSP_MBCMD_DSPCFG_REQ, 0);
+ dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
+
+ if (ioctl_wait_cmd != 0) {
+ printk(KERN_ERR "omapdsp: configuration error!\n");
+ ret = -EINVAL;
+ cfgstat = CFG_ERR;
+ goto up_out;
+ }
+
+#ifdef OLD_BINARY_SUPPORT
+ /*
+ * MBREV 3.2 or earlier doesn't assume DMA domain is on
+ * when DSPCFG command is sent
+ */
+ if ((mbx_revision == MBREV_3_0) ||
+ (mbx_revision == MBREV_3_2)) {
+ ret = dsp_mbsend(MBCMD(PM), OMAP_DSP_MBCMD_PM_ENABLE,
+ DSPREG_ICR_DMA_IDLE_DOMAIN);
+ }
+#endif
+
+ if ((ret = dsp_task_config_all(n_stask)) < 0) {
+ up(&ioctl_sem);
+ dspuncfg();
+ dsp_mem_disable((void *)dspmem_base);
+ return -EINVAL;
+ }
+
+ cfgstat = CFG_READY;
+
+ /* send parameter */
+ if ((ret = dsp_setvar(OMAP_DSP_MBCMD_VARID_ICRMASK,
+ dsp_cpustat_get_icrmask())) < 0)
+ goto up_out;
+
+ /* create runtime sysfs entries */
+ device_create_file(&dsp_device.dev, &dev_attr_loadinfo);
+ device_create_file(&dsp_device.dev, &dev_attr_ipbuf);
+
+up_out:
+ dsp_mem_disable((void *)dspmem_base);
+ up(&ioctl_sem);
+ return ret;
+}
+
+int dspuncfg(void)
+{
+ if (dsp_taskmod_busy()) {
+ printk(KERN_WARNING "omapdsp: tasks are busy.\n");
+ return -EBUSY;
+ }
+
+ if (down_interruptible(&ioctl_sem))
+ return -ERESTARTSYS;
+
+ /* FIXME: lock task module */
+
+ /* remove runtime sysfs entries */
+ device_remove_file(&dsp_device.dev, &dev_attr_loadinfo);
+ device_remove_file(&dsp_device.dev, &dev_attr_ipbuf);
+
+ dsp_mb_stop();
+ dsp_twch_stop();
+ dsp_mem_stop();
+ dsp_err_stop();
+ dsp_dbg_stop();
+ dsp_task_unconfig_all();
+ ipbuf_stop();
+ cfgstat = CFG_ERR;
+
+ up(&ioctl_sem);
+ return 0;
+}
+
+int dsp_is_ready(void)
+{
+ return (cfgstat == CFG_READY) ? 1 : 0;
+}
+
+/*
+ * polls all tasks
+ */
+int dsp_poll(void)
+{
+ struct mbcmd mb;
+ int ret = 0;
+
+ if (down_interruptible(&ioctl_sem))
+ return -ERESTARTSYS;
+
+ ioctl_wait_cmd = MBCMD(POLL);
+ mbcmd_set(mb, MBCMD(POLL), 0, 0);
+ dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
+
+ if (ioctl_wait_cmd != 0) {
+ printk(KERN_ERR "omapdsp: poll error!\n");
+ ret = -EINVAL;
+ goto up_out;
+ }
+
+up_out:
+ up(&ioctl_sem);
+ return ret;
+}
+
+void dsp_runlevel(unsigned char level)
+{
+ if (level == OMAP_DSP_MBCMD_RUNLEVEL_RECOVERY)
+ dsp_mbsend_recovery(MBCMD(RUNLEVEL), level, 0);
+ else
+ dsp_mbsend(MBCMD(RUNLEVEL), level, 0);
+}
+
+static enum cfgstat cfgstat_save_suspend;
+
+/*
+ * suspend / resume callbacks
+ * DSP is not reset within this code, but done in omap_pm_suspend.
+ * so if these functions are called as OMAP_DSP_IOCTL_SUSPEND,
+ * DSP should be reset / unreset out of these functions.
+ */
+int dsp_suspend(void)
+{
+ struct mbcmd mb;
+ int ret = 0;
+
+ if (cfgstat == CFG_SUSPEND) {
+ printk(KERN_ERR "omapdsp: DSP is already in suspend state.\n");
+ return -EINVAL;
+ }
+
+ if (down_interruptible(&ioctl_sem))
+ return -ERESTARTSYS;
+
+ cfgstat_save_suspend = cfgstat;
+ if (!dsp_is_ready()) {
+ if (dsp_cpustat_get_stat() == CPUSTAT_RUN) {
+ printk(KERN_WARNING
+ "omapdsp: illegal operation: trying suspend DSP "
+ "while it is running but has not configured "
+ "yet.\n"
+ " Resetting DSP...\n");
+ }
+ goto transition;
+ }
+
+ ioctl_wait_cmd = MBCMD(SUSPEND);
+ mbcmd_set(mb, MBCMD(SUSPEND), 0, 0);
+ dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
+
+ if (ioctl_wait_cmd != 0) {
+ printk(KERN_ERR "omapdsp: DSP suspend error!\n");
+ ret = -EINVAL;
+ goto up_out;
+ }
+
+ udelay(100);
+transition:
+ cfgstat = CFG_SUSPEND;
+up_out:
+ up(&ioctl_sem);
+ return ret;
+}
+
+int dsp_resume(void)
+{
+ if (cfgstat != CFG_SUSPEND) {
+ printk(KERN_ERR "omapdsp: DSP is not in suspend state.\n");
+ return -EINVAL;
+ }
+
+ cfgstat = cfgstat_save_suspend;
+ return 0;
+}
+
+static void dsp_fbctl_enable(void)
+{
+ dsp_mbsend(MBCMD(KFUNC), OMAP_DSP_MBCMD_KFUNC_FBCTL,
+ OMAP_DSP_MBCMD_FBCTL_ENABLE);
+}
+
+static int dsp_fbctl_disable(void)
+{
+ int ret = 0;
+ struct mbcmd mb;
+
+ if (down_interruptible(&ioctl_sem))
+ return -ERESTARTSYS;
+
+ ioctl_wait_cmd = MBCMD(KFUNC);
+ mbcmd_set(mb, MBCMD(KFUNC), OMAP_DSP_MBCMD_KFUNC_FBCTL,
+ OMAP_DSP_MBCMD_FBCTL_DISABLE);
+ dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
+ if (ioctl_wait_cmd != 0) {
+ printk(KERN_ERR "omapdsp: fb disable error!\n");
+ ret = -EINVAL;
+ }
+ up(&ioctl_sem);
+
+ return ret;
+}
+
+/*
+ * 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 OMAP_DSP_IOCTL_RUN:
+ dsp_cpustat_request(CPUSTAT_RUN);
+ break;
+
+ case OMAP_DSP_IOCTL_RESET:
+ dsp_cpustat_request(CPUSTAT_RESET);
+ break;
+
+ case OMAP_DSP_IOCTL_SETRSTVECT:
+ ret = dsp_set_rstvect((unsigned long)arg);
+ break;
+
+ case OMAP_DSP_IOCTL_CPU_IDLE:
+ dsp_cpustat_request(CPUSTAT_CPU_IDLE);
+ break;
+
+ case OMAP_DSP_IOCTL_GBL_IDLE:
+ dsp_cpustat_request(CPUSTAT_GBL_IDLE);
+ break;
+
+ case OMAP_DSP_IOCTL_MPUI_WORDSWAP_ON:
+ mpui_wordswap_on();
+ break;
+
+ case OMAP_DSP_IOCTL_MPUI_WORDSWAP_OFF:
+ mpui_wordswap_off();
+ break;
+
+ case OMAP_DSP_IOCTL_MPUI_BYTESWAP_ON:
+ mpui_byteswap_on();
+ break;
+
+ case OMAP_DSP_IOCTL_MPUI_BYTESWAP_OFF:
+ mpui_byteswap_off();
+ break;
+
+ case OMAP_DSP_IOCTL_MBSEND:
+ {
+ struct omap_dsp_mailbox_cmd u_cmd;
+ struct mbcmd_hw mb;
+ if (copy_from_user(&u_cmd, (void *)arg, sizeof(u_cmd)))
+ return -EFAULT;
+ mb.cmd = u_cmd.cmd;
+ mb.data = u_cmd.data;
+ ret = dsp_mbcmd_send((struct mbcmd *)&mb);
+ break;
+ }
+
+ case OMAP_DSP_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 OMAP_DSP_IOCTL_RUNLEVEL:
+ dsp_runlevel(arg);
+ break;
+
+ case OMAP_DSP_IOCTL_FBEN:
+ dsp_fbctl_enable();
+ return 0;
+
+ /*
+ * command level 2: commands which need lock
+ */
+ case OMAP_DSP_IOCTL_DSPCFG:
+ ret = dspcfg();
+ break;
+
+ case OMAP_DSP_IOCTL_DSPUNCFG:
+ ret = dspuncfg();
+ break;
+
+ case OMAP_DSP_IOCTL_TASKCNT:
+ ret = dsp_task_count();
+ break;
+
+ case OMAP_DSP_IOCTL_POLL:
+ ret = dsp_poll();
+ break;
+
+ case OMAP_DSP_IOCTL_FBDIS:
+ ret = dsp_fbctl_disable();
+ break;
+
+ /*
+ * FIXME: cpu status control for suspend - resume
+ */
+ case OMAP_DSP_IOCTL_SUSPEND:
+ if ((ret = dsp_suspend()) < 0)
+ break;
+ dsp_cpustat_request(CPUSTAT_RESET);
+ break;
+
+ case OMAP_DSP_IOCTL_RESUME:
+ if ((ret = dsp_resume()) < 0)
+ break;
+ dsp_cpustat_request(CPUSTAT_RUN);
+ break;
+
+ case OMAP_DSP_IOCTL_REGMEMR:
+ {
+ struct omap_dsp_reginfo *u_reg = (void *)arg;
+ unsigned short adr, val;
+
+ if (copy_from_user(&adr, &u_reg->adr, sizeof(short)))
+ return -EFAULT;
+ if ((ret = dsp_regread(OMAP_DSP_MBCMD_REGRW_MEMR,
+ adr, &val)) < 0)
+ return ret;
+ if (copy_to_user(&u_reg->val, &val, sizeof(short)))
+ return -EFAULT;
+ break;
+ }
+
+ case OMAP_DSP_IOCTL_REGMEMW:
+ {
+ struct omap_dsp_reginfo reg;
+
+ if (copy_from_user(®, (void *)arg, sizeof(reg)))
+ return -EFAULT;
+ ret = dsp_regwrite(OMAP_DSP_MBCMD_REGRW_MEMW,
+ reg.adr, reg.val);
+ break;
+ }
+
+ case OMAP_DSP_IOCTL_REGIOR:
+ {
+ struct omap_dsp_reginfo *u_reg = (void *)arg;
+ unsigned short adr, val;
+
+ if (copy_from_user(&adr, &u_reg->adr, sizeof(short)))
+ return -EFAULT;
+ if ((ret = dsp_regread(OMAP_DSP_MBCMD_REGRW_IOR,
+ adr, &val)) < 0)
+ return ret;
+ if (copy_to_user(&u_reg->val, &val, sizeof(short)))
+ return -EFAULT;
+ break;
+ }
+
+ case OMAP_DSP_IOCTL_REGIOW:
+ {
+ struct omap_dsp_reginfo reg;
+
+ if (copy_from_user(®, (void *)arg, sizeof(reg)))
+ return -EFAULT;
+ ret = dsp_regwrite(OMAP_DSP_MBCMD_REGRW_IOW,
+ reg.adr, reg.val);
+ break;
+ }
+
+ case OMAP_DSP_IOCTL_GETVAR:
+ {
+ struct omap_dsp_varinfo *u_var = (void *)arg;
+ unsigned char varid;
+ unsigned short val[5]; /* maximum */
+ int argc;
+
+ if (copy_from_user(&varid, &u_var->varid, sizeof(char)))
+ return -EFAULT;
+ switch (varid) {
+ case OMAP_DSP_MBCMD_VARID_ICRMASK:
+ argc = 1;
+ break;
+ case OMAP_DSP_MBCMD_VARID_LOADINFO:
+ argc = 5;
+ break;
+ default:
+ return -EINVAL;
+ }
+ if ((ret = dsp_getvar(varid, val, argc)) < 0)
+ return ret;
+ if (copy_to_user(&u_var->val, val, sizeof(short) * argc))
+ return -EFAULT;
+ break;
+ }
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return ret;
+}
+
+/*
+ * functions called from mailbox1 interrupt routine
+ */
+void mbx1_suspend(struct mbcmd *mb)
+{
+ if (!waitqueue_active(&ioctl_wait_q) ||
+ (ioctl_wait_cmd != MBCMD(SUSPEND))) {
+ printk(KERN_WARNING
+ "mbx: SUSPEND command received, "
+ "but nobody is waiting for it...\n");
+ return;
+ }
+
+ ioctl_wait_cmd = 0;
+ wake_up_interruptible(&ioctl_wait_q);
+}
+
+void mbx1_dspcfg(struct mbcmd *mb)
+{
+ unsigned char last = mb->cmd_l & 0x80;
+ unsigned char cfgcmd = mb->cmd_l & 0x7f;
+ static unsigned long tmp_ipb_adr;
+
+ /* mailbox protocol check */
+ if (cfgcmd == OMAP_DSP_MBCMD_DSPCFG_PROTREV) {
+ if (!waitqueue_active(&ioctl_wait_q) ||
+ (ioctl_wait_cmd != MBCMD(DSPCFG))) {
+ printk(KERN_WARNING
+ "mbx: DSPCFG command received, "
+ "but nobody is waiting for it...\n");
+ return;
+ }
+
+ mbx_revision = mb->data;
+ if (mbx_revision == OMAP_DSP_MBPROT_REVISION)
+ return;
+#ifdef OLD_BINARY_SUPPORT
+ else if ((mbx_revision == MBREV_3_0) ||
+ (mbx_revision == MBREV_3_2)) {
+ printk(KERN_WARNING
+ "mbx: ***** old DSP binary *****\n"
+ " Please update your DSP application.\n");
+ return;
+ }
+#endif
+ else {
+ printk(KERN_ERR
+ "mbx: protocol revision check error!\n"
+ " expected=0x%04x, received=0x%04x\n",
+ OMAP_DSP_MBPROT_REVISION, mb->data);
+ mbx_revision = -1;
+ goto abort1;
+ }
+ }
+
+ /*
+ * following commands are accepted only after
+ * revision check has been passed.
+ */
+ if (!mbx_revision < 0) {
+ printk(KERN_INFO
+ "mbx: DSPCFG command received, "
+ "but revision check has not been passed.\n");
+ return;
+ }
+
+ if (!waitqueue_active(&ioctl_wait_q) ||
+ (ioctl_wait_cmd != MBCMD(DSPCFG))) {
+ printk(KERN_WARNING
+ "mbx: DSPCFG command received, "
+ "but nobody is waiting for it...\n");
+ return;
+ }
+
+ switch (cfgcmd) {
+ case OMAP_DSP_MBCMD_DSPCFG_SYSADRH:
+ tmp_ipb_adr = (unsigned long)mb->data << 16;
+ break;
+
+ case OMAP_DSP_MBCMD_DSPCFG_SYSADRL:
+ tmp_ipb_adr |= mb->data;
+ break;
+
+ case OMAP_DSP_MBCMD_DSPCFG_ABORT:
+ goto abort1;
+
+ default:
+ printk(KERN_ERR
+ "mbx: Unknown CFG command: cmd_l=0x%02x, data=0x%04x\n",
+ mb->cmd_l, mb->data);
+ return;
+ }
+
+ if (last) {
+ void *badr;
+ unsigned short bln;
+ unsigned short bsz;
+ volatile unsigned short *buf;
+ void *ipb_sys_da, *ipb_sys_ad;
+ void *mbseq;
+ short *dbg_buf;
+ unsigned short 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 (sync_with_dsp(&ipbuf_sys_da->s, OMAP_DSP_TID_ANON, 10) < 0) {
+ printk(KERN_ERR "mbx: DSPCFG - IPBUF sync failed!\n");
+ goto abort1;
+ }
+ /*
+ * read configuration data on system IPBUF
+ * we must read with 16bit-access
+ */
+#ifdef OLD_BINARY_SUPPORT
+ if (mbx_revision == OMAP_DSP_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 (mbx_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 (mbx_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 */
+ goto abort1;
+#endif /* OLD_BINARY_SUPPORT */
+
+ release_ipbuf_pvt(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_mb_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;
+
+ ioctl_wait_cmd = 0;
+ wake_up_interruptible(&ioctl_wait_q);
+ }
+ return;
+
+abort2:
+ ipbuf_stop();
+abort1:
+ wake_up_interruptible(&ioctl_wait_q);
+ return;
+}
+
+void mbx1_poll(struct mbcmd *mb)
+{
+ if (!waitqueue_active(&ioctl_wait_q) ||
+ (ioctl_wait_cmd != MBCMD(POLL))) {
+ printk(KERN_WARNING
+ "mbx: POLL command received, "
+ "but nobody is waiting for it...\n");
+ return;
+ }
+
+ ioctl_wait_cmd = 0;
+ wake_up_interruptible(&ioctl_wait_q);
+}
+
+void mbx1_regrw(struct mbcmd *mb)
+{
+ if (!waitqueue_active(&ioctl_wait_q) ||
+ (ioctl_wait_cmd != MBCMD(REGRW))) {
+ printk(KERN_WARNING
+ "mbx: REGRW command received, "
+ "but nobody is waiting for it...\n");
+ return;
+ }
+
+ switch (mb->cmd_l) {
+ case OMAP_DSP_MBCMD_REGRW_DATA:
+ ioctl_wait_cmd = 0;
+ varread_val[0] = mb->data;
+ wake_up_interruptible(&ioctl_wait_q);
+ return;
+
+ default:
+ printk(KERN_ERR
+ "mbx: Illegal REGRW command: "
+ "cmd_l=0x%02x, data=0x%04x\n", mb->cmd_l, mb->data);
+ return;
+ }
+}
+
+void mbx1_getvar(struct mbcmd *mb)
+{
+ unsigned char varid = mb->cmd_l;
+ int i;
+ volatile unsigned short *buf;
+
+ if (!waitqueue_active(&ioctl_wait_q) ||
+ (ioctl_wait_cmd != MBCMD(GETVAR))) {
+ printk(KERN_WARNING
+ "mbx: GETVAR command received, "
+ "but nobody is waiting for it...\n");
+ return;
+ }
+
+ ioctl_wait_cmd = 0;
+ switch (varid) {
+ case OMAP_DSP_MBCMD_VARID_ICRMASK:
+ varread_val[0] = mb->data;
+ break;
+ case OMAP_DSP_MBCMD_VARID_LOADINFO:
+ {
+ if (sync_with_dsp(&ipbuf_sys_da->s, OMAP_DSP_TID_ANON, 10) < 0) {
+ printk(KERN_ERR
+ "mbx: GETVAR - IPBUF sync failed!\n");
+ return;
+ }
+ /* need word access. do not use memcpy. */
+ buf = ipbuf_sys_da->d;
+ for (i = 0; i < 5; i++) {
+ varread_val[i] = buf[i];
+ }
+ release_ipbuf_pvt(ipbuf_sys_da);
+ break;
+ }
+ }
+ wake_up_interruptible(&ioctl_wait_q);
+
+ return;
+}
+
+/*
+ * sysfs files
+ */
+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
+ * OMAP_DSP_IOCTL_GBL_IDLE
+ * OMAP_DSP_IOCTL_CPU_IDLE (instead of OMAP_DSP_IOCTL_IDLE)
+ * OMAP_DSP_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;
+}
+
+static struct device_attribute dev_attr_ifver = __ATTR_RO(ifver);
+
+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()));
+}
+
+static struct device_attribute dev_attr_cpustat = __ATTR_RO(cpustat);
+
+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)
+{
+ unsigned short mask;
+ int ret;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ mask = simple_strtol(buf, NULL, 16);
+ dsp_cpustat_set_icrmask(mask);
+
+ if (dsp_is_ready()) {
+ ret = dsp_setvar(OMAP_DSP_MBCMD_VARID_ICRMASK, mask);
+ if (ret < 0)
+ return ret;
+ }
+
+ return strlen(buf);
+}
+
+static struct device_attribute dev_attr_icrmask =
+ __ATTR(icrmask, S_IWUSR | S_IRUGO, icrmask_show, icrmask_store);
+
+static ssize_t loadinfo_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int len;
+ int ret;
+ static unsigned short val[5];
+
+ if ((ret = dsp_getvar(OMAP_DSP_MBCMD_VARID_LOADINFO, val, 5)) < 0)
+ return ret;
+
+ /* load info value range is 0(free) - 10000(busy) */
+ 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);
+ return len;
+}
+
+/*
+ * This is declared at the top of this file.
+ *
+ * static struct device_attribute dev_attr_loadinfo = __ATTR_RO(loadinfo);
+ */
+
+void mbx1_fbctl_disable(void)
+{
+ if (!waitqueue_active(&ioctl_wait_q) ||
+ (ioctl_wait_cmd != MBCMD(KFUNC))) {
+ printk(KERN_WARNING
+ "mbx: KFUNC:FBCTL command received, "
+ "but nobody is waiting for it...\n");
+ return;
+ }
+ ioctl_wait_cmd = 0;
+ wake_up_interruptible(&ioctl_wait_q);
+}
+
+#ifdef CONFIG_PROC_FS
+/* for backward compatibility */
+static int version_read_proc(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ /*
+ * This entry is read by 3.1 tools only, so leave it as is.
+ * 3.2 and later will read from sysfs file.
+ */
+ return sprintf(page, "3.1\n");
+}
+
+static void __init dsp_ctl_create_proc(void)
+{
+ struct proc_dir_entry *ent;
+
+ /* version */
+ ent = create_proc_read_entry("version", 0, procdir_dsp,
+ version_read_proc, NULL);
+ if (ent == NULL) {
+ printk(KERN_ERR
+ "omapdsp: failed to register proc device: version\n");
+ }
+}
+
+static void dsp_ctl_remove_proc(void)
+{
+ remove_proc_entry("version", procdir_dsp);
+}
+#endif /* CONFIG_PROC_FS */
+
+struct file_operations dsp_ctl_fops = {
+ .owner = THIS_MODULE,
+ .ioctl = dsp_ctl_ioctl,
+};
+
+void __init dsp_ctl_init(void)
+{
+ device_create_file(&dsp_device.dev, &dev_attr_ifver);
+ device_create_file(&dsp_device.dev, &dev_attr_cpustat);
+ device_create_file(&dsp_device.dev, &dev_attr_icrmask);
+#ifdef CONFIG_PROC_FS
+ dsp_ctl_create_proc();
+#endif
+}
+
+void dsp_ctl_exit(void)
+{
+ device_remove_file(&dsp_device.dev, &dev_attr_ifver);
+ device_remove_file(&dsp_device.dev, &dev_attr_cpustat);
+ device_remove_file(&dsp_device.dev, &dev_attr_icrmask);
+#ifdef CONFIG_PROC_FS
+ dsp_ctl_remove_proc();
+#endif
+}
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap/dsp/dsp_ctl_core.c
+ *
+ * OMAP DSP control devices core driver
+ *
+ * Copyright (C) 2004,2005 Nokia Corporation
+ *
+ * Written by 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 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
+ *
+ * 2005/07/26: DSP Gateway version 3.3
+ */
+
+#include <linux/module.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <asm/arch/dsp.h>
+#include "hardware_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)
+{
+ 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;
+ struct class_device *cdev;
+
+ 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++) {
+ cdev = class_device_create(dsp_ctl_class, NULL,
+ MKDEV(OMAP_DSP_CTL_MAJOR,
+ dev_list[i].minor),
+ NULL, dev_list[i].devname);
+ }
+
+ return 0;
+}
+
+void dsp_ctl_core_exit(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dev_list); i++) {
+ class_device_destroy(dsp_ctl_class,
+ MKDEV(OMAP_DSP_CTL_MAJOR,
+ dev_list[i].minor));
+ }
+ class_destroy(dsp_ctl_class);
+
+ unregister_chrdev(OMAP_DSP_CTL_MAJOR, "dspctl");
+}
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap/dsp/dsp_mem.c
+ *
+ * OMAP DSP memory driver
+ *
+ * Copyright (C) 2002-2005 Nokia Corporation
+ *
+ * Written by 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 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
+ *
+ * Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ * 2005/06/09: DSP Gateway version 3.3
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/bootmem.h>
+#include <linux/fb.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mempool.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/ioctls.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/dsp_common.h>
+#include "uaccess_dsp.h"
+#include "ipbuf.h"
+#include "dsp.h"
+
+#define SZ_1MB 0x100000
+#define SZ_64KB 0x10000
+#define SZ_4KB 0x1000
+#define SZ_1KB 0x400
+#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 PGDIR_MASK (~(PGDIR_SIZE-1))
+#define PGDIR_ALIGN(addr) (((addr)+PGDIR_SIZE-1)&(PGDIR_MASK))
+
+#define dsp_mmu_enable() \
+ do { \
+ omap_writew(DSPMMU_CNTL_MMU_EN | DSPMMU_CNTL_RESET_SW, \
+ DSPMMU_CNTL); \
+ } while(0)
+#define dsp_mmu_disable() \
+ do { omap_writew(0, DSPMMU_CNTL); } while(0)
+#define dsp_mmu_flush() \
+ do { \
+ omap_writew(DSPMMU_FLUSH_ENTRY_FLUSH_ENTRY, \
+ DSPMMU_FLUSH_ENTRY); \
+ } while(0)
+#define __dsp_mmu_gflush() \
+ do { omap_writew(DSPMMU_GFLUSH_GFLUSH, DSPMMU_GFLUSH); } while(0)
+#define __dsp_mmu_itack() \
+ do { omap_writew(DSPMMU_IT_ACK_IT_ACK, DSPMMU_IT_ACK); } while(0)
+
+#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)
+
+enum exmap_type {
+ EXMAP_TYPE_MEM,
+ EXMAP_TYPE_FB
+};
+
+struct exmap_tbl {
+ unsigned int valid:1;
+ unsigned int cntnu:1; /* grouping */
+ 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;
+};
+#define DSPMMU_TLB_LINES 32
+static struct exmap_tbl exmap_tbl[DSPMMU_TLB_LINES];
+static DECLARE_RWSEM(exmap_sem);
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+static struct omapfb_notifier_block *omapfb_nb;
+static int omapfb_ready;
+#endif
+
+static int dsp_exunmap(unsigned long dspadr);
+
+static void *dspvect_page;
+static unsigned long dsp_fault_adr;
+static struct mem_sync_struct mem_sync;
+
+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);
+}
+
+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;
+}
+
+void dsp_mem_sync_inc(void)
+{
+ /*
+ * FIXME: dsp_mem_enable()!!!
+ */
+ 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_sync_config() is called from mbx1 workqueue
+ */
+int dsp_mem_sync_config(struct mem_sync_struct *sync)
+{
+ size_t sync_seq_sz = sizeof(struct sync_seq);
+
+#ifdef OLD_BINARY_SUPPORT
+ if (sync == NULL) {
+ memset(&mem_sync, 0, sizeof(struct mem_sync_struct));
+ return 0;
+ }
+#endif
+ if ((dsp_mem_type(sync->DARAM, sync_seq_sz) != MEM_TYPE_DARAM) ||
+ (dsp_mem_type(sync->SARAM, sync_seq_sz) != MEM_TYPE_SARAM) ||
+ (dsp_mem_type(sync->SDRAM, sync_seq_sz) != MEM_TYPE_EXTERN)) {
+ printk(KERN_ERR
+ "omapdsp: mem_sync address validation failure!\n"
+ " mem_sync.DARAM = 0x%p,\n"
+ " mem_sync.SARAM = 0x%p,\n"
+ " mem_sync.SDRAM = 0x%p,\n",
+ sync->DARAM, sync->SARAM, sync->SDRAM);
+ return -1;
+ }
+ memcpy(&mem_sync, sync, sizeof(struct mem_sync_struct));
+ return 0;
+}
+
+static mempool_t *kmem_pool_1M;
+static mempool_t *kmem_pool_64K;
+
+static void *dsp_pool_alloc(unsigned int __nocast gfp, void *order)
+{
+ return (void *)__get_dma_pages(gfp, (unsigned int)order);
+}
+
+static void dsp_pool_free(void *buf, void *order)
+{
+ free_pages((unsigned long)buf, (unsigned int)order);
+}
+
+static void dsp_kmem_release(void)
+{
+ if (kmem_pool_64K) {
+ mempool_destroy(kmem_pool_64K);
+ kmem_pool_64K = NULL;
+ }
+
+ if (kmem_pool_1M) {
+ mempool_destroy(kmem_pool_1M);
+ kmem_pool_1M = NULL;
+ }
+}
+
+static int dsp_kmem_reserve(unsigned long size)
+{
+ unsigned long len = size;
+
+ /* alignment check */
+ if (!is_aligned(size, SZ_64KB)) {
+ printk(KERN_ERR
+ "omapdsp: size(0x%lx) is not multiple of 64KB.\n", size);
+ return -EINVAL;
+ }
+ if (size > DSPSPACE_SIZE) {
+ printk(KERN_ERR
+ "omapdsp: size(0x%lx) is larger than DSP memory space "
+ "size (0x%x.\n", size, DSPSPACE_SIZE);
+ return -EINVAL;
+ }
+
+ if (size >= SZ_1MB) {
+ int nr = size >> 20;
+
+ if (likely(!kmem_pool_1M))
+ kmem_pool_1M = mempool_create(nr,
+ dsp_pool_alloc,
+ dsp_pool_free,
+ (void *)ORDER_1MB);
+ else
+ mempool_resize(kmem_pool_1M, kmem_pool_1M->min_nr + nr,
+ GFP_KERNEL);
+
+ size &= ~(0xf << 20);
+ }
+
+ if (size >= SZ_64KB) {
+ int nr = size >> 16;
+
+ if (likely(!kmem_pool_64K))
+ kmem_pool_64K = mempool_create(nr,
+ dsp_pool_alloc,
+ dsp_pool_free,
+ (void *)ORDER_64KB);
+ else
+ mempool_resize(kmem_pool_64K,
+ kmem_pool_64K->min_nr + nr, GFP_KERNEL);
+
+ size &= ~(0xf << 16);
+ }
+
+ if (size)
+ len -= size;
+
+ return len;
+}
+
+static void dsp_mem_free_pages(unsigned long buf, unsigned int order)
+{
+ struct page *page, *ps, *pe;
+
+ ps = virt_to_page(buf);
+ pe = virt_to_page(buf + (1 << (PAGE_SHIFT + order)));
+
+ for (page = ps; page < pe; page++)
+ ClearPageReserved(page);
+
+ if (buf) {
+ if ((order == ORDER_64KB) && likely(kmem_pool_64K))
+ mempool_free((void *)buf, kmem_pool_64K);
+ else if ((order == ORDER_1MB) && likely(kmem_pool_1M))
+ mempool_free((void *)buf, kmem_pool_1M);
+ else
+ free_pages(buf, order);
+ }
+}
+
+static inline void
+exmap_alloc_pte(unsigned long virt, unsigned long phys, pgprot_t prot)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ pgd = pgd_offset_k(virt);
+ pud = pud_offset(pgd, virt);
+ pmd = pmd_offset(pud, virt);
+
+ if (pmd_none(*pmd)) {
+ pte = pte_alloc_one_kernel(&init_mm, 0);
+ if (!pte)
+ return;
+
+ /* note: two PMDs will be set */
+ pmd_populate_kernel(&init_mm, pmd, pte);
+ }
+
+ pte = pte_offset_kernel(pmd, virt);
+ set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, prot));
+}
+
+static inline int
+exmap_alloc_sect(unsigned long virt, unsigned long phys, int prot)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+
+ pgd = pgd_offset_k(virt);
+ pud = pud_alloc(&init_mm, pgd, virt);
+ pmd = pmd_alloc(&init_mm, pud, virt);
+
+ if (virt & (1 << 20))
+ pmd++;
+
+ if (!pmd_none(*pmd))
+ /* No good, fall back on smaller mappings. */
+ return -EINVAL;
+
+ *pmd = __pmd(phys | prot);
+ flush_pmd_entry(pmd);
+
+ return 0;
+}
+
+/*
+ * ARM MMU operations
+ */
+static int exmap_set_armmmu(unsigned long virt, unsigned long phys,
+ unsigned long size)
+{
+ long off;
+ pgprot_t prot_pte;
+ int prot_sect;
+
+ printk(KERN_DEBUG
+ "omapdsp: mapping in ARM MMU, v=0x%08lx, p=0x%08lx, sz=0x%lx\n",
+ virt, phys, size);
+
+ prot_pte = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG |
+ L_PTE_DIRTY | L_PTE_WRITE);
+
+ prot_sect = PMD_TYPE_SECT | PMD_SECT_UNCACHED |
+ PMD_SECT_AP_WRITE | PMD_DOMAIN(DOMAIN_IO);
+
+ if (cpu_architecture() <= CPU_ARCH_ARMv5)
+ prot_sect |= PMD_BIT4;
+
+ off = phys - virt;
+
+ while ((virt & 0xfffff || (virt + off) & 0xfffff) && size >= PAGE_SIZE) {
+ exmap_alloc_pte(virt, virt + off, prot_pte);
+
+ virt += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ /* XXX: Not yet.. confuses dspfb -- PFM. */
+#if 0
+ while (size >= (PGDIR_SIZE / 2)) {
+ if (exmap_alloc_sect(virt, virt + off, prot_sect) < 0)
+ break;
+
+ virt += (PGDIR_SIZE / 2);
+ size -= (PGDIR_SIZE / 2);
+ }
+#endif
+
+ while (size >= PAGE_SIZE) {
+ exmap_alloc_pte(virt, virt + off, prot_pte);
+
+ virt += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ BUG_ON(size);
+
+ return 0;
+}
+
+static inline void
+exmap_clear_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end)
+{
+ pte_t *pte;
+
+ pte = pte_offset_map(pmd, addr);
+ do {
+ if (pte_none(*pte))
+ continue;
+
+ pte_clear(&init_mm, addr, pte);
+ } while (pte++, addr += PAGE_SIZE, addr != end);
+
+ pte_unmap(pte - 1);
+}
+
+static inline void
+exmap_clear_pmd_range(pud_t *pud, unsigned long addr, unsigned long end)
+{
+ pmd_t *pmd;
+ unsigned long next;
+
+ pmd = pmd_offset(pud, addr);
+ do {
+ next = pmd_addr_end(addr, end);
+
+ if (addr & (1 << 20))
+ pmd++;
+
+ if ((pmd_val(*pmd) & PMD_TYPE_MASK) == PMD_TYPE_SECT) {
+ *pmd = __pmd(0);
+ clean_pmd_entry(pmd);
+ continue;
+ }
+
+ if (pmd_none_or_clear_bad(pmd))
+ continue;
+
+ exmap_clear_pte_range(pmd, addr, next);
+ } while (pmd++, addr = next, addr != end);
+}
+
+static inline void
+exmap_clear_pud_range(pgd_t *pgd, unsigned long addr, unsigned long end)
+{
+ pud_t *pud;
+ unsigned long next;
+
+ pud = pud_offset(pgd, addr);
+ do {
+ next = pud_addr_end(addr, end);
+ if (pud_none_or_clear_bad(pud))
+ continue;
+
+ exmap_clear_pmd_range(pud, addr, next);
+ } while (pud++, addr = next, addr != end);
+}
+
+static void exmap_clear_armmmu(unsigned long virt, unsigned long size)
+{
+ unsigned long next, end;
+ pgd_t *pgd;
+
+ printk(KERN_DEBUG
+ "omapdsp: unmapping in ARM MMU, v=0x%08lx, sz=0x%lx\n",
+ virt, size);
+
+ pgd = pgd_offset_k(virt);
+ end = virt + size;
+ do {
+ next = pgd_addr_end(virt, end);
+ if (pgd_none_or_clear_bad(pgd))
+ continue;
+
+ exmap_clear_pud_range(pgd, virt, next);
+ } while (pgd++, virt = next, virt != end);
+}
+
+static int exmap_valid(void *vadr, size_t len)
+{
+ /* exmap_sem should be held before calling this function */
+ int i;
+
+start:
+ for (i = 0; i < DSPMMU_TLB_LINES; i++) {
+ void *mapadr;
+ unsigned long mapsize;
+ struct exmap_tbl *ent = &exmap_tbl[i];
+
+ if (!ent->valid)
+ continue;
+ mapadr = (void *)ent->vadr;
+ mapsize = 1 << (ent->order + PAGE_SHIFT);
+ if ((vadr >= mapadr) && (vadr < mapadr + mapsize)) {
+ if (vadr + len <= mapadr + mapsize) {
+ /* this map covers whole address. */
+ return 1;
+ } else {
+ /*
+ * this map covers partially.
+ * check rest portion.
+ */
+ len -= mapadr + mapsize - vadr;
+ vadr = mapadr + mapsize;
+ goto start;
+ }
+ }
+ }
+
+ return 0;
+}
+
+enum dsp_mem_type_e dsp_mem_type(void *vadr, size_t len)
+{
+ void *ds = (void *)daram_base;
+ void *de = (void *)daram_base + daram_size;
+ void *ss = (void *)saram_base;
+ void *se = (void *)saram_base + saram_size;
+ int ret;
+
+ if ((vadr >= ds) && (vadr < de)) {
+ if (vadr + len > de)
+ return MEM_TYPE_CROSSING;
+ else
+ return MEM_TYPE_DARAM;
+ } else if ((vadr >= ss) && (vadr < se)) {
+ if (vadr + len > se)
+ return MEM_TYPE_CROSSING;
+ else
+ return MEM_TYPE_SARAM;
+ } else {
+ down_read(&exmap_sem);
+ if (exmap_valid(vadr, len))
+ ret = MEM_TYPE_EXTERN;
+ else
+ ret = MEM_TYPE_NONE;
+ up_read(&exmap_sem);
+ return ret;
+ }
+}
+
+int dsp_address_validate(void *p, size_t len, char *fmt, ...)
+{
+ if (dsp_mem_type(p, len) <= 0) {
+ if (fmt != NULL) {
+ char s[64];
+ va_list args;
+
+ va_start(args, fmt);
+ vsprintf(s, fmt, args);
+ va_end(args);
+ printk(KERN_ERR
+ "omapdsp: %s address(0x%p) and size(0x%x) is "
+ "not valid!\n"
+ " (crossing different type of memories, or \n"
+ " external memory space where no "
+ "actual memory is mapped)\n",
+ s, p, len);
+ }
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * exmap_use(), unuse():
+ * when the mapped area is exported to user space with mmap,
+ * the usecount is incremented.
+ * while the usecount > 0, that area can't be released.
+ */
+void exmap_use(void *vadr, size_t len)
+{
+ int i;
+
+ down_write(&exmap_sem);
+ for (i = 0; i < DSPMMU_TLB_LINES; i++) {
+ void *mapadr;
+ unsigned long mapsize;
+ struct exmap_tbl *ent = &exmap_tbl[i];
+
+ if (!ent->valid)
+ continue;
+ mapadr = (void *)ent->vadr;
+ mapsize = 1 << (ent->order + PAGE_SHIFT);
+ if ((vadr + len > mapadr) && (vadr < mapadr + mapsize)) {
+ ent->usecount++;
+ }
+ }
+ up_write(&exmap_sem);
+}
+
+void exmap_unuse(void *vadr, size_t len)
+{
+ int i;
+
+ down_write(&exmap_sem);
+ for (i = 0; i < DSPMMU_TLB_LINES; i++) {
+ void *mapadr;
+ unsigned long mapsize;
+ struct exmap_tbl *ent = &exmap_tbl[i];
+
+ if (!ent->valid)
+ continue;
+ mapadr = (void *)ent->vadr;
+ mapsize = 1 << (ent->order + PAGE_SHIFT);
+ if ((vadr + len > mapadr) && (vadr < mapadr + mapsize)) {
+ ent->usecount--;
+ }
+ }
+ up_write(&exmap_sem);
+}
+
+/*
+ * dsp_virt_to_phys()
+ * returns physical address, and sets len to valid length
+ */
+unsigned long dsp_virt_to_phys(void *vadr, size_t *len)
+{
+ int i;
+
+ if (is_dsp_internal_mem(vadr)) {
+ /* DSRAM or SARAM */
+ *len = dspmem_base + dspmem_size - (unsigned long)vadr;
+ return (unsigned long)vadr;
+ }
+
+ /* EXRAM */
+ for (i = 0; i < DSPMMU_TLB_LINES; i++) {
+ void *mapadr;
+ unsigned long mapsize;
+ struct exmap_tbl *ent = &exmap_tbl[i];
+
+ if (!ent->valid)
+ continue;
+ mapadr = (void *)ent->vadr;
+ mapsize = 1 << (ent->order + PAGE_SHIFT);
+ if ((vadr >= mapadr) && (vadr < mapadr + mapsize)) {
+ *len = mapadr + mapsize - vadr;
+ return __pa(ent->buf) + vadr - mapadr;
+ }
+ }
+
+ /* valid mapping not found */
+ return 0;
+}
+
+/*
+ * DSP MMU operations
+ */
+static __inline__ unsigned short get_cam_l_va_mask(unsigned short slst)
+{
+ switch (slst) {
+ case DSPMMU_CAM_L_SLST_1MB:
+ return DSPMMU_CAM_L_VA_TAG_L1_MASK |
+ DSPMMU_CAM_L_VA_TAG_L2_MASK_1MB;
+ case DSPMMU_CAM_L_SLST_64KB:
+ return DSPMMU_CAM_L_VA_TAG_L1_MASK |
+ DSPMMU_CAM_L_VA_TAG_L2_MASK_64KB;
+ case DSPMMU_CAM_L_SLST_4KB:
+ return DSPMMU_CAM_L_VA_TAG_L1_MASK |
+ DSPMMU_CAM_L_VA_TAG_L2_MASK_4KB;
+ case DSPMMU_CAM_L_SLST_1KB:
+ return DSPMMU_CAM_L_VA_TAG_L1_MASK |
+ DSPMMU_CAM_L_VA_TAG_L2_MASK_1KB;
+ }
+ return 0;
+}
+
+static __inline__ void get_tlb_lock(int *base, int *victim)
+{
+ unsigned short lock = omap_readw(DSPMMU_LOCK);
+ if (base != NULL)
+ *base = (lock & DSPMMU_LOCK_BASE_MASK)
+ >> DSPMMU_LOCK_BASE_SHIFT;
+ if (victim != NULL)
+ *victim = (lock & DSPMMU_LOCK_VICTIM_MASK)
+ >> DSPMMU_LOCK_VICTIM_SHIFT;
+}
+
+static __inline__ void set_tlb_lock(int base, int victim)
+{
+ omap_writew((base << DSPMMU_LOCK_BASE_SHIFT) |
+ (victim << DSPMMU_LOCK_VICTIM_SHIFT), DSPMMU_LOCK);
+}
+
+static __inline__ void __read_tlb(unsigned short lbase, unsigned short victim,
+ unsigned short *cam_h, unsigned short *cam_l,
+ unsigned short *ram_h, unsigned short *ram_l)
+{
+ /* set victim */
+ set_tlb_lock(lbase, victim);
+
+ /* read a TLB entry */
+ omap_writew(DSPMMU_LD_TLB_RD, DSPMMU_LD_TLB);
+
+ if (cam_h != NULL)
+ *cam_h = omap_readw(DSPMMU_READ_CAM_H);
+ if (cam_l != NULL)
+ *cam_l = omap_readw(DSPMMU_READ_CAM_L);
+ if (ram_h != NULL)
+ *ram_h = omap_readw(DSPMMU_READ_RAM_H);
+ if (ram_l != NULL)
+ *ram_l = omap_readw(DSPMMU_READ_RAM_L);
+}
+
+static __inline__ void __load_tlb(unsigned short cam_h, unsigned short cam_l,
+ unsigned short ram_h, unsigned short ram_l)
+{
+ omap_writew(cam_h, DSPMMU_CAM_H);
+ omap_writew(cam_l, DSPMMU_CAM_L);
+ omap_writew(ram_h, DSPMMU_RAM_H);
+ omap_writew(ram_l, DSPMMU_RAM_L);
+
+ /* flush the entry */
+ dsp_mmu_flush();
+
+ /* load a TLB entry */
+ omap_writew(DSPMMU_LD_TLB_LD, DSPMMU_LD_TLB);
+}
+
+static int dsp_mmu_load_tlb(unsigned long vadr, unsigned long padr,
+ unsigned short slst, unsigned short prsvd,
+ unsigned short ap)
+{
+ int lbase, victim;
+ unsigned short cam_l_va_mask;
+
+ clk_enable(dsp_ck_handle);
+
+ get_tlb_lock(&lbase, NULL);
+ for (victim = 0; victim < lbase; victim++) {
+ unsigned short cam_l;
+
+ /* read a TLB entry */
+ __read_tlb(lbase, victim, NULL, &cam_l, NULL, NULL);
+ if (!(cam_l & DSPMMU_CAM_L_V))
+ goto found_victim;
+ }
+ set_tlb_lock(lbase, victim);
+
+found_victim:
+ /* The last (31st) entry cannot be locked? */
+ if (victim == 31) {
+ printk(KERN_ERR "omapdsp: TLB is full.\n");
+ return -EBUSY;
+ }
+
+ cam_l_va_mask = get_cam_l_va_mask(slst);
+ if (vadr &
+ ~(DSPMMU_CAM_H_VA_TAG_H_MASK << 22 |
+ (unsigned long)cam_l_va_mask << 6)) {
+ printk(KERN_ERR
+ "omapdsp: mapping vadr (0x%06lx) is not "
+ "aligned boundary\n", vadr);
+ return -EINVAL;
+ }
+
+ __load_tlb(vadr >> 22, (vadr >> 6 & cam_l_va_mask) | prsvd | slst,
+ padr >> 16, (padr & DSPMMU_RAM_L_RAM_LSB_MASK) | ap);
+
+ /* update lock base */
+ if (victim == lbase)
+ lbase++;
+ set_tlb_lock(lbase, lbase);
+
+ clk_disable(dsp_ck_handle);
+ return 0;
+}
+
+static int dsp_mmu_clear_tlb(unsigned long vadr)
+{
+ int lbase;
+ int i;
+ int max_valid = 0;
+
+ clk_enable(dsp_ck_handle);
+
+ get_tlb_lock(&lbase, NULL);
+ for (i = 0; i < lbase; i++) {
+ unsigned short cam_h, cam_l;
+ unsigned short cam_l_va_mask, cam_vld, slst;
+ unsigned long cam_va;
+
+ /* read a TLB entry */
+ __read_tlb(lbase, i, &cam_h, &cam_l, NULL, NULL);
+
+ cam_vld = cam_l & DSPMMU_CAM_L_V;
+ if (!cam_vld)
+ continue;
+
+ slst = cam_l & DSPMMU_CAM_L_SLST_MASK;
+ cam_l_va_mask = get_cam_l_va_mask(slst);
+ cam_va = (unsigned long)(cam_h & DSPMMU_CAM_H_VA_TAG_H_MASK) << 22 |
+ (unsigned long)(cam_l & cam_l_va_mask) << 6;
+
+ if (cam_va == vadr)
+ /* flush the entry */
+ dsp_mmu_flush();
+ else
+ max_valid = i;
+ }
+
+ /* set new lock base */
+ set_tlb_lock(max_valid+1, max_valid+1);
+
+ clk_disable(dsp_ck_handle);
+ return 0;
+}
+
+static void dsp_mmu_gflush(void)
+{
+ clk_enable(dsp_ck_handle);
+
+ __dsp_mmu_gflush();
+ set_tlb_lock(1, 1);
+
+ clk_disable(dsp_ck_handle);
+}
+
+/*
+ * dsp_exmap()
+ *
+ * OMAP_DSP_MEM_IOCTL_EXMAP ioctl calls this function with padr=0.
+ * In this case, the buffer for DSP is allocated in this routine,
+ * then it is mapped.
+ * On the other hand, for example - frame buffer sharing, calls
+ * this function with padr set. It means some known address space
+ * pointed with padr is going to be shared with DSP.
+ */
+static int dsp_exmap(unsigned long dspadr, unsigned long padr,
+ unsigned long size, enum exmap_type type)
+{
+ unsigned short slst;
+ void *buf;
+ unsigned int order = 0;
+ unsigned long unit;
+ unsigned int cntnu = 0;
+ unsigned long _dspadr = dspadr;
+ unsigned long _padr = padr;
+ void *_vadr = dspbyte_to_virt(dspadr);
+ unsigned long _size = size;
+ struct exmap_tbl *exmap_ent;
+ int status;
+ int i;
+
+#define MINIMUM_PAGESZ SZ_4KB
+ /*
+ * alignment check
+ */
+ if (!is_aligned(size, MINIMUM_PAGESZ)) {
+ printk(KERN_ERR
+ "omapdsp: size(0x%lx) is not multiple of 4KB.\n", size);
+ return -EINVAL;
+ }
+ if (!is_aligned(dspadr, MINIMUM_PAGESZ)) {
+ printk(KERN_ERR
+ "omapdsp: DSP address(0x%lx) is not aligned.\n", dspadr);
+ return -EINVAL;
+ }
+ if (!is_aligned(padr, MINIMUM_PAGESZ)) {
+ printk(KERN_ERR
+ "omapdsp: physical address(0x%lx) is not aligned.\n",
+ padr);
+ return -EINVAL;
+ }
+
+ /* address validity check */
+ if ((dspadr < dspmem_size) ||
+ (dspadr >= DSPSPACE_SIZE) ||
+ ((dspadr + size > DSP_INIT_PAGE) &&
+ (dspadr < DSP_INIT_PAGE + PAGE_SIZE))) {
+ printk(KERN_ERR
+ "omapdsp: illegal address/size for dsp_exmap().\n");
+ return -EINVAL;
+ }
+
+ down_write(&exmap_sem);
+
+ /* overlap check */
+ for (i = 0; i < DSPMMU_TLB_LINES; i++) {
+ unsigned long mapsize;
+ struct exmap_tbl *tmp_ent = &exmap_tbl[i];
+
+ if (!tmp_ent->valid)
+ continue;
+ mapsize = 1 << (tmp_ent->order + PAGE_SHIFT);
+ if ((_vadr + size > tmp_ent->vadr) &&
+ (_vadr < tmp_ent->vadr + mapsize)) {
+ printk(KERN_ERR "omapdsp: exmap page overlap!\n");
+ up_write(&exmap_sem);
+ return -EINVAL;
+ }
+ }
+
+start:
+ buf = NULL;
+ /* Are there any free TLB lines? */
+ for (i = 0; i < DSPMMU_TLB_LINES; i++) {
+ if (!exmap_tbl[i].valid)
+ goto found_free;
+ }
+ printk(KERN_ERR "omapdsp: DSP TLB is full.\n");
+ status = -EBUSY;
+ goto fail;
+
+found_free:
+ exmap_ent = &exmap_tbl[i];
+
+ if ((_size >= SZ_1MB) &&
+ (is_aligned(_padr, SZ_1MB) || (padr == 0)) &&
+ is_aligned(_dspadr, SZ_1MB)) {
+ unit = SZ_1MB;
+ slst = DSPMMU_CAM_L_SLST_1MB;
+ } else if ((_size >= SZ_64KB) &&
+ (is_aligned(_padr, SZ_64KB) || (padr == 0)) &&
+ is_aligned(_dspadr, SZ_64KB)) {
+ unit = SZ_64KB;
+ slst = DSPMMU_CAM_L_SLST_64KB;
+ } else {
+ unit = SZ_4KB;
+ slst = DSPMMU_CAM_L_SLST_4KB;
+ }
+
+ order = get_order(unit);
+
+ /* buffer allocation */
+ if (type == EXMAP_TYPE_MEM) {
+ struct page *page, *ps, *pe;
+
+ if ((order == ORDER_1MB) && likely(kmem_pool_1M))
+ buf = mempool_alloc_from_pool(kmem_pool_1M, GFP_KERNEL);
+ else if ((order == ORDER_64KB) && likely(kmem_pool_64K))
+ buf = mempool_alloc_from_pool(kmem_pool_64K,GFP_KERNEL);
+ else {
+ buf = (void *)__get_dma_pages(GFP_KERNEL, order);
+ if (buf == NULL) {
+ status = -ENOMEM;
+ goto fail;
+ }
+ }
+
+ /* mark the pages as reserved; this is needed for mmap */
+ ps = virt_to_page(buf);
+ pe = virt_to_page(buf + unit);
+
+ for (page = ps; page < pe; page++)
+ SetPageReserved(page);
+
+ _padr = __pa(buf);
+ }
+
+ /*
+ * mapping for ARM MMU:
+ * we should not access to the allocated memory through 'buf'
+ * since this area should not be cashed.
+ */
+ status = exmap_set_armmmu((unsigned long)_vadr, _padr, unit);
+ if (status < 0)
+ goto fail;
+
+ /* loading DSP TLB entry */
+ status = dsp_mmu_load_tlb(_dspadr, _padr, slst, 0, DSPMMU_RAM_L_AP_FA);
+ if (status < 0) {
+ exmap_clear_armmmu((unsigned long)_vadr, unit);
+ goto fail;
+ }
+
+ exmap_ent->buf = buf;
+ exmap_ent->vadr = _vadr;
+ exmap_ent->order = order;
+ exmap_ent->valid = 1;
+ exmap_ent->cntnu = cntnu;
+ exmap_ent->type = type;
+ exmap_ent->usecount = 0;
+
+ if ((_size -= unit) == 0) { /* normal completion */
+ up_write(&exmap_sem);
+ return size;
+ }
+
+ _dspadr += unit;
+ _vadr += unit;
+ _padr = padr ? _padr + unit : 0;
+ cntnu = 1;
+ goto start;
+
+fail:
+ up_write(&exmap_sem);
+ if (buf)
+ dsp_mem_free_pages((unsigned long)buf, order);
+ dsp_exunmap(dspadr);
+ return status;
+}
+
+static unsigned long unmap_free_arm(struct exmap_tbl *ent)
+{
+ unsigned long size;
+
+ /* clearing ARM MMU */
+ size = 1 << (ent->order + PAGE_SHIFT);
+ exmap_clear_armmmu((unsigned long)ent->vadr, size);
+
+ /* freeing allocated memory */
+ if (ent->type == EXMAP_TYPE_MEM) {
+ dsp_mem_free_pages((unsigned long)ent->buf, ent->order);
+ printk(KERN_DEBUG
+ "omapdsp: freeing 0x%lx bytes @ adr 0x%8p\n",
+ size, ent->buf);
+ }
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+ else if (ent->type == EXMAP_TYPE_FB) {
+ int status;
+ if (omapfb_nb) {
+ status = omapfb_unregister_client(omapfb_nb);
+ if (!status)
+ printk("omapfb_unregister_client(): "
+ "success\n");
+ else
+ printk("omapfb_runegister_client(): "
+ "failure(%d)\n", status);
+ kfree(omapfb_nb);
+ omapfb_nb = NULL;
+ omapfb_ready = 0;
+ }
+ }
+#endif
+
+ return size;
+}
+
+static int dsp_exunmap(unsigned long dspadr)
+{
+ void *vadr;
+ unsigned long size;
+ int total = 0;
+ struct exmap_tbl *ent;
+ int idx;
+
+ vadr = dspbyte_to_virt(dspadr);
+ down_write(&exmap_sem);
+ for (idx = 0; idx < DSPMMU_TLB_LINES; idx++) {
+ ent = &exmap_tbl[idx];
+ if (!ent->valid)
+ continue;
+ if (ent->vadr == vadr)
+ goto found_map;
+ }
+ up_write(&exmap_sem);
+ printk(KERN_WARNING
+ "omapdsp: address %06lx not found in exmap_tbl.\n", dspadr);
+ return -EINVAL;
+
+found_map:
+ if (ent->usecount > 0) {
+ printk(KERN_ERR
+ "omapdsp: exmap reference count is not 0.\n"
+ " idx=%d, vadr=%p, order=%d, usecount=%d\n",
+ idx, ent->vadr, ent->order, ent->usecount);
+ up_write(&exmap_sem);
+ return -EINVAL;
+ }
+ /* clearing DSP TLB entry */
+ dsp_mmu_clear_tlb(dspadr);
+
+ /* clear ARM MMU and free buffer */
+ size = unmap_free_arm(ent);
+ ent->valid = 0;
+ total += size;
+
+ /* we don't free PTEs */
+
+ /* flush TLB */
+ flush_tlb_kernel_range((unsigned long)vadr, (unsigned long)vadr + size);
+
+ /* check if next mapping is in same group */
+ if (++idx == DSPMMU_TLB_LINES)
+ goto up_out; /* normal completion */
+ ent = &exmap_tbl[idx];
+ if (!ent->valid || !ent->cntnu)
+ goto up_out; /* normal completion */
+
+ dspadr += size;
+ vadr += size;
+ if (ent->vadr == vadr)
+ goto found_map; /* continue */
+
+ printk(KERN_ERR
+ "omapdsp: illegal exmap_tbl grouping!\n"
+ "expected vadr = %p, exmap_tbl[%d].vadr = %p\n",
+ vadr, idx, ent->vadr);
+ up_write(&exmap_sem);
+ return -EINVAL;
+
+up_out:
+ up_write(&exmap_sem);
+ return total;
+}
+
+static void exmap_flush(void)
+{
+ struct exmap_tbl *ent;
+ int i;
+
+ down_write(&exmap_sem);
+
+ /* clearing DSP TLB entry */
+ dsp_mmu_gflush();
+
+ /* exmap_tbl[0] should be preserved */
+ for (i = 1; i < DSPMMU_TLB_LINES; i++) {
+ ent = &exmap_tbl[i];
+ if (ent->valid) {
+ unmap_free_arm(ent);
+ ent->valid = 0;
+ }
+ }
+
+ /* flush TLB */
+ flush_tlb_kernel_range(dspmem_base + dspmem_size,
+ dspmem_base + DSPSPACE_SIZE);
+ up_write(&exmap_sem);
+}
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+#ifndef CONFIG_FB
+#error You configured OMAP_DSP_FBEXPORT, but FB was not configured!
+#endif /* CONFIG_FB */
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+static int omapfb_notifier_cb(struct omapfb_notifier_block *omapfb_nb,
+ unsigned long event, struct omapfb_device *fbdev)
+{
+ /* XXX */
+ printk("omapfb_notifier_cb(): event = %s\n",
+ (event == OMAPFB_EVENT_READY) ? "READY" :
+ (event == OMAPFB_EVENT_DISABLED) ? "DISABLED" : "Unknown");
+ if (event == OMAPFB_EVENT_READY)
+ omapfb_ready = 1;
+ else if (event == OMAPFB_EVENT_DISABLED)
+ omapfb_ready = 0;
+ return 0;
+}
+#endif
+
+static int dsp_fbexport(unsigned long *dspadr)
+{
+ unsigned long dspadr_actual;
+ unsigned long padr_sys, padr, fbsz_sys, fbsz;
+ int cnt;
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+ int status;
+#endif
+
+ printk(KERN_DEBUG "omapdsp: frame buffer export\n");
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+ if (omapfb_nb) {
+ printk(KERN_WARNING
+ "omapdsp: frame buffer has been exported already!\n");
+ return -EBUSY;
+ }
+#endif
+
+ if (num_registered_fb == 0) {
+ printk(KERN_INFO "omapdsp: frame buffer not registered.\n");
+ return -EINVAL;
+ }
+ if (num_registered_fb != 1) {
+ printk(KERN_INFO
+ "omapdsp: %d frame buffers found. we use first one.\n",
+ num_registered_fb);
+ }
+ padr_sys = registered_fb[0]->fix.smem_start;
+ fbsz_sys = registered_fb[0]->fix.smem_len;
+ if (fbsz_sys == 0) {
+ printk(KERN_ERR
+ "omapdsp: framebuffer doesn't seem to be configured "
+ "correctly! (size=0)\n");
+ return -EINVAL;
+ }
+
+ /*
+ * align padr and fbsz to 4kB boundary
+ * (should be noted to the user afterwards!)
+ */
+ padr = padr_sys & ~(SZ_4KB-1);
+ fbsz = (fbsz_sys + padr_sys - padr + SZ_4KB-1) & ~(SZ_4KB-1);
+
+ /* line up dspadr offset with padr */
+ dspadr_actual =
+ (fbsz > SZ_1MB) ? lineup_offset(*dspadr, padr, SZ_1MB-1) :
+ (fbsz > SZ_64KB) ? lineup_offset(*dspadr, padr, SZ_64KB-1) :
+ /* (fbsz > SZ_4KB) ? */ *dspadr;
+ if (dspadr_actual != *dspadr)
+ printk(KERN_DEBUG
+ "omapdsp: actual dspadr for FBEXPORT = %08lx\n",
+ dspadr_actual);
+ *dspadr = dspadr_actual;
+
+ cnt = dsp_exmap(dspadr_actual, padr, fbsz, EXMAP_TYPE_FB);
+ if (cnt < 0) {
+ printk(KERN_ERR "omapdsp: exmap failure.\n");
+ return cnt;
+ }
+
+ if ((padr != padr_sys) || (fbsz != fbsz_sys)) {
+ printk(KERN_WARNING
+" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
+" !! screen base address or size is not aligned in 4kB: !!\n"
+" !! actual screen adr = %08lx, size = %08lx !!\n"
+" !! exporting adr = %08lx, size = %08lx !!\n"
+" !! Make sure that the framebuffer is allocated with 4kB-order! !!\n"
+" !! Otherwise DSP can corrupt the kernel memory. !!\n"
+" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",
+ padr_sys, fbsz_sys, padr, fbsz);
+ }
+
+ /* increase the DMA priority */
+ set_emiff_dma_prio(15);
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+ omapfb_nb = kmalloc(sizeof(struct omapfb_notifier_block), GFP_KERNEL);
+ if (omapfb_nb == NULL) {
+ printk(KERN_ERR
+ "omapdsp: failed to allocate memory for omapfb_nb!\n");
+ dsp_exunmap(dspadr_actual);
+ return -ENOMEM;
+ }
+ status = omapfb_register_client(omapfb_nb, omapfb_notifier_cb, NULL);
+ if (!status)
+ printk("omapfb_register_client(): success\n");
+ else
+ printk("omapfb_register_client(): failure(%d)\n", status);
+#endif
+
+ return cnt;
+}
+
+#else /* CONFIG_OMAP_DSP_FBEXPORT */
+
+static int dsp_fbexport(unsigned long *dspadr)
+{
+ printk(KERN_ERR "omapdsp: FBEXPORT function is not enabled.\n");
+ return -EINVAL;
+}
+
+#endif /* CONFIG_OMAP_DSP_FBEXPORT */
+
+static int dsp_mmu_itack(void)
+{
+ unsigned long dspadr;
+
+ printk(KERN_INFO "omapdsp: sending DSP MMU interrupt ack.\n");
+ if (!dsp_err_mmu_isset()) {
+ printk(KERN_ERR "omapdsp: DSP MMU error has not been set.\n");
+ return -EINVAL;
+ }
+ dspadr = dsp_fault_adr & ~(SZ_4K-1);
+ dsp_exmap(dspadr, 0, SZ_4K, EXMAP_TYPE_MEM); /* FIXME: reserve TLB entry for this */
+ printk(KERN_INFO "omapdsp: falling into recovery runlevel...\n");
+ dsp_runlevel(OMAP_DSP_MBCMD_RUNLEVEL_RECOVERY);
+ __dsp_mmu_itack();
+ udelay(100);
+ dsp_exunmap(dspadr);
+ dsp_err_mmu_clear();
+ return 0;
+}
+
+static void dsp_mmu_init(void)
+{
+ unsigned long phys;
+ void *virt;
+
+ clk_enable(dsp_ck_handle);
+ down_write(&exmap_sem);
+
+ dsp_mmu_disable(); /* clear all */
+ udelay(100);
+ dsp_mmu_enable();
+
+ /* mapping for ARM MMU */
+ phys = __pa(dspvect_page);
+ virt = dspbyte_to_virt(DSP_INIT_PAGE); /* 0xe0fff000 */
+ exmap_set_armmmu((unsigned long)virt, phys, PAGE_SIZE);
+ exmap_tbl[0].buf = dspvect_page;
+ exmap_tbl[0].vadr = virt;
+ exmap_tbl[0].usecount = 0;
+ exmap_tbl[0].order = 0;
+ exmap_tbl[0].valid = 1;
+ exmap_tbl[0].cntnu = 0;
+
+ /* DSP TLB initialization */
+ set_tlb_lock(0, 0);
+ /* preserved, full access */
+ dsp_mmu_load_tlb(DSP_INIT_PAGE, phys, DSPMMU_CAM_L_SLST_4KB,
+ DSPMMU_CAM_L_P, DSPMMU_RAM_L_AP_FA);
+ up_write(&exmap_sem);
+ clk_disable(dsp_ck_handle);
+}
+
+static void dsp_mmu_shutdown(void)
+{
+ exmap_flush();
+ dsp_mmu_disable(); /* clear all */
+}
+
+/*
+ * 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_is_ready())
+ ret = dsp_mbsend(MBCMD(PM), OMAP_DSP_MBCMD_PM_ENABLE,
+ DSPREG_ICR_DMA_IDLE_DOMAIN);
+
+ return ret;
+}
+
+static void intmem_disable(void) {
+ if (dsp_is_ready())
+ dsp_mbsend(MBCMD(PM), OMAP_DSP_MBCMD_PM_DISABLE,
+ DSPREG_ICR_DMA_IDLE_DOMAIN);
+}
+
+/*
+ * dsp_mem_enable() / disable()
+ */
+int intmem_usecount;
+
+int dsp_mem_enable(void *adr)
+{
+ int ret = 0;
+
+ if (is_dsp_internal_mem(adr)) {
+ if (intmem_usecount++ == 0)
+ ret = omap_dsp_request_mem();
+ } else
+ down_read(&exmap_sem);
+
+ return ret;
+}
+
+void dsp_mem_disable(void *adr)
+{
+ if (is_dsp_internal_mem(adr)) {
+ if (--intmem_usecount == 0)
+ omap_dsp_release_mem();
+ } else
+ up_read(&exmap_sem);
+}
+
+/* for safety */
+void dsp_mem_usecount_clear(void)
+{
+ if (intmem_usecount != 0) {
+ printk(KERN_WARNING
+ "omapdsp: unbalanced memory request/release detected.\n"
+ " intmem_usecount is not zero at where "
+ "it should be! ... fixed to be zero.\n");
+ intmem_usecount = 0;
+ omap_dsp_release_mem();
+ }
+}
+
+/*
+ * dsp_mem file operations
+ */
+static loff_t dsp_mem_lseek(struct file *file, loff_t offset, int orig)
+{
+ loff_t ret;
+
+ mutex_lock(&file->f_dentry->d_inode->i_mutex);
+ switch (orig) {
+ case 0:
+ file->f_pos = offset;
+ ret = file->f_pos;
+ break;
+ case 1:
+ file->f_pos += offset;
+ ret = file->f_pos;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+ return ret;
+}
+
+static ssize_t intmem_read(struct file *file, char *buf, size_t count,
+ loff_t *ppos)
+{
+ unsigned long p = *ppos;
+ void *vadr = dspbyte_to_virt(p);
+ ssize_t size = dspmem_size;
+ ssize_t read;
+
+ if (p >= size)
+ return 0;
+ clk_enable(api_ck_handle);
+ 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(api_ck_handle);
+ return read;
+}
+
+static ssize_t exmem_read(struct file *file, char *buf, size_t count,
+ loff_t *ppos)
+{
+ unsigned long p = *ppos;
+ void *vadr = dspbyte_to_virt(p);
+
+ if (!exmap_valid(vadr, count)) {
+ printk(KERN_ERR
+ "omapdsp: DSP address %08lx / size %08x "
+ "is not valid!\n", p, count);
+ return -EFAULT;
+ }
+ if (count > DSPSPACE_SIZE - p)
+ count = DSPSPACE_SIZE - p;
+ if (copy_to_user(buf, vadr, count))
+ return -EFAULT;
+ *ppos += count;
+
+ return count;
+}
+
+static ssize_t dsp_mem_read(struct file *file, char *buf, size_t count,
+ loff_t *ppos)
+{
+ int ret;
+ void *vadr = dspbyte_to_virt(*(unsigned long *)ppos);
+
+ if (dsp_mem_enable(vadr) < 0)
+ return -EBUSY;
+ if (is_dspbyte_internal_mem(*ppos))
+ ret = intmem_read(file, buf, count, ppos);
+ else
+ ret = exmem_read(file, buf, count, ppos);
+ dsp_mem_disable(vadr);
+
+ return ret;
+}
+
+static ssize_t intmem_write(struct file *file, const char *buf, size_t count,
+ loff_t *ppos)
+{
+ unsigned long p = *ppos;
+ void *vadr = dspbyte_to_virt(p);
+ ssize_t size = dspmem_size;
+ ssize_t written;
+
+ if (p >= size)
+ return 0;
+ clk_enable(api_ck_handle);
+ 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(api_ck_handle);
+ return written;
+}
+
+static ssize_t exmem_write(struct file *file, const char *buf, size_t count,
+ loff_t *ppos)
+{
+ unsigned long p = *ppos;
+ void *vadr = dspbyte_to_virt(p);
+
+ if (!exmap_valid(vadr, count)) {
+ printk(KERN_ERR
+ "omapdsp: DSP address %08lx / size %08x "
+ "is not valid!\n", p, count);
+ return -EFAULT;
+ }
+ if (count > DSPSPACE_SIZE - p)
+ count = DSPSPACE_SIZE - p;
+ if (copy_from_user(vadr, buf, count))
+ return -EFAULT;
+ *ppos += count;
+
+ return count;
+}
+
+static ssize_t dsp_mem_write(struct file *file, const char *buf, size_t count,
+ loff_t *ppos)
+{
+ int ret;
+ void *vadr = dspbyte_to_virt(*(unsigned long *)ppos);
+
+ if (dsp_mem_enable(vadr) < 0)
+ return -EBUSY;
+ if (is_dspbyte_internal_mem(*ppos))
+ ret = intmem_write(file, buf, count, ppos);
+ else
+ ret = exmem_write(file, buf, count, ppos);
+ dsp_mem_disable(vadr);
+
+ return ret;
+}
+
+static int dsp_mem_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ case OMAP_DSP_MEM_IOCTL_MMUINIT:
+ dsp_mmu_init();
+ return 0;
+
+ case OMAP_DSP_MEM_IOCTL_EXMAP:
+ {
+ struct omap_dsp_mapinfo mapinfo;
+ if (copy_from_user(&mapinfo, (void *)arg,
+ sizeof(mapinfo)))
+ return -EFAULT;
+ return dsp_exmap(mapinfo.dspadr, 0, mapinfo.size,
+ EXMAP_TYPE_MEM);
+ }
+
+ case OMAP_DSP_MEM_IOCTL_EXUNMAP:
+ return dsp_exunmap((unsigned long)arg);
+
+ case OMAP_DSP_MEM_IOCTL_EXMAP_FLUSH:
+ exmap_flush();
+ return 0;
+
+ case OMAP_DSP_MEM_IOCTL_FBEXPORT:
+ {
+ unsigned long dspadr;
+ int ret;
+ if (copy_from_user(&dspadr, (void *)arg, sizeof(long)))
+ return -EFAULT;
+ ret = dsp_fbexport(&dspadr);
+ if (copy_to_user((void *)arg, &dspadr, sizeof(long)))
+ return -EFAULT;
+ return ret;
+ }
+
+ case OMAP_DSP_MEM_IOCTL_MMUITACK:
+ return dsp_mmu_itack();
+
+ case OMAP_DSP_MEM_IOCTL_KMEM_RESERVE:
+ {
+ unsigned long size;
+ if (copy_from_user(&size, (void *)arg, sizeof(long)))
+ return -EFAULT;
+ return dsp_kmem_reserve(size);
+ }
+
+ case OMAP_DSP_MEM_IOCTL_KMEM_RELEASE:
+ dsp_kmem_release();
+ return 0;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+static int dsp_mem_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ /*
+ * FIXME
+ */
+ return -ENOSYS;
+}
+
+static int dsp_mem_open(struct inode *inode, struct file *file)
+{
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+ return 0;
+}
+
+static int dsp_mem_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+/*
+ * fb update functions:
+ * fbupd_response() is executed by the workqueue.
+ * fbupd_cb() is called when fb update is done, in interrupt context.
+ * mbx1_fbupd() is called when KFUNC:FBCTL:UPD is received from DSP.
+ */
+static void fbupd_response(void *arg)
+{
+ int status;
+
+ status = dsp_mbsend(MBCMD(KFUNC), OMAP_DSP_MBCMD_KFUNC_FBCTL,
+ OMAP_DSP_MBCMD_FBCTL_UPD);
+ if (status < 0) {
+ /* FIXME: DSP is busy !! */
+ printk(KERN_ERR
+ "omapdsp: DSP is busy when trying to send FBCTL:UPD "
+ "response!\n");
+ }
+}
+
+static DECLARE_WORK(fbupd_response_work, (void (*)(void *))fbupd_response,
+ NULL);
+
+static void fbupd_cb(void *arg)
+{
+ schedule_work(&fbupd_response_work);
+}
+
+void mbx1_fbctl_upd(void)
+{
+ struct omapfb_update_window win;
+ volatile unsigned short *buf = ipbuf_sys_da->d;
+
+ /* FIXME: try count sometimes exceeds 1000. */
+ if (sync_with_dsp(&ipbuf_sys_da->s, OMAP_DSP_TID_ANON, 5000) < 0) {
+ printk(KERN_ERR "mbx: FBCTL:UPD - IPBUF sync failed!\n");
+ return;
+ }
+ win.x = buf[0];
+ win.y = buf[1];
+ win.width = buf[2];
+ win.height = buf[3];
+ win.format = buf[4];
+ release_ipbuf_pvt(ipbuf_sys_da);
+
+ if (!omapfb_ready) {
+ printk(KERN_WARNING
+ "omapdsp: fbupd() called while HWA742 is not ready!\n");
+ return;
+ }
+ //printk("calling omapfb_update_window_async()\n");
+ omapfb_update_window_async(&win, fbupd_cb, NULL);
+}
+
+#else /* CONFIG_FB_OMAP_LCDC_EXTERNAL */
+
+void mbx1_fbctl_upd(void)
+{
+}
+#endif /* CONFIG_FB_OMAP_LCDC_EXTERNAL */
+
+/*
+ * sysfs files
+ */
+static ssize_t mmu_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int len;
+ int lbase, victim;
+ int i;
+
+ clk_enable(dsp_ck_handle);
+ down_read(&exmap_sem);
+
+ get_tlb_lock(&lbase, &victim);
+
+ len = sprintf(buf, "p: preserved, v: valid\n"
+ "ety cam_va ram_pa sz ap\n");
+ /* 00: p v 0x300000 0x10171800 64KB FA */
+ for (i = 0; i < 32; i++) {
+ unsigned short cam_h, cam_l, ram_h, ram_l;
+ unsigned short cam_l_va_mask, prsvd, cam_vld, slst;
+ unsigned long cam_va;
+ unsigned short ram_l_ap;
+ unsigned long ram_pa;
+ char *pgsz_str, *ap_str;
+
+ /* read a TLB entry */
+ __read_tlb(lbase, i, &cam_h, &cam_l, &ram_h, &ram_l);
+
+ slst = cam_l & DSPMMU_CAM_L_SLST_MASK;
+ cam_l_va_mask = get_cam_l_va_mask(slst);
+ pgsz_str = (slst == DSPMMU_CAM_L_SLST_1MB) ? " 1MB":
+ (slst == DSPMMU_CAM_L_SLST_64KB)? "64KB":
+ (slst == DSPMMU_CAM_L_SLST_4KB) ? " 4KB":
+ " 1KB";
+ prsvd = cam_l & DSPMMU_CAM_L_P;
+ cam_vld = cam_l & DSPMMU_CAM_L_V;
+ ram_l_ap = ram_l & DSPMMU_RAM_L_AP_MASK;
+ ap_str = (ram_l_ap == DSPMMU_RAM_L_AP_RO) ? "RO":
+ (ram_l_ap == DSPMMU_RAM_L_AP_FA) ? "FA":
+ "NA";
+ cam_va = (unsigned long)(cam_h & DSPMMU_CAM_H_VA_TAG_H_MASK) << 22 |
+ (unsigned long)(cam_l & cam_l_va_mask) << 6;
+ ram_pa = (unsigned long)ram_h << 16 |
+ (ram_l & DSPMMU_RAM_L_RAM_LSB_MASK);
+
+ if (i == lbase)
+ len += sprintf(buf + len, "lock base = %d\n", lbase);
+ if (i == victim)
+ len += sprintf(buf + len, "victim = %d\n", victim);
+ /* 00: p v 0x300000 0x10171800 64KB FA */
+ len += sprintf(buf + len,
+ "%02d: %c %c 0x%06lx 0x%08lx %s %s\n",
+ i,
+ prsvd ? 'p' : ' ',
+ cam_vld ? 'v' : ' ',
+ cam_va, ram_pa, pgsz_str, ap_str);
+ }
+
+ /* restore victim entry */
+ set_tlb_lock(lbase, victim);
+
+ up_read(&exmap_sem);
+ clk_disable(dsp_ck_handle);
+ return len;
+}
+
+static struct device_attribute dev_attr_mmu = __ATTR_RO(mmu);
+
+static ssize_t exmap_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int len;
+ int i;
+
+ down_read(&exmap_sem);
+ len = sprintf(buf, "v: valid, c: cntnu\n"
+ "ety vadr buf od uc\n");
+ /* 00: v c 0xe0300000 0xc0171800 0 */
+ for (i = 0; i < DSPMMU_TLB_LINES; i++) {
+ struct exmap_tbl *ent = &exmap_tbl[i];
+ /* 00: v c 0xe0300000 0xc0171800 0 */
+ len += sprintf(buf + len, "%02d: %c %c 0x%8p 0x%8p %2d %2d\n",
+ i,
+ ent->valid ? 'v' : ' ',
+ ent->cntnu ? 'c' : ' ',
+ ent->vadr, ent->buf, ent->order, ent->usecount);
+ }
+
+ up_read(&exmap_sem);
+ return len;
+}
+
+static struct device_attribute dev_attr_exmap = __ATTR_RO(exmap);
+
+static ssize_t kmem_pool_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr_1M, nr_64K, total;
+
+ nr_1M = kmem_pool_1M->min_nr;
+ nr_64K = kmem_pool_64K->min_nr;
+ total = nr_1M * SZ_1MB + nr_64K * SZ_64KB;
+
+ return sprintf(buf, "0x%x %d %d\n", total, nr_1M, nr_64K);
+}
+
+static struct device_attribute dev_attr_kmem_pool = __ATTR_RO(kmem_pool);
+
+/*
+ * DSP MMU interrupt handler
+ */
+
+/*
+ * MMU fault mask:
+ * We ignore prefetch err.
+ */
+#define MMUFAULT_MASK \
+ (DSPMMU_FAULT_ST_PERM |\
+ DSPMMU_FAULT_ST_TLB_MISS |\
+ DSPMMU_FAULT_ST_TRANS)
+irqreturn_t dsp_mmu_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned short status;
+ unsigned short adh, adl;
+ unsigned short dp;
+
+ status = omap_readw(DSPMMU_FAULT_ST);
+ adh = omap_readw(DSPMMU_FAULT_AD_H);
+ adl = omap_readw(DSPMMU_FAULT_AD_L);
+ dp = adh & DSPMMU_FAULT_AD_H_DP;
+ dsp_fault_adr = MKLONG(adh & DSPMMU_FAULT_AD_H_ADR_MASK, adl);
+ /* if the fault is masked, nothing to do */
+ if ((status & MMUFAULT_MASK) == 0) {
+ printk(KERN_DEBUG "DSP MMU interrupt, but ignoring.\n");
+ /*
+ * note: in OMAP1710,
+ * when CACHE + DMA domain gets out of idle in DSP,
+ * MMU interrupt occurs but DSPMMU_FAULT_ST is not set.
+ * in this case, we just ignore the interrupt.
+ */
+ if (status) {
+ printk(KERN_DEBUG "%s%s%s%s\n",
+ (status & DSPMMU_FAULT_ST_PREF)?
+ " (prefetch err)" : "",
+ (status & DSPMMU_FAULT_ST_PERM)?
+ " (permission fault)" : "",
+ (status & DSPMMU_FAULT_ST_TLB_MISS)?
+ " (TLB miss)" : "",
+ (status & DSPMMU_FAULT_ST_TRANS) ?
+ " (translation fault)": "");
+ printk(KERN_DEBUG
+ "fault address = %s: 0x%06lx\n",
+ dp ? "DATA" : "PROGRAM",
+ dsp_fault_adr);
+ }
+ return IRQ_HANDLED;
+ }
+
+ printk(KERN_INFO "DSP MMU interrupt!\n");
+ printk(KERN_INFO "%s%s%s%s\n",
+ (status & DSPMMU_FAULT_ST_PREF)?
+ (MMUFAULT_MASK & DSPMMU_FAULT_ST_PREF)?
+ " prefetch err":
+ " (prefetch err)":
+ "",
+ (status & DSPMMU_FAULT_ST_PERM)?
+ (MMUFAULT_MASK & DSPMMU_FAULT_ST_PERM)?
+ " permission fault":
+ " (permission fault)":
+ "",
+ (status & DSPMMU_FAULT_ST_TLB_MISS)?
+ (MMUFAULT_MASK & DSPMMU_FAULT_ST_TLB_MISS)?
+ " TLB miss":
+ " (TLB miss)":
+ "",
+ (status & DSPMMU_FAULT_ST_TRANS)?
+ (MMUFAULT_MASK & DSPMMU_FAULT_ST_TRANS)?
+ " translation fault":
+ " (translation fault)":
+ "");
+ printk(KERN_INFO "fault address = %s: 0x%06lx\n",
+ dp ? "DATA" : "PROGRAM",
+ dsp_fault_adr);
+
+ if (dsp_is_ready()) {
+ /*
+ * If we call dsp_exmap() here,
+ * "kernel BUG at slab.c" occurs.
+ */
+ /* FIXME */
+ dsp_err_mmu_set(dsp_fault_adr);
+ } else {
+ disable_irq(INT_DSP_MMU);
+ __dsp_mmu_itack();
+ printk(KERN_INFO "Resetting DSP...\n");
+ dsp_cpustat_request(CPUSTAT_RESET);
+ enable_irq(INT_DSP_MMU);
+ /*
+ * if we enable followings, semaphore lock should be avoided.
+ *
+ printk(KERN_INFO "Flushing DSP MMU...\n");
+ exmap_flush();
+ dsp_mmu_init();
+ */
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
+ *
+ */
+struct file_operations dsp_mem_fops = {
+ .owner = THIS_MODULE,
+ .llseek = dsp_mem_lseek,
+ .read = dsp_mem_read,
+ .write = dsp_mem_write,
+ .ioctl = dsp_mem_ioctl,
+ .mmap = dsp_mem_mmap,
+ .open = dsp_mem_open,
+ .release = dsp_mem_release,
+};
+
+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();
+}
+
+int __init dsp_mem_init(void)
+{
+ int i;
+
+ for (i = 0; i < DSPMMU_TLB_LINES; i++) {
+ exmap_tbl[i].valid = 0;
+ }
+
+ dspvect_page = (void *)__get_dma_pages(GFP_KERNEL, 0);
+ if (dspvect_page == NULL) {
+ printk(KERN_ERR
+ "omapdsp: failed to allocate memory "
+ "for dsp vector table\n");
+ return -ENOMEM;
+ }
+ dsp_mmu_init();
+ dsp_set_idle_boot_base(IDLEPG_BASE, IDLEPG_SIZE);
+
+ device_create_file(&dsp_device.dev, &dev_attr_mmu);
+ device_create_file(&dsp_device.dev, &dev_attr_exmap);
+ device_create_file(&dsp_device.dev, &dev_attr_kmem_pool);
+
+ return 0;
+}
+
+void dsp_mem_exit(void)
+{
+ dsp_mmu_shutdown();
+ dsp_kmem_release();
+
+ if (dspvect_page != NULL) {
+ unsigned long virt;
+
+ down_read(&exmap_sem);
+
+ virt = (unsigned long)dspbyte_to_virt(DSP_INIT_PAGE);
+ flush_tlb_kernel_range(virt, virt + PAGE_SIZE);
+ free_page((unsigned long)dspvect_page);
+ dspvect_page = NULL;
+
+ up_read(&exmap_sem);
+ }
+
+ device_remove_file(&dsp_device.dev, &dev_attr_mmu);
+ device_remove_file(&dsp_device.dev, &dev_attr_exmap);
+ device_remove_file(&dsp_device.dev, &dev_attr_kmem_pool);
+}
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap/dsp/error.c
+ *
+ * OMAP DSP error detection I/F device driver
+ *
+ * Copyright (C) 2002-2005 Nokia Corporation
+ *
+ * Written by 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 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
+ *
+ * 2005/03/11: DSP Gateway version 3.3
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/ioctls.h>
+#include <asm/arch/dsp.h>
+#include "dsp.h"
+
+static DECLARE_WAIT_QUEUE_HEAD(err_wait_q);
+static unsigned long errcode;
+static int errcnt;
+static unsigned short wdtval; /* FIXME: read through ioctl */
+static unsigned long mmu_fadr; /* FIXME: read through ioctl */
+
+/*
+ * DSP error detection device file operations
+ */
+static ssize_t dsp_err_read(struct file *file, char *buf, size_t count,
+ loff_t *ppos)
+{
+ unsigned long flags;
+ int status;
+
+ if (count < 4)
+ return 0;
+
+ if (errcnt == 0) {
+ long current_state;
+ DECLARE_WAITQUEUE(wait, current);
+
+ add_wait_queue(&err_wait_q, &wait);
+ current_state = current->state;
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (errcnt == 0) /* last check */
+ schedule();
+ set_current_state(current_state);
+ remove_wait_queue(&err_wait_q, &wait);
+ if (signal_pending(current))
+ return -EINTR;
+ }
+
+ local_irq_save(flags);
+ status = copy_to_user(buf, &errcode, 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,
+};
+
+/*
+ * DSP MMU
+ */
+void dsp_err_mmu_set(unsigned long adr)
+{
+ disable_irq(INT_DSP_MMU);
+ errcode |= OMAP_DSP_ERRDT_MMU;
+ errcnt++;
+ mmu_fadr = adr;
+ wake_up_interruptible(&err_wait_q);
+}
+
+void dsp_err_mmu_clear(void)
+{
+ errcode &= ~OMAP_DSP_ERRDT_MMU;
+ enable_irq(INT_DSP_MMU);
+}
+
+int dsp_err_mmu_isset(void)
+{
+ return (errcode & OMAP_DSP_ERRDT_MMU) ? 1 : 0;
+}
+
+/*
+ * WDT
+ */
+void dsp_err_wdt_clear(void)
+{
+ errcode &= ~OMAP_DSP_ERRDT_WDT;
+}
+
+int dsp_err_wdt_isset(void)
+{
+ return (errcode & OMAP_DSP_ERRDT_WDT) ? 1 : 0;
+}
+
+/*
+ * functions called from mailbox1 interrupt routine
+ */
+static void mbx1_err_wdt(unsigned short data)
+{
+ errcode |= OMAP_DSP_ERRDT_WDT;
+ errcnt++;
+ wdtval = data;
+ wake_up_interruptible(&err_wait_q);
+}
+
+#ifdef OLD_BINARY_SUPPORT
+/* v3.3 obsolete */
+void mbx1_wdt(struct mbcmd *mb)
+{
+ mbx1_err_wdt(mb->data);
+}
+#endif
+
+extern void mbx1_err_ipbfull(void);
+extern void mbx1_err_fatal(unsigned char tid);
+
+void mbx1_err(struct mbcmd *mb)
+{
+ unsigned char eid = mb->cmd_l;
+ char *eidnm = subcmd_name(mb);
+ unsigned char tid;
+
+ if (eidnm) {
+ printk(KERN_WARNING
+ "mbx: ERR from DSP (%s): 0x%04x\n", eidnm, mb->data);
+ } else {
+ printk(KERN_WARNING
+ "mbx: ERR from DSP (unknown EID=%02x): %04x\n",
+ eid, mb->data);
+ }
+
+ switch (eid) {
+ case OMAP_DSP_EID_IPBFULL:
+ mbx1_err_ipbfull();
+ break;
+
+ case OMAP_DSP_EID_FATAL:
+ tid = mb->data & 0x00ff;
+ mbx1_err_fatal(tid);
+ break;
+
+ case OMAP_DSP_EID_WDT:
+ mbx1_err_wdt(mb->data);
+ break;
+ }
+}
+
+/*
+ *
+ */
+void dsp_err_start(void)
+{
+ errcnt = 0;
+ if (dsp_err_wdt_isset())
+ dsp_err_wdt_clear();
+ if (dsp_err_mmu_isset())
+ dsp_err_mmu_clear();
+}
+
+void dsp_err_stop(void)
+{
+ wake_up_interruptible(&err_wait_q);
+}
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap/dsp/fifo.h
+ *
+ * FIFO buffer operators
+ *
+ * Copyright (C) 2002-2005 Nokia Corporation
+ *
+ * Written by 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 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
+ *
+ * 2005/02/24: DSP Gateway version 3.3
+ */
+
+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)
+ 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 */
+ if ((fifo->buf = kmalloc(sz, GFP_KERNEL)) == NULL) {
+ fifo->sz = 0;
+ ret = -ENOMEM;
+ goto out;
+ }
+ fifo->sz = sz;
+ fifo->cnt = 0;
+ fifo->wp = 0;
+
+out:
+ spin_unlock(&fifo->lock);
+ return ret;
+}
+
+static inline void write_word_to_fifo(struct fifo_struct *fifo,
+ unsigned short word)
+{
+ spin_lock(&fifo->lock);
+ *(unsigned short *)&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;
+}
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap/dsp/hardware_dsp.h
+ *
+ * Register bit definitions for DSP driver
+ *
+ * Copyright (C) 2002-2005 Nokia Corporation
+ *
+ * Written by 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 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
+ *
+ * 2005/05/30: DSP Gateway version 3.3
+ */
+
+#ifndef __OMAP_DSP_HARDWARE_DSP_H
+#define __OMAP_DSP_HARDWARE_DSP_H
+
+#ifdef CONFIG_ARCH_OMAP15XX
+#define OMAP1510_DARAM_BASE 0xe0000000
+#define OMAP1510_DARAM_SIZE 0x10000
+#define OMAP1510_SARAM_BASE 0xe0010000
+#define OMAP1510_SARAM_SIZE 0x18000
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
+#define OMAP16XX_DARAM_BASE 0xe0000000
+#define OMAP16XX_DARAM_SIZE 0x10000
+#define OMAP16XX_SARAM_BASE 0xe0010000
+#define OMAP16XX_SARAM_SIZE 0x18000
+#endif
+
+/*
+ * MAJOR device number: !! allocated arbitrary !!
+ */
+#define OMAP_DSP_CTL_MAJOR 96
+#define OMAP_DSP_TASK_MAJOR 97
+
+/*
+ * Reset Control
+ */
+#define ARM_RSTCT1_SW_RST 0x0008
+#define ARM_RSTCT1_DSP_RST 0x0004
+#define ARM_RSTCT1_DSP_EN 0x0002
+#define ARM_RSTCT1_ARM_RST 0x0001
+
+/*
+ * MPUI
+ */
+#define MPUI_CTRL_WORDSWAP_MASK 0x00600000
+#define MPUI_CTRL_WORDSWAP_ALL 0x00000000
+#define MPUI_CTRL_WORDSWAP_NONAPI 0x00200000
+#define MPUI_CTRL_WORDSWAP_API 0x00400000
+#define MPUI_CTRL_WORDSWAP_NONE 0x00600000
+#define MPUI_CTRL_AP_MASK 0x001c0000
+#define MPUI_CTRL_AP_MDH 0x00000000
+#define MPUI_CTRL_AP_MHD 0x00040000
+#define MPUI_CTRL_AP_DMH 0x00080000
+#define MPUI_CTRL_AP_HMD 0x000c0000
+#define MPUI_CTRL_AP_DHM 0x00100000
+#define MPUI_CTRL_AP_HDM 0x00140000
+#define MPUI_CTRL_BYTESWAP_MASK 0x00030000
+#define MPUI_CTRL_BYTESWAP_NONE 0x00000000
+#define MPUI_CTRL_BYTESWAP_NONAPI 0x00010000
+#define MPUI_CTRL_BYTESWAP_ALL 0x00020000
+#define MPUI_CTRL_BYTESWAP_API 0x00030000
+#define MPUI_CTRL_TIMEOUT_MASK 0x0000ff00
+#define MPUI_CTRL_APIF_HNSTB_DIV_MASK 0x000000f0
+#define MPUI_CTRL_S_NABORT_GL 0x00000008
+#define MPUI_CTRL_S_NABORT_32BIT 0x00000004
+#define MPUI_CTRL_EN_TIMEOUT 0x00000002
+#define MPUI_CTRL_HF_MCUCLK 0x00000001
+#define MPUI_DSP_BOOT_CONFIG_DIRECT 0x00000000
+#define MPUI_DSP_BOOT_CONFIG_PSD_DIRECT 0x00000001
+#define MPUI_DSP_BOOT_CONFIG_IDLE 0x00000002
+#define MPUI_DSP_BOOT_CONFIG_DL16 0x00000003
+#define MPUI_DSP_BOOT_CONFIG_DL32 0x00000004
+#define MPUI_DSP_BOOT_CONFIG_MPUI 0x00000005
+#define MPUI_DSP_BOOT_CONFIG_INTERNAL 0x00000006
+
+/*
+ * DSP boot mode
+ * direct: 0xffff00
+ * pseudo direct: 0x080000
+ * MPUI: branch 0x010000
+ * internel: branch 0x024000
+ */
+#define DSP_BOOT_ADR_DIRECT 0xffff00
+#define DSP_BOOT_ADR_PSD_DIRECT 0x080000
+#define DSP_BOOT_ADR_MPUI 0x010000
+#define DSP_BOOT_ADR_INTERNAL 0x024000
+
+/*
+ * TC
+ */
+#define TC_ENDIANISM_SWAP 0x00000002
+#define TC_ENDIANISM_SWAP_WORD 0x00000002
+#define TC_ENDIANISM_SWAP_BYTE 0x00000000
+#define TC_ENDIANISM_EN 0x00000001
+
+/*
+ * DSP MMU
+ */
+#define DSPMMU_BASE (0xfffed200)
+#define DSPMMU_PREFETCH (DSPMMU_BASE + 0x00)
+#define DSPMMU_WALKING_ST (DSPMMU_BASE + 0x04)
+#define DSPMMU_CNTL (DSPMMU_BASE + 0x08)
+#define DSPMMU_FAULT_AD_H (DSPMMU_BASE + 0x0c)
+#define DSPMMU_FAULT_AD_L (DSPMMU_BASE + 0x10)
+#define DSPMMU_FAULT_ST (DSPMMU_BASE + 0x14)
+#define DSPMMU_IT_ACK (DSPMMU_BASE + 0x18)
+#define DSPMMU_TTB_H (DSPMMU_BASE + 0x1c)
+#define DSPMMU_TTB_L (DSPMMU_BASE + 0x20)
+#define DSPMMU_LOCK (DSPMMU_BASE + 0x24)
+#define DSPMMU_LD_TLB (DSPMMU_BASE + 0x28)
+#define DSPMMU_CAM_H (DSPMMU_BASE + 0x2c)
+#define DSPMMU_CAM_L (DSPMMU_BASE + 0x30)
+#define DSPMMU_RAM_H (DSPMMU_BASE + 0x34)
+#define DSPMMU_RAM_L (DSPMMU_BASE + 0x38)
+#define DSPMMU_GFLUSH (DSPMMU_BASE + 0x3c)
+#define DSPMMU_FLUSH_ENTRY (DSPMMU_BASE + 0x40)
+#define DSPMMU_READ_CAM_H (DSPMMU_BASE + 0x44)
+#define DSPMMU_READ_CAM_L (DSPMMU_BASE + 0x48)
+#define DSPMMU_READ_RAM_H (DSPMMU_BASE + 0x4c)
+#define DSPMMU_READ_RAM_L (DSPMMU_BASE + 0x50)
+
+#define DSPMMU_CNTL_BURST_16MNGT_EN 0x0020
+#define DSPMMU_CNTL_WTL_EN 0x0004
+#define DSPMMU_CNTL_MMU_EN 0x0002
+#define DSPMMU_CNTL_RESET_SW 0x0001
+
+#define DSPMMU_FAULT_AD_H_DP 0x0100
+#define DSPMMU_FAULT_AD_H_ADR_MASK 0x00ff
+
+#define DSPMMU_FAULT_ST_PREF 0x0008
+#define DSPMMU_FAULT_ST_PERM 0x0004
+#define DSPMMU_FAULT_ST_TLB_MISS 0x0002
+#define DSPMMU_FAULT_ST_TRANS 0x0001
+
+#define DSPMMU_IT_ACK_IT_ACK 0x0001
+
+#define DSPMMU_LOCK_BASE_MASK 0xfc00
+#define DSPMMU_LOCK_BASE_SHIFT 10
+#define DSPMMU_LOCK_VICTIM_MASK 0x03f0
+#define DSPMMU_LOCK_VICTIM_SHIFT 4
+
+#define DSPMMU_CAM_H_VA_TAG_H_MASK 0x0003
+
+#define DSPMMU_CAM_L_VA_TAG_L1_MASK 0xc000
+#define DSPMMU_CAM_L_VA_TAG_L2_MASK_1MB 0x0000
+#define DSPMMU_CAM_L_VA_TAG_L2_MASK_64KB 0x3c00
+#define DSPMMU_CAM_L_VA_TAG_L2_MASK_4KB 0x3fc0
+#define DSPMMU_CAM_L_VA_TAG_L2_MASK_1KB 0x3ff0
+#define DSPMMU_CAM_L_P 0x0008
+#define DSPMMU_CAM_L_V 0x0004
+#define DSPMMU_CAM_L_SLST_MASK 0x0003
+#define DSPMMU_CAM_L_SLST_1MB 0x0000
+#define DSPMMU_CAM_L_SLST_64KB 0x0001
+#define DSPMMU_CAM_L_SLST_4KB 0x0002
+#define DSPMMU_CAM_L_SLST_1KB 0x0003
+
+#define DSPMMU_RAM_L_RAM_LSB_MASK 0xfc00
+#define DSPMMU_RAM_L_AP_MASK 0x0300
+#define DSPMMU_RAM_L_AP_NA 0x0000
+#define DSPMMU_RAM_L_AP_RO 0x0200
+#define DSPMMU_RAM_L_AP_FA 0x0300
+
+#define DSPMMU_GFLUSH_GFLUSH 0x0001
+
+#define DSPMMU_FLUSH_ENTRY_FLUSH_ENTRY 0x0001
+
+#define DSPMMU_LD_TLB_RD 0x0002
+#define DSPMMU_LD_TLB_LD 0x0001
+
+/*
+ * Mailbox
+ */
+#define MAILBOX_BASE (0xfffcf000)
+#define MAILBOX_ARM2DSP1 (MAILBOX_BASE + 0x00)
+#define MAILBOX_ARM2DSP1b (MAILBOX_BASE + 0x04)
+#define MAILBOX_DSP2ARM1 (MAILBOX_BASE + 0x08)
+#define MAILBOX_DSP2ARM1b (MAILBOX_BASE + 0x0c)
+#define MAILBOX_DSP2ARM2 (MAILBOX_BASE + 0x10)
+#define MAILBOX_DSP2ARM2b (MAILBOX_BASE + 0x14)
+#define MAILBOX_ARM2DSP1_Flag (MAILBOX_BASE + 0x18)
+#define MAILBOX_DSP2ARM1_Flag (MAILBOX_BASE + 0x1c)
+#define MAILBOX_DSP2ARM2_Flag (MAILBOX_BASE + 0x20)
+
+/*
+ * DSP ICR
+ */
+#define DSPREG_ICR_RESERVED_BITS 0xffc0
+#define DSPREG_ICR_EMIF_IDLE_DOMAIN 0x0020
+#define DSPREG_ICR_DPLL_IDLE_DOMAIN 0x0010
+#define DSPREG_ICR_PER_IDLE_DOMAIN 0x0008
+#define DSPREG_ICR_CACHE_IDLE_DOMAIN 0x0004
+#define DSPREG_ICR_DMA_IDLE_DOMAIN 0x0002
+#define DSPREG_ICR_CPU_IDLE_DOMAIN 0x0001
+
+#endif /* __OMAP_DSP_HARDWARE_DSP_H */
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap/dsp/ipbuf.c
+ *
+ * IPBUF handler
+ *
+ * Copyright (C) 2002-2005 Nokia Corporation
+ *
+ * Written by 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 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
+ *
+ * 2005/06/06: DSP Gateway version 3.3
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <asm/signal.h>
+#include <asm/arch/dsp.h>
+#include "dsp.h"
+#include "ipbuf.h"
+
+struct ipbuf **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;
+
+void ipbuf_stop(void)
+{
+ int i;
+
+ spin_lock(&ipb_free.lock);
+ INIT_IPBLINK(&ipb_free);
+ spin_unlock(&ipb_free.lock);
+
+ ipbcfg.ln = 0;
+ if (ipbuf) {
+ kfree(ipbuf);
+ 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(unsigned short ln, unsigned short lsz, void *base)
+{
+ unsigned long lsz_byte = ((unsigned long)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;
+
+ ipbuf = kmalloc(sizeof(void *) * ln, GFP_KERNEL);
+ if (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;
+ ipbuf[i] = (struct ipbuf *)top;
+ 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%08lx\n", i, top, lsz_byte);
+ ret = -EINVAL;
+ goto free_out;
+ }
+ }
+ ipbcfg.ln = ln;
+ ipbcfg.lsz = lsz;
+ ipbcfg.base = base;
+ ipbcfg.bsycnt = ln; /* DSP holds all ipbufs initially. */
+ ipbcfg.cnt_full = 0;
+
+ printk(KERN_INFO
+ "omapdsp: IPBUF configuration\n"
+ " %d words * %d lines at 0x%p.\n",
+ ipbcfg.lsz, ipbcfg.ln, ipbcfg.base);
+
+ return ret;
+
+free_out:
+ kfree(ipbuf);
+ ipbuf = NULL;
+ return ret;
+}
+
+int ipbuf_sys_config(void *p, enum arm_dsp_dir 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, enum arm_dsp_dir 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
+ */
+unsigned short get_free_ipbuf(unsigned char tid)
+{
+ unsigned short bid;
+
+ if (dsp_mem_enable_ipbuf() < 0)
+ return OMAP_DSP_BID_NULL;
+
+ spin_lock(&ipb_free.lock);
+
+ if (ipblink_empty(&ipb_free)) {
+ /* FIXME: wait on queue when not available. */
+ bid = OMAP_DSP_BID_NULL;
+ goto out;
+ }
+ bid = ipb_free.top;
+ ipbuf[bid]->la = tid; /* lock */
+ ipblink_del_top(&ipb_free, ipbuf);
+out:
+ spin_unlock(&ipb_free.lock);
+ dsp_mem_disable_ipbuf();
+
+ return bid;
+}
+
+void release_ipbuf(unsigned short bid)
+{
+ if (ipbuf[bid]->la == OMAP_DSP_TID_FREE) {
+ printk(KERN_WARNING
+ "omapdsp: attempt to release unlocked IPBUF[%d].\n",
+ bid);
+ /*
+ * FIXME: re-calc bsycnt
+ */
+ return;
+ }
+ ipbuf[bid]->la = OMAP_DSP_TID_FREE;
+ ipbuf[bid]->sa = OMAP_DSP_TID_FREE;
+ spin_lock(&ipb_free.lock);
+ ipblink_add_tail(&ipb_free, bid, ipbuf);
+ spin_unlock(&ipb_free.lock);
+}
+
+static int try_yld(unsigned short bid)
+{
+ int status;
+
+ ipbuf[bid]->sa = OMAP_DSP_TID_ANON;
+ status = dsp_mbsend(MBCMD(BKYLD), 0, bid);
+ if (status < 0) {
+ /* DSP is busy and ARM keeps this line. */
+ release_ipbuf(bid);
+ return status;
+ }
+
+ ipb_bsycnt_inc(&ipbcfg);
+ return 0;
+}
+
+/*
+ * balancing ipbuf lines with DSP
+ */
+static void do_balance_ipbuf(void)
+{
+ while (ipbcfg.bsycnt <= ipbcfg.ln / 4) {
+ unsigned short bid;
+
+ bid = get_free_ipbuf(OMAP_DSP_TID_ANON);
+ if (bid == OMAP_DSP_BID_NULL)
+ return;
+ if (try_yld(bid) < 0)
+ return;
+ }
+}
+
+static DECLARE_WORK(balance_ipbuf_work, (void (*)(void *))do_balance_ipbuf,
+ NULL);
+
+void balance_ipbuf(void)
+{
+ schedule_work(&balance_ipbuf_work);
+}
+
+/* for process context */
+void unuse_ipbuf(unsigned short bid)
+{
+ if (ipbcfg.bsycnt > ipbcfg.ln / 4) {
+ /* we don't have enough IPBUF lines. let's keep it. */
+ release_ipbuf(bid);
+ } else {
+ /* we have enough IPBUF lines. let's return this line to DSP. */
+ ipbuf[bid]->la = OMAP_DSP_TID_ANON;
+ try_yld(bid);
+ balance_ipbuf();
+ }
+}
+
+/* for interrupt context */
+void unuse_ipbuf_nowait(unsigned short bid)
+{
+ release_ipbuf(bid);
+ balance_ipbuf();
+}
+
+/*
+ * functions called from mailbox1 interrupt routine
+ */
+
+void mbx1_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;
+ unsigned short bid;
+
+ for (bid = 0; bid < ipbcfg.ln; bid++) {
+ unsigned short la = ipbuf[bid]->la;
+ unsigned short ld = ipbuf[bid]->ld;
+ unsigned short c = ipbuf[bid]->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, ipbuf[bid]);
+ if (la == OMAP_DSP_TID_FREE) {
+ len += sprintf(buf + len,
+ " DSPtask[%d]->Linux "
+ "(already read and now free for Linux)\n",
+ ld);
+ } else if (ld == OMAP_DSP_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, ipbuf) {
+ 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;
+}
+
+struct device_attribute dev_attr_ipbuf = __ATTR_RO(ipbuf);
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap/dsp/ipbuf.h
+ *
+ * Header for IPBUF
+ *
+ * Copyright (C) 2002-2005 Nokia Corporation
+ *
+ * Written by 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 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
+ *
+ * 2005/05/17: DSP Gateway version 3.3
+ */
+
+struct ipbuf {
+ unsigned short c; /* count */
+ unsigned short next; /* link */
+ unsigned short la; /* lock owner (ARM side) */
+ unsigned short sa; /* sync word (ARM->DSP) */
+ unsigned short ld; /* lock owner (DSP side) */
+ unsigned short sd; /* sync word (DSP->ARM) */
+ unsigned char d[0]; /* data */
+};
+
+struct ipbuf_p {
+ unsigned short c; /* count */
+ unsigned short s; /* sync word */
+ unsigned short al; /* data address lower */
+ unsigned short ah; /* data address upper */
+};
+
+struct ipbuf_sys {
+ unsigned short s; /* sync word */
+ unsigned short d[31]; /* data */
+};
+
+struct ipbcfg {
+ unsigned short ln;
+ unsigned short lsz;
+ void *base;
+ unsigned short bsycnt;
+ unsigned long cnt_full; /* count of IPBFULL error */
+};
+
+extern struct ipbuf **ipbuf;
+extern struct ipbcfg ipbcfg;
+extern struct ipbuf_sys *ipbuf_sys_da, *ipbuf_sys_ad;
+
+#define ipb_bsycnt_inc(ipbcfg) \
+ do { \
+ disable_irq(INT_D2A_MB1); \
+ (ipbcfg)->bsycnt++; \
+ enable_irq(INT_D2A_MB1); \
+ } while(0)
+
+#define ipb_bsycnt_dec(ipbcfg) \
+ do { \
+ disable_irq(INT_D2A_MB1); \
+ (ipbcfg)->bsycnt--; \
+ enable_irq(INT_D2A_MB1); \
+ } while(0)
+
+#define dsp_mem_enable_ipbuf() dsp_mem_enable(ipbcfg.base)
+#define dsp_mem_disable_ipbuf() dsp_mem_disable(ipbcfg.base)
+
+struct ipblink {
+ spinlock_t lock;
+ unsigned short top;
+ unsigned short tail;
+};
+
+#define IPBLINK_INIT { \
+ .lock = SPIN_LOCK_UNLOCKED, \
+ .top = OMAP_DSP_BID_NULL, \
+ .tail = OMAP_DSP_BID_NULL, \
+ }
+
+#define INIT_IPBLINK(link) \
+ do { \
+ spin_lock_init(&(link)->lock); \
+ (link)->top = OMAP_DSP_BID_NULL; \
+ (link)->tail = OMAP_DSP_BID_NULL; \
+ } while(0)
+
+#define ipblink_empty(link) ((link)->top == OMAP_DSP_BID_NULL)
+
+static __inline__ void ipblink_del_top(struct ipblink *link,
+ struct ipbuf **ipbuf)
+{
+ struct ipbuf *bufp = ipbuf[link->top];
+
+ if ((link->top = bufp->next) == OMAP_DSP_BID_NULL)
+ link->tail = OMAP_DSP_BID_NULL;
+ else
+ bufp->next = OMAP_DSP_BID_NULL;
+}
+
+static __inline__ void ipblink_add_tail(struct ipblink *link,
+ unsigned short bid,
+ struct ipbuf **ipbuf)
+{
+ if (ipblink_empty(link))
+ link->top = bid;
+ else
+ ipbuf[link->tail]->next = bid;
+ link->tail = bid;
+}
+
+static __inline__ void ipblink_add_pvt(struct ipblink *link)
+{
+ link->top = OMAP_DSP_BID_PVT;
+ link->tail = OMAP_DSP_BID_PVT;
+}
+
+static __inline__ void ipblink_del_pvt(struct ipblink *link)
+{
+ link->top = OMAP_DSP_BID_NULL;
+ link->tail = OMAP_DSP_BID_NULL;
+}
+
+#define ipblink_for_each(bid, link, ipbuf) \
+ for (bid = (link)->top; bid != OMAP_DSP_BID_NULL; bid = ipbuf[bid]->next)
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap/dsp/mblog.c
+ *
+ * OMAP DSP driver Mailbox log module
+ *
+ * Copyright (C) 2003-2005 Nokia Corporation
+ *
+ * Written by 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 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
+ *
+ * 2005/05/18: DSP Gateway version 3.3
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <asm/irq.h>
+#include <asm/arch/dsp.h>
+#include "dsp.h"
+
+#define RLCMD(nm) OMAP_DSP_MBCMD_RUNLEVEL_##nm
+#define KFUNCCMD(nm) OMAP_DSP_MBCMD_KFUNC_##nm
+#define PMCMD(nm) OMAP_DSP_MBCMD_PM_##nm
+#define CFGCMD(nm) OMAP_DSP_MBCMD_DSPCFG_##nm
+#define REGCMD(nm) OMAP_DSP_MBCMD_REGRW_##nm
+#define VICMD(nm) OMAP_DSP_MBCMD_VARID_##nm
+#define EID(nm) OMAP_DSP_EID_##nm
+
+char *subcmd_name(struct mbcmd *mb)
+{
+ unsigned char cmd_h = mb->cmd_h;
+ unsigned char cmd_l = mb->cmd_l;
+ char *s;
+
+ switch (cmd_h) {
+ case MBCMD(RUNLEVEL):
+ s = (cmd_l == RLCMD(USER)) ? "USER":
+ (cmd_l == RLCMD(SUPER)) ? "SUPER":
+ (cmd_l == RLCMD(RECOVERY)) ? "RECOVERY":
+ NULL;
+ break;
+ case MBCMD(PM):
+ s = (cmd_l == PMCMD(DISABLE)) ? "DISABLE":
+ (cmd_l == PMCMD(ENABLE)) ? "ENABLE":
+ NULL;
+ break;
+ case MBCMD(KFUNC):
+ s = (cmd_l == KFUNCCMD(FBCTL)) ? "FBCTL":
+ (cmd_l == KFUNCCMD(AUDIO_PWR)) ? "AUDIO_PWR":
+ NULL;
+ break;
+ case MBCMD(DSPCFG):
+ {
+ unsigned char cfgc = cmd_l & 0x7f;
+ s = (cfgc == CFGCMD(REQ)) ? "REQ":
+ (cfgc == CFGCMD(SYSADRH)) ? "SYSADRH":
+ (cfgc == CFGCMD(SYSADRL)) ? "SYSADRL":
+ (cfgc == CFGCMD(ABORT)) ? "ABORT":
+ (cfgc == CFGCMD(PROTREV)) ? "PROTREV":
+ NULL;
+ break;
+ }
+ case MBCMD(REGRW):
+ s = (cmd_l == REGCMD(MEMR)) ? "MEMR":
+ (cmd_l == REGCMD(MEMW)) ? "MEMW":
+ (cmd_l == REGCMD(IOR)) ? "IOR":
+ (cmd_l == REGCMD(IOW)) ? "IOW":
+ (cmd_l == REGCMD(DATA)) ? "DATA":
+ NULL;
+ break;
+ case MBCMD(GETVAR):
+ case MBCMD(SETVAR):
+ s = (cmd_l == VICMD(ICRMASK)) ? "ICRMASK":
+ (cmd_l == VICMD(LOADINFO)) ? "LOADINFO":
+ NULL;
+ break;
+ case MBCMD(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;
+ unsigned short cmd;
+ unsigned short data;
+ enum arm_dsp_dir dir;
+};
+
+static struct {
+ spinlock_t lock;
+ int wp;
+ unsigned long cnt, cnt_ad, cnt_da;
+ struct mblogent ent[MBLOG_DEPTH];
+} mblog;
+
+void mblog_add(struct mbcmd *mb, enum arm_dsp_dir dir)
+{
+ struct mbcmd_hw *mb_hw = (struct mbcmd_hw *)mb;
+ struct mblogent *ent;
+
+ spin_lock(&mblog.lock);
+ ent = &mblog.ent[mblog.wp];
+ ent->jiffies = jiffies;
+ ent->cmd = mb_hw->cmd;
+ ent->data = mb_hw->data;
+ 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);
+}
+
+/*
+ * 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 q cmd data q cmd data\n");
+ i = (mblog.cnt >= MBLOG_DEPTH) ? wp : 0;
+ do {
+ struct mblogent *ent = &mblog.ent[i];
+ union {
+ struct mbcmd sw;
+ struct mbcmd_hw hw;
+ } mb = {
+ .hw.cmd = ent->cmd,
+ .hw.data = ent->data
+ };
+ char *subname;
+ const struct cmdinfo *ci = cmdinfo[mb.sw.cmd_h];
+
+ len += sprintf(buf + len,
+ (ent->dir == DIR_A2D) ?
+ "%08lx %d %04x %04x ":
+ "%08lx %d %04x %04x ",
+ ent->jiffies, mb.sw.seq, ent->cmd, ent->data);
+ switch (ci->cmd_l_type) {
+ case CMD_L_TYPE_SUBCMD:
+ if ((subname = subcmd_name(&mb.sw)) == 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.sw.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);
+
+#ifdef CONFIG_OMAP_DSP_MBCMD_VERBOSE
+void mblog_printcmd(struct mbcmd *mb, enum arm_dsp_dir 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:
+ if ((subname = subcmd_name(mb)) == NULL)
+ subname = "Unknown";
+ printk(KERN_DEBUG
+ "mbx: %s seq=%d, cmd=%02x:%02x(%s:%s), data=%04x\n",
+ dir_str, mb->seq, mb->cmd_h, mb->cmd_l,
+ ci->name, subname, mb->data);
+ break;
+ case CMD_L_TYPE_TID:
+ printk(KERN_DEBUG
+ "mbx: %s seq=%d, cmd=%02x:%02x(%s:task %d), data=%04x\n",
+ dir_str, mb->seq, mb->cmd_h, mb->cmd_l,
+ ci->name, mb->cmd_l, mb->data);
+ break;
+ case CMD_L_TYPE_NULL:
+ printk(KERN_DEBUG
+ "mbx: %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;
+ }
+}
+#endif /* CONFIG_OMAP_DSP_MBCMD_VERBOSE */
+
+void __init mblog_init(void)
+{
+ spin_lock_init(&mblog.lock);
+ device_create_file(&dsp_device.dev, &dev_attr_mblog);
+}
+
+void mblog_exit(void)
+{
+ device_remove_file(&dsp_device.dev, &dev_attr_mblog);
+}
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap/dsp/proclist.h
+ *
+ * Linux task list handler
+ *
+ * Copyright (C) 2004,2005 Nokia Corporation
+ *
+ * Written by 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 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
+ *
+ * 2004/11/22: DSP Gateway version 3.3
+ */
+
+struct proc_list {
+ struct list_head list_head;
+ pid_t pid;
+ unsigned int cnt;
+};
+
+static __inline__ void proc_list_add(struct list_head *list,
+ struct task_struct *tsk)
+{
+ struct proc_list *pl;
+ struct proc_list *new;
+
+ list_for_each_entry(pl, list, list_head) {
+ if (pl->pid == tsk->pid) {
+ /*
+ * this process has opened DSP devices multi time
+ */
+ pl->cnt++;
+ return;
+ }
+ }
+
+ new = kmalloc(sizeof(struct proc_list), GFP_KERNEL);
+ new->pid = tsk->pid;
+ new->cnt = 1;
+ list_add_tail(&new->list_head, list);
+}
+
+static __inline__ void proc_list_del(struct list_head *list,
+ struct task_struct *tsk)
+{
+ struct proc_list *pl, *next;
+
+ list_for_each_entry(pl, list, list_head) {
+ if (pl->pid == tsk->pid) {
+ if (--pl->cnt == 0) {
+ list_del(&pl->list_head);
+ kfree(pl);
+ }
+ return;
+ }
+ }
+
+ /*
+ * correspinding pid wasn't found in the list
+ * -- this means the caller of proc_list_del is different from
+ * the proc_list_add's caller. in this case, the parent is
+ * cleaning up the context of a killed child.
+ * let's delete exiting task from the list.
+ */
+ /* need to lock tasklist_lock before calling find_task_by_pid_type. */
+ read_lock(&tasklist_lock);
+ list_for_each_entry_safe(pl, next, list, list_head) {
+ if (find_task_by_pid_type(PIDTYPE_PID, pl->pid) == NULL) {
+ list_del(&pl->list_head);
+ kfree(pl);
+ }
+ }
+ read_unlock(&tasklist_lock);
+}
+
+static __inline__ void proc_list_flush(struct list_head *list)
+{
+ struct proc_list *pl;
+
+ while (!list_empty(list)) {
+ pl = list_entry(list->next, struct proc_list, list_head);
+ list_del(&pl->list_head);
+ kfree(pl);
+ }
+}
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap/dsp/task.c
+ *
+ * OMAP DSP task device driver
+ *
+ * Copyright (C) 2002-2005 Nokia Corporation
+ *
+ * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ * mmap function by Hiroo Ishikawa <ext-hiroo.ishikawa@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
+ *
+ * 2005/07/26: DSP Gateway version 3.3
+ */
+
+#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/proc_fs.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/signal.h>
+#include <asm/irq.h>
+#include <asm/ioctls.h>
+#include <asm/arch/dsp.h>
+#include "uaccess_dsp.h"
+#include "dsp.h"
+#include "ipbuf.h"
+#include "fifo.h"
+#include "proclist.h"
+
+#define is_aligned(adr,align) (!((adr)&((align)-1)))
+
+/*
+ * taskdev.state: 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.
+ * ADDFAIL: tadd failed.
+ * ADDING: tadd in process.
+ * DELING: tdel in process.
+ * KILLING: tkill in process.
+ */
+#define devstate_name(stat) (\
+ ((stat) & OMAP_DSP_DEVSTATE_NOTASK) ? "NOTASK" :\
+ ((stat) & OMAP_DSP_DEVSTATE_ATTACHED) ? "ATTACHED" :\
+ ((stat) & OMAP_DSP_DEVSTATE_GARBAGE) ? "GARBAGE" :\
+ ((stat) & OMAP_DSP_DEVSTATE_INVALID) ? "INVALID" :\
+ ((stat) & OMAP_DSP_DEVSTATE_ADDREQ) ? "ADDREQ" :\
+ ((stat) & OMAP_DSP_DEVSTATE_DELREQ) ? "DELREQ" :\
+ ((stat) & OMAP_DSP_DEVSTATE_ADDFAIL) ? "ADDFAIL" :\
+ ((stat) & OMAP_DSP_DEVSTATE_ADDING) ? "ADDING" :\
+ ((stat) & OMAP_DSP_DEVSTATE_DELING) ? "DELING" :\
+ ((stat) & OMAP_DSP_DEVSTATE_KILLING) ? "KILLING" :\
+ "unknown")
+
+struct taskdev {
+ struct bus_type *bus;
+// struct device_driver *driver;
+ struct device dev; /* Generic device interface */
+
+ long state;
+ spinlock_t state_lock;
+ wait_queue_head_t state_wait_q;
+ unsigned int usecount;
+ char name[OMAP_DSP_TNM_LEN];
+ struct file_operations fops;
+ struct list_head proc_list;
+ struct dsptask *task;
+
+ /* read stuff */
+ wait_queue_head_t read_wait_q;
+ struct semaphore read_sem;
+
+ /* write stuff */
+ wait_queue_head_t write_wait_q;
+ struct semaphore write_sem;
+
+ /* ioctl stuff */
+ wait_queue_head_t ioctl_wait_q;
+ struct semaphore ioctl_sem;
+
+ /* device lock */
+ struct semaphore lock_sem;
+ pid_t lock_pid;
+};
+
+#define to_taskdev(n) container_of(n, struct taskdev, dev)
+
+struct rcvdt_bk_struct {
+ struct ipblink link;
+ unsigned int rp;
+ struct ipbuf_p *ipbuf_pvt_r;
+};
+
+struct dsptask {
+ enum {
+ TASK_STATE_ERR = 0,
+ TASK_STATE_READY,
+ TASK_STATE_CFGREQ
+ } state;
+ unsigned char tid;
+ char name[OMAP_DSP_TNM_LEN];
+ unsigned short ttyp;
+ struct taskdev *dev;
+
+ /* read stuff */
+ union {
+ struct fifo_struct fifo; /* for active word */
+ struct rcvdt_bk_struct bk;
+ } rcvdt;
+
+ /* write stuff */
+ size_t wsz;
+ spinlock_t wsz_lock;
+ struct ipbuf_p *ipbuf_pvt_w; /* for private block */
+
+ /* tctl stuff */
+ int tctl_stat;
+
+ /* mmap stuff */
+ void *map_base;
+ size_t map_length;
+};
+
+#define sndtyp_acv(ttyp) ((ttyp) & OMAP_DSP_TTYP_ASND)
+#define sndtyp_psv(ttyp) (!((ttyp) & OMAP_DSP_TTYP_ASND))
+#define sndtyp_bk(ttyp) ((ttyp) & OMAP_DSP_TTYP_BKDM)
+#define sndtyp_wd(ttyp) (!((ttyp) & OMAP_DSP_TTYP_BKDM))
+#define sndtyp_pvt(ttyp) ((ttyp) & OMAP_DSP_TTYP_PVDM)
+#define sndtyp_gbl(ttyp) (!((ttyp) & OMAP_DSP_TTYP_PVDM))
+#define rcvtyp_acv(ttyp) ((ttyp) & OMAP_DSP_TTYP_ARCV)
+#define rcvtyp_psv(ttyp) (!((ttyp) & OMAP_DSP_TTYP_ARCV))
+#define rcvtyp_bk(ttyp) ((ttyp) & OMAP_DSP_TTYP_BKMD)
+#define rcvtyp_wd(ttyp) (!((ttyp) & OMAP_DSP_TTYP_BKMD))
+#define rcvtyp_pvt(ttyp) ((ttyp) & OMAP_DSP_TTYP_PVMD)
+#define rcvtyp_gbl(ttyp) (!((ttyp) & OMAP_DSP_TTYP_PVMD))
+
+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 void taskdev_attach_task(struct taskdev *dev, struct dsptask *task);
+static void taskdev_detach_task(struct taskdev *dev);
+static int dsp_tdel_bh(unsigned char minor, unsigned short type);
+
+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);
+
+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_fifosz =
+ __ATTR(fifosz, S_IWUGO | S_IRUGO, fifosz_show, fifosz_store);
+static struct device_attribute dev_attr_fifocnt = __ATTR_RO(fifocnt);
+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_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 struct bus_type dsptask_bus = {
+ .name = "dsptask",
+};
+
+static struct class *dsp_task_class;
+static struct taskdev *taskdev[TASKDEV_MAX];
+static struct dsptask *dsptask[TASKDEV_MAX];
+static DECLARE_MUTEX(cfg_sem);
+static unsigned short cfg_cmd;
+static unsigned char cfg_tid;
+static DECLARE_WAIT_QUEUE_HEAD(cfg_wait_q);
+static unsigned char n_task;
+static void *heap;
+
+#define devstate_lock(dev, devstate) devstate_lock_timeout(dev, devstate, 0)
+
+/*
+ * devstate_lock_timeout():
+ * when called with timeout > 0, dev->state can be diffeent from what you want.
+ */
+static int devstate_lock_timeout(struct taskdev *dev, long devstate,
+ int timeout)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ long current_state = current->state;
+ int ret = 0;
+
+ spin_lock(&dev->state_lock);
+ add_wait_queue(&dev->state_wait_q, &wait);
+ while (!(dev->state & devstate)) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_unlock(&dev->state_lock);
+ if (timeout) {
+ if ((timeout = schedule_timeout(timeout)) == 0) {
+ /* timeout */
+ spin_lock(&dev->state_lock);
+ break;
+ }
+ }
+ else
+ schedule();
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ spin_lock(&dev->state_lock);
+ }
+ remove_wait_queue(&dev->state_wait_q, &wait);
+ set_current_state(current_state);
+ return ret;
+}
+
+static __inline__ void devstate_unlock(struct taskdev *dev)
+{
+ spin_unlock(&dev->state_lock);
+}
+
+static __inline__ int down_tasksem_interruptible(struct taskdev *dev,
+ struct semaphore *sem)
+{
+ int ret;
+
+ if (dev->lock_pid == current->pid) {
+ /* this process has lock */
+ ret = down_interruptible(sem);
+ } else {
+ if ((ret = down_interruptible(&dev->lock_sem)) != 0)
+ return ret;
+ ret = down_interruptible(sem);
+ up(&dev->lock_sem);
+ }
+ return ret;
+}
+
+static void proclist_send_sigbus(struct list_head *list)
+{
+ siginfo_t info;
+ struct proc_list *pl;
+ struct task_struct *tsk;
+
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = SI_KERNEL;
+ info._sifields._sigfault._addr = NULL;
+
+ /* need to lock tasklist_lock before calling find_task_by_pid_type. */
+ read_lock(&tasklist_lock);
+ list_for_each_entry(pl, list, list_head) {
+ if ((tsk = find_task_by_pid_type(PIDTYPE_PID, pl->pid)) != NULL)
+ send_sig_info(SIGBUS, &info, tsk);
+ }
+ read_unlock(&tasklist_lock);
+}
+
+static int dsp_task_flush_buf(struct dsptask *task)
+{
+ unsigned short ttyp = task->ttyp;
+
+ if (sndtyp_wd(ttyp)) {
+ /* word receiving */
+ flush_fifo(&task->rcvdt.fifo);
+ } else {
+ /* block receiving */
+ struct rcvdt_bk_struct *rcvdt = &task->rcvdt.bk;
+
+ spin_lock(&rcvdt->link.lock);
+ if (sndtyp_gbl(ttyp)) {
+ /* global IPBUF */
+ while (!ipblink_empty(&rcvdt->link)) {
+ unsigned short bid = rcvdt->link.top;
+ ipblink_del_top(&rcvdt->link, ipbuf);
+ unuse_ipbuf(bid);
+ }
+ } else {
+ /* private IPBUF */
+ if (!ipblink_empty(&rcvdt->link)) {
+ ipblink_del_pvt(&rcvdt->link);
+ release_ipbuf_pvt(rcvdt->ipbuf_pvt_r);
+ }
+ }
+ spin_unlock(&rcvdt->link.lock);
+ }
+
+ return 0;
+}
+
+static int dsp_task_set_fifosz(struct dsptask *task, unsigned long sz)
+{
+ unsigned short ttyp = 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(&task->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, task->name);
+ return stat;
+ }
+
+ return 0;
+}
+
+static int taskdev_lock(struct taskdev *dev)
+{
+ if (down_interruptible(&dev->lock_sem))
+ return -ERESTARTSYS;
+ dev->lock_pid = current->pid;
+ return 0;
+}
+
+static int taskdev_unlock(struct taskdev *dev)
+{
+ if (dev->lock_pid != current->pid) {
+ printk(KERN_ERR
+ "omapdsp: an illegal process attempted to "
+ "unlock the dsptask lock!\n");
+ return -EINVAL;
+ }
+ dev->lock_pid = 0;
+ up(&dev->lock_sem);
+ return 0;
+}
+
+static int dsp_task_config(struct dsptask *task, unsigned char tid)
+{
+ unsigned short ttyp;
+ struct mbcmd mb;
+ int ret;
+
+ task->tid = tid;
+ dsptask[tid] = task;
+
+ /* TCFG request */
+ task->state = TASK_STATE_CFGREQ;
+ if (down_interruptible(&cfg_sem)) {
+ ret = -ERESTARTSYS;
+ goto fail_out;
+ }
+ cfg_cmd = MBCMD(TCFG);
+ mbcmd_set(mb, MBCMD(TCFG), tid, 0);
+ dsp_mbcmd_send_and_wait(&mb, &cfg_wait_q);
+ cfg_cmd = 0;
+ up(&cfg_sem);
+
+ if (task->state != TASK_STATE_READY) {
+ printk(KERN_ERR "omapdsp: task %d configuration error!\n", tid);
+ ret = -EINVAL;
+ goto fail_out;
+ }
+
+ if (strlen(task->name) <= 1)
+ sprintf(task->name, "%d", tid);
+ printk(KERN_INFO "omapdsp: task %d: name %s\n", tid, task->name);
+
+ ttyp = task->ttyp;
+
+ /*
+ * task info sanity check
+ */
+
+ /* task type check */
+ if (rcvtyp_psv(ttyp) && rcvtyp_pvt(ttyp)) {
+ printk(KERN_ERR "omapdsp: illegal task type(0x%04x), tid=%d\n",
+ tid, ttyp);
+ ret = -EINVAL;
+ goto fail_out;
+ }
+
+ /* private buffer address check */
+ if (sndtyp_pvt(ttyp) &&
+ (ipbuf_p_validate(task->rcvdt.bk.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;
+ }
+
+ /*
+ * initialization
+ */
+
+ /* read initialization */
+ if (sndtyp_wd(ttyp)) {
+ /* word */
+ size_t fifosz;
+
+ fifosz = sndtyp_psv(ttyp) ? 2 : /* passive */
+ 32; /* active */
+ if (init_fifo(&task->rcvdt.fifo, fifosz) < 0) {
+ printk(KERN_ERR
+ "omapdsp: unable to allocate receive buffer. "
+ "(%d bytes for %s)\n", fifosz, task->name);
+ ret = -ENOMEM;
+ goto fail_out;
+ }
+ } else {
+ /* block */
+ INIT_IPBLINK(&task->rcvdt.bk.link);
+ task->rcvdt.bk.rp = 0;
+ }
+
+ /* write initialization */
+ spin_lock_init(&task->wsz_lock);
+ task->wsz = rcvtyp_acv(ttyp) ? 0 : /* active */
+ rcvtyp_wd(ttyp) ? 2 : /* passive word */
+ ipbcfg.lsz*2; /* passive block */
+
+ return 0;
+
+fail_out:
+ dsptask[tid] = NULL;
+ return ret;
+}
+
+static void dsp_task_init(struct dsptask *task)
+{
+ dsp_mbsend(MBCMD(TCTL), task->tid, OMAP_DSP_MBCMD_TCTL_TINIT);
+}
+
+int dsp_task_config_all(unsigned char n)
+{
+ int i, ret;
+ struct taskdev *devheap;
+ struct dsptask *taskheap;
+ size_t devheapsz, taskheapsz;
+
+ memset(taskdev, 0, sizeof(void *) * TASKDEV_MAX);
+ memset(dsptask, 0, sizeof(void *) * TASKDEV_MAX);
+
+ n_task = n;
+ printk(KERN_INFO "omapdsp: found %d task(s)\n", n_task);
+ if (n_task == 0)
+ return 0;
+
+ /*
+ * reducing kmalloc!
+ */
+ devheapsz = sizeof(struct taskdev) * n_task;
+ taskheapsz = sizeof(struct dsptask) * n_task;
+ heap = kmalloc(devheapsz + taskheapsz, GFP_KERNEL);
+ if (heap == NULL) {
+ n_task = 0;
+ return -ENOMEM;
+ }
+ memset(heap, 0, devheapsz + taskheapsz);
+ devheap = heap;
+ taskheap = heap + devheapsz;
+
+ for (i = 0; i < n_task; 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;
+ taskdev_attach_task(dev, task);
+ dsp_task_init(task);
+ printk(KERN_INFO "omapdsp: taskdev %s enabled.\n", dev->name);
+ }
+
+ return 0;
+}
+
+static void dsp_task_unconfig(struct dsptask *task)
+{
+ unsigned char tid = task->tid;
+
+ preempt_disable();
+ dsp_task_flush_buf(task);
+ if (sndtyp_wd(task->ttyp) && (task->state == TASK_STATE_READY))
+ free_fifo(&task->rcvdt.fifo);
+ dsptask[tid] = NULL;
+ preempt_enable();
+}
+
+void dsp_task_unconfig_all(void)
+{
+ unsigned char minor;
+ unsigned char 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,
+};
+
+unsigned char dsp_task_count(void)
+{
+ return n_task;
+}
+
+int dsp_taskmod_busy(void)
+{
+ struct taskdev *dev;
+ unsigned char minor;
+
+ for (minor = 0; minor < TASKDEV_MAX; minor++) {
+ dev = taskdev[minor];
+ if (dev == NULL)
+ continue;
+ if (dev->usecount > 0) {
+ printk("dsp_taskmod_busy(): %s: usecount=%d\n",
+ dev->name, dev->usecount);
+ return 1;
+ }
+/*
+ if ((dev->state & (OMAP_DSP_DEVSTATE_ADDREQ |
+ OMAP_DSP_DEVSTATE_DELREQ)) {
+*/
+ if (dev->state & OMAP_DSP_DEVSTATE_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 *buf, size_t count,
+ loff_t *ppos)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ int have_devstate_lock = 0;
+ int ret = 0;
+
+ if (count == 0) {
+ return 0;
+ } else if (count & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: odd count is illegal for DSP task device.\n");
+ return -EINVAL;
+ }
+
+ if (down_tasksem_interruptible(dev, &dev->read_sem))
+ return -ERESTARTSYS;
+ if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
+ ret = -ERESTARTSYS;
+ goto up_out;
+ }
+ have_devstate_lock = 1;
+
+ if (fifo_empty(&dev->task->rcvdt.fifo)) {
+ long current_state = current->state;
+ DECLARE_WAITQUEUE(wait, current);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&dev->read_wait_q, &wait);
+ if (fifo_empty(&dev->task->rcvdt.fifo)) { /* last check */
+ devstate_unlock(dev);
+ have_devstate_lock = 0;
+ schedule();
+ }
+ set_current_state(current_state);
+ remove_wait_queue(&dev->read_wait_q, &wait);
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ goto up_out;
+ }
+ if (!have_devstate_lock) {
+ if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
+ ret = -ERESTARTSYS;
+ goto up_out;
+ }
+ have_devstate_lock = 1;
+ }
+ if (fifo_empty(&dev->task->rcvdt.fifo)) /* should not occur */
+ goto up_out;
+ }
+
+ ret = copy_to_user_fm_fifo(buf, &dev->task->rcvdt.fifo, count);
+
+up_out:
+ if (have_devstate_lock)
+ devstate_unlock(dev);
+ up(&dev->read_sem);
+ return ret;
+}
+
+static ssize_t dsp_task_read_bk_acv(struct file *file, char *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;
+ int have_devstate_lock = 0;
+ ssize_t ret = 0;
+
+ if (count == 0) {
+ return 0;
+ } else if (count & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: odd count is illegal for DSP task device.\n");
+ return -EINVAL;
+ } else if ((int)buf & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: buf should be word aligned for "
+ "dsp_task_read().\n");
+ return -EINVAL;
+ }
+
+ if (down_tasksem_interruptible(dev, &dev->read_sem))
+ return -ERESTARTSYS;
+ if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
+ ret = -ERESTARTSYS;
+ goto up_out;
+ }
+ have_devstate_lock = 1;
+
+ if (ipblink_empty(&dev->task->rcvdt.bk.link)) {
+ long current_state;
+ DECLARE_WAITQUEUE(wait, current);
+
+ add_wait_queue(&dev->read_wait_q, &wait);
+ current_state = current->state;
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (ipblink_empty(&dev->task->rcvdt.bk.link)) { /* last check */
+ devstate_unlock(dev);
+ have_devstate_lock = 0;
+ schedule();
+ }
+ set_current_state(current_state);
+ remove_wait_queue(&dev->read_wait_q, &wait);
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ goto up_out;
+ }
+ if (!have_devstate_lock) {
+ if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
+ ret = -ERESTARTSYS;
+ goto up_out;
+ }
+ have_devstate_lock = 1;
+ }
+ /* signal or 0-byte send from DSP */
+ if (ipblink_empty(&dev->task->rcvdt.bk.link))
+ goto up_out;
+ }
+
+ rcvdt = &dev->task->rcvdt.bk;
+ /* copy from delayed IPBUF */
+ if (sndtyp_pvt(dev->task->ttyp)) {
+ /* private */
+ if (!ipblink_empty(&rcvdt->link)) {
+ struct ipbuf_p *ipbp = rcvdt->ipbuf_pvt_r;
+ unsigned char *base, *src;
+ size_t bkcnt;
+
+ if (dsp_mem_enable(ipbp) < 0) {
+ ret = -ERESTARTSYS;
+ 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 = -ERESTARTSYS;
+ goto pv_out1;
+ }
+ if (dsp_mem_enable(base) < 0) {
+ ret = -ERESTARTSYS;
+ 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;
+ spin_lock(&rcvdt->link.lock);
+ ipblink_del_pvt(&rcvdt->link);
+ spin_unlock(&rcvdt->link.lock);
+ 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 = -ERESTARTSYS;
+ goto up_out;
+ }
+ while (!ipblink_empty(&rcvdt->link)) {
+ unsigned char *src;
+ size_t bkcnt;
+ unsigned short bid = rcvdt->link.top;
+ struct ipbuf *ipbp = ipbuf[bid];
+
+ src = ipbp->d + rcvdt->rp;
+ bkcnt = ((unsigned long)ipbp->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;
+ spin_lock(&rcvdt->link.lock);
+ ipblink_del_top(&rcvdt->link, ipbuf);
+ spin_unlock(&rcvdt->link.lock);
+ unuse_ipbuf(bid);
+ rcvdt->rp = 0;
+ }
+ }
+gb_out:
+ dsp_mem_disable_ipbuf();
+ }
+
+up_out:
+ if (have_devstate_lock)
+ devstate_unlock(dev);
+ up(&dev->read_sem);
+ return ret;
+}
+
+static ssize_t dsp_task_read_wd_psv(struct file *file, char *buf, size_t count,
+ loff_t *ppos)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ struct mbcmd mb;
+ unsigned char tid;
+ 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 (down_tasksem_interruptible(dev, &dev->read_sem))
+ return -ERESTARTSYS;
+ if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
+ ret = -ERESTARTSYS;
+ goto up_out;
+ }
+ tid = dev->task->tid;
+ devstate_unlock(dev);
+
+ mbcmd_set(mb, MBCMD(WDREQ), tid, 0);
+ dsp_mbcmd_send_and_wait(&mb, &dev->read_wait_q);
+
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ goto up_out;
+ }
+ if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
+ ret = -ERESTARTSYS;
+ goto up_out;
+ }
+ if (fifo_empty(&dev->task->rcvdt.fifo)) /* should not occur */
+ goto unlock_out;
+
+ ret = copy_to_user_fm_fifo(buf, &dev->task->rcvdt.fifo, count);
+
+unlock_out:
+ devstate_unlock(dev);
+up_out:
+ up(&dev->read_sem);
+ return ret;
+}
+
+static ssize_t dsp_task_read_bk_psv(struct file *file, char *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;
+ struct mbcmd mb;
+ unsigned char tid;
+ 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 (down_tasksem_interruptible(dev, &dev->read_sem))
+ return -ERESTARTSYS;
+ if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
+ ret = -ERESTARTSYS;
+ goto up_out;
+ }
+ tid = dev->task->tid;
+ devstate_unlock(dev);
+
+ mbcmd_set(mb, MBCMD(BKREQ), tid, count/2);
+ dsp_mbcmd_send_and_wait(&mb, &dev->read_wait_q);
+
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ goto up_out;
+ }
+ if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
+ ret = -ERESTARTSYS;
+ goto up_out;
+ }
+ rcvdt = &dev->task->rcvdt.bk;
+ /* signal or 0-byte send from DSP */
+ if (ipblink_empty(&rcvdt->link))
+ goto unlock_out;
+
+ /*
+ * We will not receive more than requested count.
+ */
+ if (sndtyp_pvt(dev->task->ttyp)) {
+ /* private */
+ struct ipbuf_p *ipbp = rcvdt->ipbuf_pvt_r;
+ size_t rcvcnt;
+ void *src;
+
+ if (dsp_mem_enable(ipbp) < 0) {
+ ret = -ERESTARTSYS;
+ goto unlock_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 = -ERESTARTSYS;
+ goto pv_out1;
+ }
+ if (dsp_mem_enable(src) < 0) {
+ ret = -ERESTARTSYS;
+ goto pv_out1;
+ }
+ if (count > rcvcnt)
+ count = rcvcnt;
+ if (copy_to_user_dsp(buf, src, count)) {
+ ret = -EFAULT;
+ goto pv_out2;
+ }
+ spin_lock(&rcvdt->link.lock);
+ ipblink_del_pvt(&rcvdt->link);
+ spin_unlock(&rcvdt->link.lock);
+ release_ipbuf_pvt(ipbp);
+ ret = count;
+pv_out2:
+ dsp_mem_disable(src);
+pv_out1:
+ dsp_mem_disable(ipbp);
+ } else {
+ /* global */
+ unsigned short bid = rcvdt->link.top;
+ struct ipbuf *ipbp = ipbuf[bid];
+ size_t rcvcnt;
+
+ if (dsp_mem_enable_ipbuf() < 0) {
+ ret = -ERESTARTSYS;
+ goto unlock_out;
+ }
+ rcvcnt = ((unsigned long)ipbp->c) * 2;
+ if (count > rcvcnt)
+ count = rcvcnt;
+ if (copy_to_user_dsp(buf, ipbp->d, count)) {
+ ret = -EFAULT;
+ goto gb_out;
+ }
+ spin_lock(&rcvdt->link.lock);
+ ipblink_del_top(&rcvdt->link, ipbuf);
+ spin_unlock(&rcvdt->link.lock);
+ unuse_ipbuf(bid);
+ ret = count;
+gb_out:
+ dsp_mem_disable_ipbuf();
+ }
+
+unlock_out:
+ devstate_unlock(dev);
+up_out:
+ up(&dev->read_sem);
+ return ret;
+}
+
+static ssize_t dsp_task_write_wd(struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ unsigned short wd;
+ int have_devstate_lock = 0;
+ 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 (down_tasksem_interruptible(dev, &dev->write_sem))
+ return -ERESTARTSYS;
+ if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
+ ret = -ERESTARTSYS;
+ goto up_out;
+ }
+ have_devstate_lock = 1;
+
+ if (dev->task->wsz == 0) {
+ long current_state;
+ DECLARE_WAITQUEUE(wait, current);
+
+ add_wait_queue(&dev->write_wait_q, &wait);
+ current_state = current->state;
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (dev->task->wsz == 0) { /* last check */
+ devstate_unlock(dev);
+ have_devstate_lock = 0;
+ schedule();
+ }
+ set_current_state(current_state);
+ remove_wait_queue(&dev->write_wait_q, &wait);
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ goto up_out;
+ }
+ if (!have_devstate_lock) {
+ if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
+ ret = -ERESTARTSYS;
+ goto up_out;
+ }
+ have_devstate_lock = 1;
+ }
+ if (dev->task->wsz == 0) /* should not occur */
+ goto up_out;
+ }
+
+ if (copy_from_user(&wd, buf, count)) {
+ ret = -EFAULT;
+ goto up_out;
+ }
+
+ spin_lock(&dev->task->wsz_lock);
+ if (dsp_mbsend(MBCMD(WDSND), dev->task->tid, wd) < 0) {
+ spin_unlock(&dev->task->wsz_lock);
+ goto up_out;
+ }
+ ret = count;
+ if (rcvtyp_acv(dev->task->ttyp))
+ dev->task->wsz = 0;
+ spin_unlock(&dev->task->wsz_lock);
+
+up_out:
+ if (have_devstate_lock)
+ devstate_unlock(dev);
+ up(&dev->write_sem);
+ return ret;
+}
+
+static ssize_t dsp_task_write_bk(struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ int have_devstate_lock = 0;
+ int ret = 0;
+
+ if (count == 0) {
+ return 0;
+ } else if (count & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: odd count is illegal for DSP task device.\n");
+ return -EINVAL;
+ } else if ((int)buf & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: buf should be word aligned for "
+ "dsp_task_write().\n");
+ return -EINVAL;
+ }
+
+ if (down_tasksem_interruptible(dev, &dev->write_sem))
+ return -ERESTARTSYS;
+ if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
+ ret = -ERESTARTSYS;
+ goto up_out;
+ }
+ have_devstate_lock = 1;
+
+ if (dev->task->wsz == 0) {
+ long current_state;
+ DECLARE_WAITQUEUE(wait, current);
+
+ add_wait_queue(&dev->write_wait_q, &wait);
+ current_state = current->state;
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (dev->task->wsz == 0) { /* last check */
+ devstate_unlock(dev);
+ have_devstate_lock = 0;
+ schedule();
+ }
+ set_current_state(current_state);
+ remove_wait_queue(&dev->write_wait_q, &wait);
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ goto up_out;
+ }
+ if (!have_devstate_lock) {
+ if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
+ ret = -ERESTARTSYS;
+ goto up_out;
+ }
+ have_devstate_lock = 1;
+ }
+ if (dev->task->wsz == 0) /* should not occur */
+ goto up_out;
+ }
+
+ if (count > dev->task->wsz)
+ count = dev->task->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 = -ERESTARTSYS;
+ goto up_out;
+ }
+ dst = MKVIRT(ipbp->ah, ipbp->al);
+ if (dsp_address_validate(dst, count, "task %s write buffer",
+ dev->task->name) < 0) {
+ ret = -ERESTARTSYS;
+ goto pv_out1;
+ }
+ if (dsp_mem_enable(dst) < 0) {
+ ret = -ERESTARTSYS;
+ 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->task->wsz_lock);
+ if (dsp_mbsend(MBCMD(BKSNDP), dev->task->tid, 0) == 0) {
+ if (rcvtyp_acv(dev->task->ttyp))
+ dev->task->wsz = 0;
+ ret = count;
+ }
+ spin_unlock(&dev->task->wsz_lock);
+pv_out2:
+ dsp_mem_disable(dst);
+pv_out1:
+ dsp_mem_disable(ipbp);
+ } else {
+ /* global */
+ struct ipbuf *ipbp;
+ unsigned short bid;
+
+ if (dsp_mem_enable_ipbuf() < 0) {
+ ret = -ERESTARTSYS;
+ goto up_out;
+ }
+ bid = get_free_ipbuf(dev->task->tid);
+ if (bid == OMAP_DSP_BID_NULL)
+ goto gb_out;
+ ipbp = ipbuf[bid];
+ if (copy_from_user_dsp(ipbp->d, buf, count)) {
+ release_ipbuf(bid);
+ ret = -EFAULT;
+ goto gb_out;
+ }
+ ipbp->c = count/2;
+ ipbp->sa = dev->task->tid;
+ spin_lock(&dev->task->wsz_lock);
+ if (dsp_mbsend(MBCMD(BKSND), dev->task->tid, bid) == 0) {
+ if (rcvtyp_acv(dev->task->ttyp))
+ dev->task->wsz = 0;
+ ret = count;
+ ipb_bsycnt_inc(&ipbcfg);
+ } else
+ release_ipbuf(bid);
+ spin_unlock(&dev->task->wsz_lock);
+gb_out:
+ dsp_mem_disable_ipbuf();
+ }
+
+up_out:
+ if (have_devstate_lock)
+ devstate_unlock(dev);
+ up(&dev->write_sem);
+ 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;
+
+ poll_wait(file, &dev->read_wait_q, wait);
+ poll_wait(file, &dev->write_wait_q, wait);
+ if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0)
+ return 0;
+ if (sndtyp_psv(task->ttyp) ||
+ (sndtyp_wd(task->ttyp) && !fifo_empty(&task->rcvdt.fifo)) ||
+ (sndtyp_bk(task->ttyp) && !ipblink_empty(&task->rcvdt.bk.link)))
+ mask |= POLLIN | POLLRDNORM;
+ if (task->wsz)
+ mask |= POLLOUT | POLLWRNORM;
+ devstate_unlock(dev);
+
+ return mask;
+}
+
+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];
+ struct mbcmd mb;
+ unsigned char tid;
+ struct mb_exarg mbarg, *mbargp;
+ int mbargc;
+ unsigned short mbargv[1];
+ int interactive;
+ int ret;
+
+ /* LOCK / UNLOCK operations */
+ switch (cmd) {
+ case OMAP_DSP_TASK_IOCTL_LOCK:
+ return taskdev_lock(dev);
+ case OMAP_DSP_TASK_IOCTL_UNLOCK:
+ return taskdev_unlock(dev);
+ }
+
+ /*
+ * actually only interractive commands need to lock
+ * the semaphore, but here all commands do it for simplicity.
+ */
+ if (down_tasksem_interruptible(dev, &dev->ioctl_sem))
+ return -ERESTARTSYS;
+ if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
+ ret = -ERESTARTSYS;
+ goto up_out;
+ }
+
+ if ((cmd >= 0x0080) && (cmd < 0x0100)) {
+ /*
+ * 0x0080 - 0x00ff
+ * reserved for backward compatibility
+ * user-defined TCTL commands: no arg, non-interactive
+ */
+ printk(KERN_WARNING "omapdsp: "
+ "TCTL commands in 0x0080 - 0x0100 are obsolete.\n"
+ "they won't be supported in the future.\n");
+ mbargc = 0;
+ interactive = 0;
+ } else if (cmd < 0x8000) {
+ /*
+ * 0x0000 - 0x7fff (except 0x0080 - 0x00ff)
+ * system reserved TCTL commands
+ */
+ switch (cmd) {
+ case OMAP_DSP_MBCMD_TCTL_TEN:
+ case OMAP_DSP_MBCMD_TCTL_TDIS:
+ mbargc = 0;
+ interactive = 0;
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ goto unlock_out;
+ }
+ }
+ /*
+ * 0x8000 - 0xffff
+ * user-defined TCTL commands
+ */
+ else if (cmd < 0x8100) {
+ /* 0x8000-0x80ff: no arg, non-interactive */
+ mbargc = 0;
+ interactive = 0;
+ } else if (cmd < 0x8200) {
+ /* 0x8100-0x81ff: 1 arg, non-interactive */
+ mbargc = 1;
+ mbargv[0] = arg & 0xffff;
+ interactive = 0;
+ } else if (cmd < 0x9000) {
+ /* 0x8200-0x8fff: reserved */
+ ret = -ENOIOCTLCMD;
+ goto unlock_out;
+ } else if (cmd < 0x9100) {
+ /* 0x9000-0x90ff: no arg, interactive */
+ mbargc = 0;
+ interactive = 1;
+ } else if (cmd < 0x9200) {
+ /* 0x9100-0x91ff: 1 arg, interactive */
+ mbargc = 1;
+ mbargv[0] = arg & 0xffff;
+ interactive = 1;
+ } else if (cmd < 0x10000) {
+ /* 0x9200-0xffff: reserved */
+ ret = -ENOIOCTLCMD;
+ goto unlock_out;
+ } else {
+ /*
+ * 0x10000 -
+ * non TCTL ioctls
+ */
+ switch (cmd) {
+ case OMAP_DSP_TASK_IOCTL_BFLSH:
+ ret = dsp_task_flush_buf(dev->task);
+ break;
+ case OMAP_DSP_TASK_IOCTL_SETBSZ:
+ ret = dsp_task_set_fifosz(dev->task, arg);
+ break;
+ case OMAP_DSP_TASK_IOCTL_GETNAME:
+ ret = 0;
+ if (copy_to_user((void *)arg, dev->name,
+ strlen(dev->name) + 1))
+ ret = -EFAULT;
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ }
+ goto unlock_out;
+ }
+
+ /*
+ * issue TCTL
+ */
+ tid = dev->task->tid;
+ mbcmd_set(mb, MBCMD(TCTL), tid, cmd);
+ if (mbargc > 0) {
+ mbarg.argc = mbargc;
+ mbarg.tid = tid;
+ mbarg.argv = mbargv;
+ mbargp = &mbarg;
+ } else
+ mbargp = NULL;
+
+ if (interactive) {
+ dev->task->tctl_stat = -ERESTARTSYS;
+ devstate_unlock(dev);
+
+ dsp_mbcmd_send_and_wait_exarg(&mb, mbargp, &dev->ioctl_wait_q);
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ goto up_out;
+ }
+ if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
+ ret = -ERESTARTSYS;
+ goto up_out;
+ }
+ ret = dev->task->tctl_stat;
+ if (ret < 0) {
+ printk(KERN_ERR "omapdsp: TCTL not responding.\n");
+ goto unlock_out;
+ }
+ } else {
+ dsp_mbcmd_send_exarg(&mb, mbargp);
+ ret = 0;
+ }
+
+unlock_out:
+ devstate_unlock(dev);
+up_out:
+ up(&dev->ioctl_sem);
+ 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 & OMAP_DSP_DEVSTATE_ATTACHED));
+ task = dev->task;
+ exmap_use(task->map_base, len);
+}
+
+static void dsp_task_mmap_close(struct vm_area_struct *vma)
+{
+ struct taskdev *dev = (struct taskdev *)vma->vm_private_data;
+ struct dsptask *task;
+ size_t len = vma->vm_end - vma->vm_start;
+
+ BUG_ON(!(dev->state & OMAP_DSP_DEVSTATE_ATTACHED));
+ task = dev->task;
+ exmap_unuse(task->map_base, len);
+}
+
+/**
+ * On demand page allocation is not allowed. The mapping area is defined by
+ * corresponding DSP tasks.
+ */
+static struct page *dsp_task_mmap_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+{
+ return NOPAGE_SIGBUS;
+}
+
+static struct vm_operations_struct dsp_task_vm_ops = {
+ .open = dsp_task_mmap_open,
+ .close = dsp_task_mmap_close,
+ .nopage = dsp_task_mmap_nopage,
+};
+
+static int dsp_task_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ void *tmp_vadr;
+ unsigned long tmp_padr, tmp_vmadr, off;
+ size_t req_len, tmp_len;
+ unsigned int minor = MINOR(filp->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ struct dsptask *task;
+ int ret = 0;
+
+ if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0)
+ return -ERESTARTSYS;
+ task = dev->task;
+
+ /*
+ * Don't swap this area out
+ * Don't dump this area to a core file
+ */
+ vma->vm_flags |= VM_RESERVED | VM_IO;
+
+ /* Do not cache this area */
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ req_len = vma->vm_end - vma->vm_start;
+ off = vma->vm_pgoff << PAGE_SHIFT;
+ tmp_vmadr = vma->vm_start;
+ tmp_vadr = task->map_base + off;
+ do {
+ tmp_padr = dsp_virt_to_phys(tmp_vadr, &tmp_len);
+ if (tmp_padr == 0) {
+ printk(KERN_ERR
+ "omapdsp: task %s: illegal address "
+ "for mmap: %p", task->name, tmp_vadr);
+ /* partial mapping will be cleared in upper layer */
+ ret = -EINVAL;
+ goto unlock_out;
+ }
+ if (tmp_len > req_len)
+ tmp_len = req_len;
+
+ printk(KERN_DEBUG
+ "omapdsp: mmap info: "
+ "vmadr = %08lx, padr = %08lx, len = %x\n",
+ tmp_vmadr, tmp_padr, tmp_len);
+ if (remap_pfn_range(vma, tmp_vmadr, tmp_padr >> PAGE_SHIFT,
+ tmp_len, vma->vm_page_prot) != 0) {
+ printk(KERN_ERR
+ "omapdsp: task %s: remap_page_range() failed.\n",
+ task->name);
+ /* partial mapping will be cleared in upper layer */
+ ret = -EINVAL;
+ goto unlock_out;
+ }
+
+ req_len -= tmp_len;
+ tmp_vmadr += tmp_len;
+ tmp_vadr += tmp_len;
+ } while (req_len);
+
+ vma->vm_ops = &dsp_task_vm_ops;
+ vma->vm_private_data = dev;
+ exmap_use(task->map_base, vma->vm_end - vma->vm_start);
+
+unlock_out:
+ devstate_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;
+ if (devstate_lock(dev, OMAP_DSP_DEVSTATE_NOTASK |
+ OMAP_DSP_DEVSTATE_ATTACHED) < 0)
+ return -ERESTARTSYS;
+#ifndef CONFIG_OMAP_DSP_TASK_MULTIOPEN
+ if (dev->usecount > 0) {
+ ret = -EBUSY;
+ goto unlock_out;
+ }
+#endif
+
+ if (dev->state & OMAP_DSP_DEVSTATE_NOTASK) {
+ dev->state = OMAP_DSP_DEVSTATE_ADDREQ;
+ /* wake up twch daemon for tadd */
+ dsp_twch_touch();
+ devstate_unlock(dev);
+ if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED |
+ OMAP_DSP_DEVSTATE_ADDFAIL) < 0) {
+ spin_lock(&dev->state_lock);
+ if (dev->state & OMAP_DSP_DEVSTATE_ADDREQ)
+ dev->state = OMAP_DSP_DEVSTATE_NOTASK;
+ spin_unlock(&dev->state_lock);
+ return -ERESTARTSYS;
+ }
+ if (dev->state & OMAP_DSP_DEVSTATE_ADDFAIL) {
+ printk(KERN_ERR "omapdsp: task attach failed for %s!\n",
+ dev->name);
+ ret = -EBUSY;
+ dev->state = OMAP_DSP_DEVSTATE_NOTASK;
+ wake_up_interruptible_all(&dev->state_wait_q);
+ goto unlock_out;
+ }
+ }
+
+ /* state_lock covers usecount, proc_list as well. */
+ dev->usecount++;
+ proc_list_add(&dev->proc_list, current);
+ file->f_op = &dev->fops;
+ devstate_unlock(dev);
+
+ return 0;
+
+unlock_out:
+ devstate_unlock(dev);
+ 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];
+
+ /* state_lock covers usecount, proc_list as well. */
+ spin_lock(&dev->state_lock);
+
+ /* state can be ATTACHED, KILLING or GARBAGE here. */
+ switch (dev->state & OMAP_DSP_DEVSTATE_STATE_MASK) {
+
+ case OMAP_DSP_DEVSTATE_KILLING:
+ dev->usecount--;
+ break;
+
+ case OMAP_DSP_DEVSTATE_GARBAGE:
+ if(--dev->usecount == 0) {
+ dev->state = OMAP_DSP_DEVSTATE_NOTASK;
+ wake_up_interruptible_all(&dev->state_wait_q);
+ }
+ break;
+
+ case OMAP_DSP_DEVSTATE_ATTACHED:
+ if (dev->lock_pid == current->pid)
+ taskdev_unlock(dev);
+ proc_list_del(&dev->proc_list, current);
+ if (--dev->usecount == 0) {
+ if (minor >= n_task) { /* dynamic task */
+ dev->state = OMAP_DSP_DEVSTATE_DELREQ;
+ /* wake up twch daemon for tdel */
+ dsp_twch_touch();
+ }
+ }
+ break;
+
+ }
+
+ spin_unlock(&dev->state_lock);
+ return 0;
+}
+
+/*
+ * mkdev / rmdev
+ */
+int dsp_mkdev(char *name)
+{
+ struct taskdev *dev;
+ int status;
+ unsigned char minor;
+
+ if (!dsp_is_ready()) {
+ printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
+ return -EINVAL;
+ }
+ for (minor = n_task; minor < TASKDEV_MAX; minor++) {
+ if (taskdev[minor] == NULL)
+ goto do_make;
+ }
+ printk(KERN_ERR "omapdsp: Too many task devices.\n");
+ return -EBUSY;
+
+do_make:
+ if ((dev = kmalloc(sizeof(struct taskdev), GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+ memset(dev, 0, sizeof(struct taskdev));
+ if ((status = taskdev_init(dev, name, minor)) < 0) {
+ kfree(dev);
+ return status;
+ }
+ return minor;
+}
+
+int dsp_rmdev(char *name)
+{
+ unsigned char minor;
+ int ret;
+
+ if (!dsp_is_ready()) {
+ printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
+ return -EINVAL;
+ }
+ for (minor = n_task; minor < TASKDEV_MAX; minor++) {
+ if (taskdev[minor] && !strcmp(taskdev[minor]->name, name)) {
+ if ((ret = dsp_rmdev_minor(minor)) < 0)
+ return ret;
+ return minor;
+ }
+ }
+ return -EINVAL;
+}
+
+static int dsp_rmdev_minor(unsigned char minor)
+{
+ struct taskdev *dev = taskdev[minor];
+
+ spin_lock(&dev->state_lock);
+
+ switch (dev->state & OMAP_DSP_DEVSTATE_STATE_MASK) {
+
+ case OMAP_DSP_DEVSTATE_NOTASK:
+ /* fine */
+ break;
+
+ case OMAP_DSP_DEVSTATE_ATTACHED:
+ /* task is working. kill it. */
+ dev->state = OMAP_DSP_DEVSTATE_KILLING;
+ proclist_send_sigbus(&dev->proc_list);
+ spin_unlock(&dev->state_lock);
+ dsp_tdel_bh(minor, OMAP_DSP_MBCMD_TDEL_KILL);
+ goto invalidate;
+
+ case OMAP_DSP_DEVSTATE_ADDREQ:
+ /* open() is waiting. drain it. */
+ dev->state = OMAP_DSP_DEVSTATE_ADDFAIL;
+ wake_up_interruptible_all(&dev->state_wait_q);
+ break;
+
+ case OMAP_DSP_DEVSTATE_DELREQ:
+ /* nobody is waiting. */
+ dev->state = OMAP_DSP_DEVSTATE_NOTASK;
+ wake_up_interruptible_all(&dev->state_wait_q);
+ break;
+
+ case OMAP_DSP_DEVSTATE_ADDING:
+ case OMAP_DSP_DEVSTATE_DELING:
+ case OMAP_DSP_DEVSTATE_KILLING:
+ case OMAP_DSP_DEVSTATE_GARBAGE:
+ case OMAP_DSP_DEVSTATE_ADDFAIL:
+ /* transient state. wait for a moment. */
+ break;
+
+ }
+
+ spin_unlock(&dev->state_lock);
+
+invalidate:
+ /* wait for some time and hope the state is settled */
+ devstate_lock_timeout(dev, OMAP_DSP_DEVSTATE_NOTASK, HZ);
+ if (!(dev->state & OMAP_DSP_DEVSTATE_NOTASK)) {
+ printk(KERN_WARNING
+ "omapdsp: illegal device state (%s) on rmdev %s.\n",
+ devstate_name(dev->state), dev->name);
+ }
+ dev->state = OMAP_DSP_DEVSTATE_INVALID;
+ devstate_unlock(dev);
+
+ taskdev_delete(minor);
+ kfree(dev);
+
+ return 0;
+}
+
+struct file_operations dsp_task_fops = {
+ .owner = THIS_MODULE,
+ .poll = dsp_task_poll,
+ .ioctl = dsp_task_ioctl,
+ .open = dsp_task_open,
+ .release = dsp_task_release,
+};
+
+static void dsptask_dev_release(struct device *dev)
+{
+}
+
+static int taskdev_init(struct taskdev *dev, char *name, unsigned char minor)
+{
+ struct class_device *cdev;
+
+ taskdev[minor] = dev;
+
+ INIT_LIST_HEAD(&dev->proc_list);
+ init_waitqueue_head(&dev->read_wait_q);
+ init_waitqueue_head(&dev->write_wait_q);
+ init_waitqueue_head(&dev->ioctl_wait_q);
+ init_MUTEX(&dev->read_sem);
+ init_MUTEX(&dev->write_sem);
+ init_MUTEX(&dev->ioctl_sem);
+ init_MUTEX(&dev->lock_sem);
+ dev->lock_pid = 0;
+
+ strncpy(dev->name, name, OMAP_DSP_TNM_LEN);
+ dev->name[OMAP_DSP_TNM_LEN-1] = '\0';
+ dev->state = (minor < n_task) ? OMAP_DSP_DEVSTATE_ATTACHED :
+ OMAP_DSP_DEVSTATE_NOTASK;
+ dev->usecount = 0;
+ memcpy(&dev->fops, &dsp_task_fops, sizeof(struct file_operations));
+
+ dev->dev.parent = &dsp_device.dev;
+ dev->dev.bus = &dsptask_bus;
+ sprintf(dev->dev.bus_id, "dsptask%d", minor);
+ dev->dev.release = dsptask_dev_release;
+ device_register(&dev->dev);
+ device_create_file(&dev->dev, &dev_attr_devname);
+ device_create_file(&dev->dev, &dev_attr_devstate);
+ device_create_file(&dev->dev, &dev_attr_proc_list);
+ cdev = class_device_create(dsp_task_class, NULL,
+ MKDEV(OMAP_DSP_TASK_MAJOR, minor),
+ NULL, "dsptask%d", minor);
+
+ init_waitqueue_head(&dev->state_wait_q);
+ spin_lock_init(&dev->state_lock);
+
+ return 0;
+}
+
+static void taskdev_delete(unsigned char minor)
+{
+ struct taskdev *dev = taskdev[minor];
+
+ if (!dev)
+ return;
+ device_remove_file(&dev->dev, &dev_attr_devname);
+ device_remove_file(&dev->dev, &dev_attr_devstate);
+ device_remove_file(&dev->dev, &dev_attr_proc_list);
+ class_device_destroy(dsp_task_class, MKDEV(OMAP_DSP_TASK_MAJOR, minor));
+ device_unregister(&dev->dev);
+ proc_list_flush(&dev->proc_list);
+ taskdev[minor] = NULL;
+}
+
+static void taskdev_attach_task(struct taskdev *dev, struct dsptask *task)
+{
+ unsigned short ttyp = task->ttyp;
+
+ dev->task = task;
+ task->dev = dev;
+ 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;
+ dev->fops.write =
+ rcvtyp_wd(ttyp) ? dsp_task_write_wd:
+ /* rcvbyp_bk */ dsp_task_write_bk;
+ if (task->map_length)
+ dev->fops.mmap = dsp_task_mmap;
+
+ device_create_file(&dev->dev, &dev_attr_taskname);
+ device_create_file(&dev->dev, &dev_attr_ttyp);
+ if (sndtyp_wd(ttyp)) {
+ device_create_file(&dev->dev, &dev_attr_fifosz);
+ device_create_file(&dev->dev, &dev_attr_fifocnt);
+ } else
+ device_create_file(&dev->dev, &dev_attr_ipblink);
+ device_create_file(&dev->dev, &dev_attr_wsz);
+ if (task->map_length)
+ device_create_file(&dev->dev, &dev_attr_mmap);
+}
+
+static void taskdev_detach_task(struct taskdev *dev)
+{
+ unsigned short 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);
+
+ if (dev->task) {
+ dev->task = NULL;
+ dev->fops.read = NULL;
+ dev->fops.write = NULL;
+ printk(KERN_INFO "omapdsp: taskdev %s disabled.\n", dev->name);
+ }
+}
+
+/*
+ * tadd / tdel / tkill
+ */
+int dsp_tadd(unsigned char minor, unsigned long adr)
+{
+ struct taskdev *dev;
+ struct dsptask *task;
+ struct mbcmd mb;
+ struct mb_exarg arg;
+ unsigned char tid, tid_response;
+ unsigned short argv[2];
+ int ret = minor;
+
+ if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
+ printk(KERN_ERR
+ "omapdsp: no task device with minor %d\n", minor);
+ return -EINVAL;
+ }
+
+ spin_lock(&dev->state_lock);
+ if (!(dev->state & OMAP_DSP_DEVSTATE_ADDREQ)) {
+ printk(KERN_ERR
+ "omapdsp: taskdev %s is not requesting for tadd. "
+ "(state is %s)\n", dev->name, devstate_name(dev->state));
+ spin_unlock(&dev->state_lock);
+ return -EINVAL;
+ }
+ dev->state = OMAP_DSP_DEVSTATE_ADDING;
+ spin_unlock(&dev->state_lock);
+
+ if (adr == OMAP_DSP_TADD_ABORTADR) {
+ /* aborting tadd intentionally */
+ printk(KERN_INFO "omapdsp: tadd address is ABORTADR.\n");
+ goto fail_out;
+ }
+ if (adr >= DSPSPACE_SIZE) {
+ printk(KERN_ERR
+ "omapdsp: illegal address 0x%08lx for tadd\n", adr);
+ ret = -EINVAL;
+ goto fail_out;
+ }
+
+ adr >>= 1; /* word address */
+ argv[0] = adr >> 16; /* addrh */
+ argv[1] = adr & 0xffff; /* addrl */
+
+ if (down_interruptible(&cfg_sem)) {
+ ret = -ERESTARTSYS;
+ goto fail_out;
+ }
+ cfg_tid = OMAP_DSP_TID_ANON;
+ cfg_cmd = MBCMD(TADD);
+ mbcmd_set(mb, MBCMD(TADD), 0, 0);
+ arg.tid = OMAP_DSP_TID_ANON;
+ arg.argc = 2;
+ arg.argv = argv;
+
+ dsp_mem_sync_inc();
+ dsp_mbcmd_send_and_wait_exarg(&mb, &arg, &cfg_wait_q);
+
+ tid = cfg_tid;
+ cfg_tid = OMAP_DSP_TID_ANON;
+ cfg_cmd = 0;
+ up(&cfg_sem);
+
+ if (tid == OMAP_DSP_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 = kmalloc(sizeof(struct dsptask), GFP_KERNEL)) == NULL) {
+ ret = -ENOMEM;
+ goto del_out;
+ }
+ memset(task, 0, sizeof(struct dsptask));
+
+ if ((ret = dsp_task_config(task, tid)) < 0)
+ goto free_out;
+ taskdev_attach_task(dev, task);
+
+ 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;
+ }
+
+ dsp_task_init(task);
+ printk(KERN_INFO "omapdsp: taskdev %s enabled.\n", dev->name);
+ dev->state = OMAP_DSP_DEVSTATE_ATTACHED;
+ wake_up_interruptible_all(&dev->state_wait_q);
+ return minor;
+
+free_out:
+ kfree(task);
+
+del_out:
+ printk(KERN_ERR "omapdsp: deleting the task...\n");
+
+ dev->state = OMAP_DSP_DEVSTATE_DELING;
+
+ if (down_interruptible(&cfg_sem)) {
+ printk(KERN_ERR "omapdsp: aborting tdel process. "
+ "DSP side could be corrupted.\n");
+ goto fail_out;
+ }
+ cfg_tid = OMAP_DSP_TID_ANON;
+ cfg_cmd = MBCMD(TDEL);
+ mbcmd_set(mb, MBCMD(TDEL), tid, OMAP_DSP_MBCMD_TDEL_KILL);
+ dsp_mbcmd_send_and_wait(&mb, &cfg_wait_q);
+ tid_response = cfg_tid;
+ cfg_tid = OMAP_DSP_TID_ANON;
+ cfg_cmd = 0;
+ up(&cfg_sem);
+
+ if (tid_response != tid)
+ printk(KERN_ERR "omapdsp: tdel failed. "
+ "DSP side could be corrupted.\n");
+
+fail_out:
+ dev->state = OMAP_DSP_DEVSTATE_ADDFAIL;
+ wake_up_interruptible_all(&dev->state_wait_q);
+ return ret;
+}
+
+int dsp_tdel(unsigned char minor)
+{
+ struct taskdev *dev;
+
+ if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
+ printk(KERN_ERR
+ "omapdsp: no task device with minor %d\n", minor);
+ return -EINVAL;
+ }
+ spin_lock(&dev->state_lock);
+ if (!(dev->state & OMAP_DSP_DEVSTATE_DELREQ)) {
+ printk(KERN_ERR
+ "omapdsp: taskdev %s is not requesting for tdel. "
+ "(state is %s)\n", dev->name, devstate_name(dev->state));
+ spin_unlock(&dev->state_lock);
+ return -EINVAL;
+ }
+ dev->state = OMAP_DSP_DEVSTATE_DELING;
+ spin_unlock(&dev->state_lock);
+
+ return dsp_tdel_bh(minor, OMAP_DSP_MBCMD_TDEL_SAFE);
+}
+
+int dsp_tkill(unsigned char minor)
+{
+ struct taskdev *dev;
+
+ if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
+ printk(KERN_ERR
+ "omapdsp: no task device with minor %d\n", minor);
+ return -EINVAL;
+ }
+ spin_lock(&dev->state_lock);
+ if (!(dev->state & OMAP_DSP_DEVSTATE_ATTACHED)) {
+ printk(KERN_ERR
+ "omapdsp: task has not been attached for taskdev %s\n",
+ dev->name);
+ spin_unlock(&dev->state_lock);
+ return -EINVAL;
+ }
+ dev->state = OMAP_DSP_DEVSTATE_KILLING;
+ proclist_send_sigbus(&dev->proc_list);
+ spin_unlock(&dev->state_lock);
+
+ return dsp_tdel_bh(minor, OMAP_DSP_MBCMD_TDEL_KILL);
+}
+
+static int dsp_tdel_bh(unsigned char minor, unsigned short type)
+{
+ struct taskdev *dev = taskdev[minor];
+ struct dsptask *task;
+ struct mbcmd mb;
+ unsigned char tid, tid_response;
+ int ret = minor;
+
+ task = dev->task;
+ tid = task->tid;
+ if (down_interruptible(&cfg_sem)) {
+ if (type == OMAP_DSP_MBCMD_TDEL_SAFE) {
+ dev->state = OMAP_DSP_DEVSTATE_DELREQ;
+ return -ERESTARTSYS;
+ } else {
+ tid_response = OMAP_DSP_TID_ANON;
+ ret = -ERESTARTSYS;
+ goto detach_out;
+ }
+ }
+ cfg_tid = OMAP_DSP_TID_ANON;
+ cfg_cmd = MBCMD(TDEL);
+ mbcmd_set(mb, MBCMD(TDEL), tid, type);
+ dsp_mbcmd_send_and_wait(&mb, &cfg_wait_q);
+ tid_response = cfg_tid;
+ cfg_tid = OMAP_DSP_TID_ANON;
+ cfg_cmd = 0;
+ up(&cfg_sem);
+
+detach_out:
+ taskdev_detach_task(dev);
+ dsp_task_unconfig(task);
+ kfree(task);
+
+ if (tid_response != tid) {
+ printk(KERN_ERR "omapdsp: %s failed!\n",
+ (type == OMAP_DSP_MBCMD_TDEL_SAFE) ? "tdel" : "tkill");
+ ret = -EINVAL;
+ }
+ spin_lock(&dev->state_lock);
+ dev->state = (dev->usecount > 0) ? OMAP_DSP_DEVSTATE_GARBAGE :
+ OMAP_DSP_DEVSTATE_NOTASK;
+ wake_up_interruptible_all(&dev->state_wait_q);
+ spin_unlock(&dev->state_lock);
+
+ return ret;
+}
+
+/*
+ * state inquiry
+ */
+long taskdev_state_stale(unsigned char minor)
+{
+ if (taskdev[minor]) {
+ long state = taskdev[minor]->state;
+ taskdev[minor]->state |= OMAP_DSP_DEVSTATE_STALE;
+ return state;
+ } else
+ return OMAP_DSP_DEVSTATE_NOTASK;
+}
+
+/*
+ * functions called from mailbox1 interrupt routine
+ */
+void mbx1_wdsnd(struct mbcmd *mb)
+{
+ unsigned char tid = mb->cmd_l;
+ struct dsptask *task = dsptask[tid];
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbx: WDSND with illegal tid! %d\n", tid);
+ return;
+ }
+ if (sndtyp_bk(task->ttyp)) {
+ printk(KERN_ERR
+ "mbx: 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
+ "mbx: WDSND from passive sending task (task%d) "
+ "without request!\n", tid);
+ return;
+ }
+
+ write_word_to_fifo(&task->rcvdt.fifo, mb->data);
+ wake_up_interruptible(&task->dev->read_wait_q);
+}
+
+void mbx1_wdreq(struct mbcmd *mb)
+{
+ unsigned char tid = mb->cmd_l;
+ struct dsptask *task = dsptask[tid];
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbx: WDREQ with illegal tid! %d\n", tid);
+ return;
+ }
+ if (rcvtyp_psv(task->ttyp)) {
+ printk(KERN_ERR
+ "mbx: WDREQ from passive receiving task! (task%d)\n",
+ tid);
+ return;
+ }
+
+ spin_lock(&task->wsz_lock);
+ task->wsz = 2;
+ spin_unlock(&task->wsz_lock);
+ wake_up_interruptible(&task->dev->write_wait_q);
+}
+
+void mbx1_bksnd(struct mbcmd *mb)
+{
+ unsigned char tid = mb->cmd_l;
+ unsigned short bid = mb->data;
+ struct dsptask *task = dsptask[tid];
+ unsigned short cnt;
+
+ if (bid >= ipbcfg.ln) {
+ printk(KERN_ERR "mbx: BKSND with illegal bid! %d\n", bid);
+ return;
+ }
+ ipb_bsycnt_dec(&ipbcfg);
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbx: BKSND with illegal tid! %d\n", tid);
+ goto unuse_ipbuf_out;
+ }
+ if (sndtyp_wd(task->ttyp)) {
+ printk(KERN_ERR
+ "mbx: BKSND from word sending task! (task%d)\n", tid);
+ goto unuse_ipbuf_out;
+ }
+ if (sndtyp_pvt(task->ttyp)) {
+ printk(KERN_ERR
+ "mbx: BKSND from private sending task! (task%d)\n", tid);
+ goto unuse_ipbuf_out;
+ }
+ if (sync_with_dsp(&ipbuf[bid]->sd, tid, 10) < 0) {
+ printk(KERN_ERR "mbx: BKSND - IPBUF sync failed!\n");
+ return;
+ }
+
+ /* should be done in DSP, but just in case. */
+ ipbuf[bid]->next = OMAP_DSP_BID_NULL;
+
+ cnt = ipbuf[bid]->c;
+ if (cnt > ipbcfg.lsz) {
+ printk(KERN_ERR "mbx: 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(bid);
+ goto done;
+ }
+ spin_lock(&task->rcvdt.bk.link.lock);
+ ipblink_add_tail(&task->rcvdt.bk.link, bid, ipbuf);
+ spin_unlock(&task->rcvdt.bk.link.lock);
+ /* 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(bid);
+ return;
+}
+
+void mbx1_bkreq(struct mbcmd *mb)
+{
+ unsigned char tid = mb->cmd_l;
+ unsigned short cnt = mb->data;
+ struct dsptask *task = dsptask[tid];
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbx: BKREQ with illegal tid! %d\n", tid);
+ return;
+ }
+ if (rcvtyp_wd(task->ttyp)) {
+ printk(KERN_ERR
+ "mbx: BKREQ from word receiving task! (task%d)\n", tid);
+ return;
+ }
+ if (rcvtyp_pvt(task->ttyp)) {
+ printk(KERN_ERR
+ "mbx: BKREQ from private receiving task! (task%d)\n",
+ tid);
+ return;
+ }
+ if (rcvtyp_psv(task->ttyp)) {
+ printk(KERN_ERR
+ "mbx: BKREQ from passive receiving task! (task%d)\n",
+ tid);
+ return;
+ }
+
+ spin_lock(&task->wsz_lock);
+ task->wsz = cnt*2;
+ spin_unlock(&task->wsz_lock);
+ wake_up_interruptible(&task->dev->write_wait_q);
+}
+
+void mbx1_bkyld(struct mbcmd *mb)
+{
+ unsigned short bid = mb->data;
+
+ if (bid >= ipbcfg.ln) {
+ printk(KERN_ERR "mbx: BKYLD with illegal bid! %d\n", bid);
+ return;
+ }
+
+ /* should be done in DSP, but just in case. */
+ ipbuf[bid]->next = OMAP_DSP_BID_NULL;
+
+ /* we don't need to sync with DSP */
+ ipb_bsycnt_dec(&ipbcfg);
+ release_ipbuf(bid);
+}
+
+void mbx1_bksndp(struct mbcmd *mb)
+{
+ unsigned char tid = mb->cmd_l;
+ struct dsptask *task = dsptask[tid];
+ struct rcvdt_bk_struct *rcvdt = &task->rcvdt.bk;
+ struct ipbuf_p *ipbp = rcvdt->ipbuf_pvt_r;
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbx: BKSNDP with illegal tid! %d\n", tid);
+ return;
+ }
+ if (sndtyp_wd(task->ttyp)) {
+ printk(KERN_ERR
+ "mbx: BKSNDP from word sending task! (task%d)\n", tid);
+ return;
+ }
+ if (sndtyp_gbl(task->ttyp)) {
+ printk(KERN_ERR
+ "mbx: 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.
+ */
+
+ if (sync_with_dsp(&ipbp->s, tid, 10) < 0) {
+ printk(KERN_ERR "mbx: BKSNDP - IPBUF sync failed!\n");
+ return;
+ }
+ printk(KERN_DEBUG "mbx: ipbuf_pvt_r->a = 0x%08lx\n",
+ MKLONG(ipbp->ah, ipbp->al));
+ spin_lock(&rcvdt->link.lock);
+ ipblink_add_pvt(&rcvdt->link);
+ spin_unlock(&rcvdt->link.lock);
+ wake_up_interruptible(&task->dev->read_wait_q);
+}
+
+void mbx1_bkreqp(struct mbcmd *mb)
+{
+ unsigned char tid = mb->cmd_l;
+ struct dsptask *task = dsptask[tid];
+ struct ipbuf_p *ipbp = task->ipbuf_pvt_w;
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbx: BKREQP with illegal tid! %d\n", tid);
+ return;
+ }
+ if (rcvtyp_wd(task->ttyp)) {
+ printk(KERN_ERR
+ "mbx: BKREQP from word receiving task! (task%d)\n", tid);
+ return;
+ }
+ if (rcvtyp_gbl(task->ttyp)) {
+ printk(KERN_ERR
+ "mbx: BKREQP from non-private receiving task! (task%d)\n", tid);
+ return;
+ }
+ if (rcvtyp_psv(task->ttyp)) {
+ printk(KERN_ERR
+ "mbx: BKREQP from passive receiving task! (task%d)\n", tid);
+ return;
+ }
+
+ if (sync_with_dsp(&ipbp->s, OMAP_DSP_TID_FREE, 10) < 0) {
+ printk(KERN_ERR "mbx: BKREQP - IPBUF sync failed!\n");
+ return;
+ }
+ printk(KERN_DEBUG "mbx: ipbuf_pvt_w->a = 0x%08lx\n",
+ MKLONG(ipbp->ah, ipbp->al));
+ spin_lock(&task->wsz_lock);
+ task->wsz = ipbp->c*2;
+ spin_unlock(&task->wsz_lock);
+ wake_up_interruptible(&task->dev->write_wait_q);
+}
+
+void mbx1_tctl(struct mbcmd *mb)
+{
+ unsigned char tid = mb->cmd_l;
+ struct dsptask *task = dsptask[tid];
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbx: TCTL with illegal tid! %d\n", tid);
+ return;
+ }
+
+ if (!waitqueue_active(&task->dev->ioctl_wait_q)) {
+ printk(KERN_WARNING "mbx: unexpected TCTL from DSP!\n");
+ return;
+ }
+
+ task->tctl_stat = mb->data;
+ wake_up_interruptible(&task->dev->ioctl_wait_q);
+}
+
+void mbx1_tcfg(struct mbcmd *mb)
+{
+ unsigned char tid = mb->cmd_l;
+ struct dsptask *task = dsptask[tid];
+ unsigned short *tnm;
+ volatile unsigned short *buf;
+ int i;
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbx: TCFG with illegal tid! %d\n", tid);
+ return;
+ }
+ if ((task->state != TASK_STATE_CFGREQ) || (cfg_cmd != MBCMD(TCFG))) {
+ printk(KERN_WARNING "mbx: unexpected TCFG from DSP!\n");
+ return;
+ }
+
+ if (sync_with_dsp(&ipbuf_sys_da->s, tid, 10) < 0) {
+ printk(KERN_ERR "mbx: TCFG - IPBUF sync failed!\n");
+ goto out;
+ }
+
+ /*
+ * read configuration data on system IPBUF
+ */
+ buf = ipbuf_sys_da->d;
+ task->ttyp = buf[0];
+ task->rcvdt.bk.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);
+
+ /*
+ * copy task name string
+ */
+ if (dsp_address_validate(tnm, OMAP_DSP_TNM_LEN, "task name buffer") <0) {
+ task->name[0] = '\0';
+ goto out;
+ }
+
+ for (i = 0; i < OMAP_DSP_TNM_LEN-1; i++) {
+ /* avoiding byte access */
+ unsigned short tmp = tnm[i];
+ task->name[i] = tmp & 0x00ff;
+ if (!tmp)
+ break;
+ }
+ task->name[OMAP_DSP_TNM_LEN-1] = '\0';
+
+ task->state = TASK_STATE_READY;
+out:
+ wake_up_interruptible(&cfg_wait_q);
+}
+
+void mbx1_tadd(struct mbcmd *mb)
+{
+ unsigned char tid = mb->cmd_l;
+
+ if ((!waitqueue_active(&cfg_wait_q)) || (cfg_cmd != MBCMD(TADD))) {
+ printk(KERN_WARNING "mbx: unexpected TADD from DSP!\n");
+ return;
+ }
+ cfg_tid = tid;
+ wake_up_interruptible(&cfg_wait_q);
+}
+
+void mbx1_tdel(struct mbcmd *mb)
+{
+ unsigned char tid = mb->cmd_l;
+
+ if ((!waitqueue_active(&cfg_wait_q)) || (cfg_cmd != MBCMD(TDEL))) {
+ printk(KERN_WARNING "mbx: unexpected TDEL from DSP!\n");
+ return;
+ }
+ cfg_tid = tid;
+ wake_up_interruptible(&cfg_wait_q);
+}
+
+void mbx1_err_fatal(unsigned char tid)
+{
+ struct dsptask *task = dsptask[tid];
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbx: FATAL ERR with illegal tid! %d\n", tid);
+ return;
+ }
+
+ spin_lock(&task->dev->state_lock);
+ proclist_send_sigbus(&task->dev->proc_list);
+ spin_unlock(&task->dev->state_lock);
+}
+
+static short *dbg_buf;
+static unsigned short dbg_buf_sz, dbg_line_sz;
+static int dbg_rp;
+
+int dsp_dbg_config(short *buf, unsigned short sz, unsigned short lsz)
+{
+#ifdef OLD_BINARY_SUPPORT
+ if ((mbx_revision == MBREV_3_0) || (mbx_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 mbx1_dbg_old(struct mbcmd *mb);
+#endif
+
+void mbx1_dbg(struct mbcmd *mb)
+{
+ unsigned char tid = mb->cmd_l;
+ int cnt = mb->data;
+ char s[80], *s_end = &s[79], *p;
+ unsigned short *src;
+ int i;
+
+#ifdef OLD_BINARY_SUPPORT
+ if ((mbx_revision == MBREV_3_0) || (mbx_revision == MBREV_3_2)) {
+ mbx1_dbg_old(mb);
+ return;
+ }
+#endif
+
+ if (((tid >= TASKDEV_MAX) || (dsptask[tid] == NULL)) &&
+ (tid != OMAP_DSP_TID_ANON)) {
+ printk(KERN_ERR "mbx: DBG with illegal tid! %d\n", tid);
+ return;
+ }
+ if (dbg_buf == NULL) {
+ printk(KERN_ERR "mbx: 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++) {
+ unsigned short tmp;
+ /*
+ * Be carefull that dbg_buf should not be read with
+ * 1-byte access since it might be placed in DARAM/SARAM
+ * and it can cause unexpected byteswap.
+ * For example,
+ * *(p++) = *(src++) & 0xff;
+ * causes 1-byte access!
+ */
+ tmp = *src++;
+ *(p++) = tmp & 0xff;
+ if (*(p-1) == '\n') {
+ *p = '\0';
+ printk(KERN_INFO "%s", s);
+ p = s;
+ continue;
+ }
+ if (p == s_end) {
+ *p = '\0';
+ printk(KERN_INFO "%s\n", s);
+ p = s;
+ continue;
+ }
+ }
+ if (p > s) {
+ *p = '\0';
+ printk(KERN_INFO "%s\n", s);
+ }
+ if ((dbg_rp += cnt + 1) > dbg_buf_sz - dbg_line_sz)
+ dbg_rp = 0;
+
+ dsp_mem_disable(dbg_buf);
+}
+
+#ifdef OLD_BINARY_SUPPORT
+static void mbx1_dbg_old(struct mbcmd *mb)
+{
+ unsigned char tid = mb->cmd_l;
+ char s[80], *s_end = &s[79], *p;
+ unsigned short *src;
+ volatile unsigned short *buf;
+ int cnt;
+ int i;
+
+ if (((tid >= TASKDEV_MAX) || (dsptask[tid] == NULL)) &&
+ (tid != OMAP_DSP_TID_ANON)) {
+ printk(KERN_ERR "mbx: DBG with illegal tid! %d\n", tid);
+ return;
+ }
+ if (sync_with_dsp(&ipbuf_sys_da->s, tid, 10) < 0) {
+ printk(KERN_ERR "mbx: DBG - IPBUF sync failed!\n");
+ return;
+ }
+ buf = ipbuf_sys_da->d;
+ cnt = buf[0];
+ src = MKVIRT(buf[1], buf[2]);
+ if (dsp_address_validate(src, cnt, "dbg buffer") < 0)
+ return;
+
+ if (dsp_mem_enable(src) < 0)
+ return;
+
+ p = s;
+ for (i = 0; i < cnt; i++) {
+ unsigned short tmp;
+ /*
+ * Be carefull that ipbuf should not be read with
+ * 1-byte access since it might be placed in DARAM/SARAM
+ * and it can cause unexpected byteswap.
+ * For example,
+ * *(p++) = *(src++) & 0xff;
+ * causes 1-byte access!
+ */
+ tmp = *src++;
+ *(p++) = tmp & 0xff;
+ if (*(p-1) == '\n') {
+ *p = '\0';
+ printk(KERN_INFO "%s", s);
+ p = s;
+ continue;
+ }
+ if (p == s_end) {
+ *p = '\0';
+ printk(KERN_INFO "%s\n", s);
+ p = s;
+ continue;
+ }
+ }
+ if (p > s) {
+ *p = '\0';
+ printk(KERN_INFO "%s\n", s);
+ }
+
+ release_ipbuf_pvt(ipbuf_sys_da);
+ dsp_mem_disable(src);
+}
+#endif /* OLD_BINARY_SUPPORT */
+
+/*
+ * sysfs files
+ */
+static ssize_t devname_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct taskdev *dev = to_taskdev(d);
+ return sprintf(buf, "%s\n", dev->name);
+}
+
+static ssize_t devstate_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct taskdev *dev = to_taskdev(d);
+ return sprintf(buf, "%s\n", devstate_name(dev->state));
+}
+
+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->state_lock);
+ list_for_each_entry(pl, &dev->proc_list, list_head) {
+ len += sprintf(buf + len, "%d\n", pl->pid);
+ }
+ spin_unlock(&dev->state_lock);
+
+ return len;
+}
+
+static ssize_t taskname_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct taskdev *dev = to_taskdev(d);
+ int len;
+
+ len = sprintf(buf, "%s\n", dev->task->name);
+
+ return len;
+}
+
+static ssize_t ttyp_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ unsigned short ttyp = to_taskdev(d)->task->ttyp;
+ int len = 0;
+
+ 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");
+
+ return len;
+}
+
+static ssize_t fifosz_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct fifo_struct *fifo = &to_taskdev(d)->task->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 dsptask *task = to_taskdev(d)->task;
+ unsigned long fifosz;
+ int ret;
+
+ fifosz = simple_strtol(buf, NULL, 10);
+ ret = dsp_task_set_fifosz(task, fifosz);
+
+ return (ret < 0) ? ret : strlen(buf);
+}
+
+static ssize_t fifocnt_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct fifo_struct *fifo = &to_taskdev(d)->task->rcvdt.fifo;
+ return sprintf(buf, "%d\n", fifo->cnt);
+}
+
+static __inline__ char *bid_name(unsigned short bid)
+{
+ static char s[6];
+
+ switch (bid) {
+ case OMAP_DSP_BID_NULL:
+ return "NULL";
+ case OMAP_DSP_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)->task->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;
+}
+
+static ssize_t wsz_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", to_taskdev(d)->task->wsz);
+}
+
+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_read_proc()
+ */
+int ipbuf_is_held(unsigned char tid, unsigned short bid)
+{
+ struct dsptask *task = dsptask[tid];
+ unsigned short b;
+ int ret = 0;
+
+ if (task == NULL)
+ return 0;
+
+ spin_lock(&task->rcvdt.bk.link.lock);
+ ipblink_for_each(b, &task->rcvdt.bk.link, ipbuf) {
+ if (b == bid) { /* found */
+ ret = 1;
+ break;
+ }
+ }
+ spin_unlock(&task->rcvdt.bk.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;
+ }
+
+ bus_register(&dsptask_bus);
+ retval = driver_register(&dsptask_driver);
+ if (retval) {
+ printk(KERN_ERR
+ "omapdsp: failed to register DSP task driver: %d\n",
+ retval);
+ bus_unregister(&dsptask_bus);
+ unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
+ return -EINVAL;
+ }
+ dsp_task_class = class_create(THIS_MODULE, "dsptask");
+
+ return 0;
+}
+
+void dsp_taskmod_exit(void)
+{
+ class_destroy(dsp_task_class);
+ driver_unregister(&dsptask_driver);
+ bus_unregister(&dsptask_bus);
+ unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
+}
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap/dsp/taskwatch.c
+ *
+ * OMAP DSP task watch device driver
+ *
+ * Copyright (C) 2002-2005 Nokia Corporation
+ *
+ * Written by 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 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
+ *
+ * 200%/05/16: DSP Gateway version 3.3
+ */
+
+#include <linux/module.h>
+#include <linux/major.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/arch/dsp.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 *buf, size_t count,
+ loff_t *ppos)
+{
+ long taskstat[TASKDEV_MAX];
+ int devcount = count / sizeof(long);
+ int i;
+
+ if (!dsp_is_ready()) {
+ printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
+ return -EINVAL;
+ }
+
+ if (change_cnt == 0) {
+ long current_state;
+ DECLARE_WAITQUEUE(wait, current);
+
+ add_wait_queue(&read_wait_q, &wait);
+ current_state = current->state;
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (change_cnt == 0) /* last check */
+ schedule();
+ set_current_state(current_state);
+ remove_wait_queue(&read_wait_q, &wait);
+
+ /* unconfigured while waiting ;-( */
+ if (dsp_is_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)
+{
+ static DECLARE_MUTEX(ioctl_sem);
+ int ret;
+
+ if (down_interruptible(&ioctl_sem))
+ return -ERESTARTSYS;
+
+ switch (cmd) {
+ case OMAP_DSP_TWCH_IOCTL_MKDEV:
+ {
+ char name[OMAP_DSP_TNM_LEN];
+ if (copy_from_user(name, (void *)arg, OMAP_DSP_TNM_LEN)) {
+ ret = -EFAULT;
+ goto up_out;
+ }
+ name[OMAP_DSP_TNM_LEN-1] = '\0';
+ ret = dsp_mkdev(name);
+ break;
+ }
+
+ case OMAP_DSP_TWCH_IOCTL_RMDEV:
+ {
+ char name[OMAP_DSP_TNM_LEN];
+ if (copy_from_user(name, (void *)arg, OMAP_DSP_TNM_LEN)) {
+ ret = -EFAULT;
+ goto up_out;
+ }
+ name[OMAP_DSP_TNM_LEN-1] = '\0';
+ ret = dsp_rmdev(name);
+ break;
+ }
+
+ case OMAP_DSP_TWCH_IOCTL_TADD:
+ {
+ struct omap_dsp_taddinfo ti;
+ if (copy_from_user(&ti, (void *)arg, sizeof(ti))) {
+ ret = -EFAULT;
+ goto up_out;
+ }
+ ret = dsp_tadd(ti.minor, ti.taskadr);
+ break;
+ }
+
+ case OMAP_DSP_TWCH_IOCTL_TDEL:
+ ret = dsp_tdel(arg);
+ break;
+
+ case OMAP_DSP_TWCH_IOCTL_TKILL:
+ ret = dsp_tkill(arg);
+ break;
+
+ default:
+ ret = -ENOIOCTLCMD;
+ }
+
+up_out:
+ up(&ioctl_sem);
+ 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);
+}
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap/dsp/uaccess_dsp.S
+ *
+ * user memory access functions for DSP driver
+ *
+ * Copyright (C) 2004,2005 Nokia Corporation
+ *
+ * Written by 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 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
+ *
+ * 2004/06/29: DSP Gateway version 3.3
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+ .text
+
+/* Prototype: int __arch_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 __arch_copy_to_user()
+ * in OMAP architecture.
+ * Params : to - user memory
+ * : from - kernel(DSP) memory
+ * Returns : success = 0, failure = 2
+ */
+
+ENTRY(__arch_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
+ LOADREGS(fd,sp!,{r4, pc})
+
+ .section .fixup,"ax"
+ .align 0
+9001: mov r0, #2
+ LOADREGS(fd,sp!, {r4, pc})
+ .previous
+
+/* Prototype: unsigned long __arch_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 __arch_copy_to_user()
+ * in OMAP architecture.
+ * Params : to - kernel (DSP) memory
+ * : from - user memory
+ * Returns : success = 0, failure = 2
+ */
+
+ENTRY(__arch_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
+ LOADREGS(fd,sp!,{r4, pc})
+
+ .section .fixup,"ax"
+ .align 0
+9001: mov r3, #0
+ strh r3, [r0], #2
+ mov r0, #2
+ LOADREGS(fd,sp!, {r4, pc})
+ .previous
--- /dev/null
+/*
+ * linux/arch/arm/mach-omap/dsp/uaccess_dsp.h
+ *
+ * Header for user access functions for DSP driver
+ *
+ * Copyright (C) 2002-2005 Nokia Corporation
+ *
+ * Modified from linux/include/asm-arm/uaccess.h
+ * by 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 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
+ *
+ * 2004/06/29: DSP Gateway version 3.3
+ */
+
+#ifndef _OMAP_DSP_UACCESS_DSP_H
+#define _OMAP_DSP_UACCESS_DSP_H
+
+#include <asm/uaccess.h>
+
+#define HAVE_ASM_COPY_FROM_USER_DSP_2B
+
+#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
+extern unsigned long __arch_copy_from_user_dsp_2b(void *to,
+ const void __user *from);
+extern unsigned long __arch_copy_to_user_dsp_2b(void __user *to,
+ const void *from);
+#endif
+
+extern unsigned long dspmem_base, dspmem_size;
+#define is_dsp_internal_mem(va) \
+ (((unsigned long)(va) >= dspmem_base) && \
+ ((unsigned long)(va) < dspmem_base + dspmem_size))
+
+
+#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 (__arch_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 (__arch_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 = __arch_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 (__arch_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 = __arch_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 __arch_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 (__arch_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 = __arch_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 (__arch_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 = __arch_copy_to_user(to, from, n);
+ }
+ }
+ return n;
+}
+
+#undef is_dsp_internal_mem
+
+#endif /* _OMAP_DSP_UACCESS_DSP_H */
--- /dev/null
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/bootmem.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/sram.h>
+#include <asm/arch/omapfb.h>
+
+#if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE)
+
+static struct omapfb_platform_data omapfb_config;
+
+static u64 omap_fb_dma_mask = ~(u32)0;
+
+/* in devices.c */
+extern void omap_nop_release(struct device *dev);
+
+static struct platform_device omap_fb_device = {
+ .name = "omapfb",
+ .id = -1,
+ .dev = {
+ .release = omap_nop_release,
+ .dma_mask = &omap_fb_dma_mask,
+ .coherent_dma_mask = ~(u32)0,
+ .platform_data = &omapfb_config,
+ },
+ .num_resources = 0,
+};
+
+/* called from map_io */
+void omapfb_reserve_mem(void)
+{
+ const struct omap_fbmem_config *fbmem_conf;
+
+ omapfb_config.fbmem.fb_sram_start = omap_fb_sram_start;
+ omapfb_config.fbmem.fb_sram_size = omap_fb_sram_size;
+
+ fbmem_conf = omap_get_config(OMAP_TAG_FBMEM, struct omap_fbmem_config);
+
+ if (fbmem_conf != NULL) {
+ /* indicate that the bootloader already initialized the
+ * fb device, so we'll skip that part in the fb driver
+ */
+ omapfb_config.fbmem.fb_sdram_start = fbmem_conf->fb_sdram_start;
+ omapfb_config.fbmem.fb_sdram_size = fbmem_conf->fb_sdram_size;
+ if (fbmem_conf->fb_sdram_size) {
+ pr_info("Reserving %u bytes SDRAM for frame buffer\n",
+ fbmem_conf->fb_sdram_size);
+ reserve_bootmem(fbmem_conf->fb_sdram_start,
+ fbmem_conf->fb_sdram_size);
+ }
+ }
+}
+
+static inline int omap_init_fb(void)
+{
+ const struct omap_lcd_config *conf;
+
+ conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
+ if (conf == NULL)
+ return 0;
+
+ omapfb_config.lcd = *conf;
+
+ return platform_device_register(&omap_fb_device);
+}
+
+arch_initcall(omap_init_fb);
+
+#else
+
+void omapfb_reserve_mem(void) {}
+
+#endif
+
+
--- /dev/null
+/*
+ * linux/arch/arm/plat-omap/gpio-switch.c
+ *
+ * Copyright (C) 2004, 2005 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/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>
+
+struct gpio_switch {
+ char name[14];
+ u16 gpio;
+ int flags;
+ int type;
+ int state;
+
+ 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 device_driver gpio_sw_driver;
+
+static const char *cover_str[2] = { "open", "closed" };
+static const char *connection_str[2] = { "disconnected", "connected" };
+
+/*
+ * GPIO switch state poll delay in ms
+ */
+#define OMAP_GPIO_SW_POLL_DELAY 10
+
+static void print_sw_state(struct gpio_switch *sw, int state)
+{
+ const char **str;
+
+ switch (sw->type) {
+ case OMAP_GPIO_SWITCH_TYPE_COVER:
+ str = cover_str;
+ break;
+ case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
+ str = connection_str;
+ break;
+ default:
+ str = NULL;
+ }
+ 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_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct gpio_switch *sw = dev_get_drvdata(dev);
+ int enable = (int)simple_strtoul(buf, NULL, 10);
+ omap_set_gpio_dataout(sw->gpio, enable);
+ return count;
+}
+
+#define gpio_sw_switch_attr(name) \
+static ssize_t gpio_sw_show_##name(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct gpio_switch *sw = dev_get_drvdata(dev); \
+ return sprintf(buf, "%s\n", name##_str[gpio_sw_get_state(sw)]); \
+} \
+static DEVICE_ATTR(name##_switch, S_IRUGO | S_IWUSR, \
+ gpio_sw_show_##name, gpio_sw_store)
+
+gpio_sw_switch_attr(cover);
+gpio_sw_switch_attr(connection);
+
+static irqreturn_t gpio_sw_irq_handler(int irq, void *arg, struct pt_regs *regs)
+{
+ struct gpio_switch *sw = arg;
+
+ mod_timer(&sw->timer, jiffies + OMAP_GPIO_SW_POLL_DELAY / (1000 / HZ));
+
+ 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(void *data)
+{
+ struct gpio_switch *sw = data;
+ int state = gpio_sw_get_state(sw);
+
+ if (sw->state == state)
+ return;
+
+ if (sw->type == OMAP_GPIO_SWITCH_TYPE_CONNECTION)
+ kobject_uevent(&sw->pdev.dev.kobj, KOBJ_CHANGE);
+ else
+ kobject_uevent(&sw->pdev.dev.kobj, KOBJ_CHANGE);
+ sw->state = state;
+ 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);
+ print_sw_state(sw, state);
+}
+
+static int __init new_switch(struct gpio_switch *sw)
+{
+ int r, direction, trigger;
+
+ 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;
+
+ r = platform_device_register(&sw->pdev);
+ if (r)
+ 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);
+
+ switch (sw->type) {
+ case OMAP_GPIO_SWITCH_TYPE_COVER:
+ device_create_file(&sw->pdev.dev, &dev_attr_cover_switch);
+ break;
+ case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
+ device_create_file(&sw->pdev.dev, &dev_attr_connection_switch);
+ break;
+ }
+
+ list_add(&sw->node, &gpio_switches);
+
+ if (!direction)
+ return 0;
+
+ if (omap_get_gpio_datain(sw->gpio))
+ trigger = SA_TRIGGER_FALLING;
+ else
+ trigger = SA_TRIGGER_RISING;
+ r = request_irq(OMAP_GPIO_IRQ(sw->gpio), gpio_sw_irq_handler,
+ SA_SHIRQ | 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, sw);
+ init_timer(&sw->timer);
+
+ sw->timer.function = gpio_sw_timer;
+ sw->timer.data = (unsigned long)sw;
+
+ 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 = kmalloc(sizeof(*sw), GFP_KERNEL);
+ if (sw == NULL) {
+ printk(KERN_ERR "gpio-switch: kmalloc failed\n");
+ return -ENOMEM;
+ }
+ memset(sw, 0, sizeof(*sw));
+ strncpy(sw->name, cfg->name, sizeof(cfg->name));
+ sw->gpio = cfg->gpio;
+ sw->flags = cfg->flags;
+ sw->type = cfg->type;
+ sw->state = gpio_sw_get_state(sw);
+ 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) {
+ kfree(old);
+
+ flush_scheduled_work();
+ del_timer_sync(&sw->timer);
+
+ free_irq(OMAP_GPIO_IRQ(sw->gpio), sw);
+
+ if (sw->type == OMAP_GPIO_SWITCH_TYPE_CONNECTION)
+ device_remove_file(&sw->pdev.dev,
+ &dev_attr_connection_switch);
+ else
+ device_remove_file(&sw->pdev.dev,
+ &dev_attr_cover_switch);
+
+ platform_device_unregister(&sw->pdev);
+ omap_free_gpio(sw->gpio);
+ old = sw;
+ }
+
+ kfree(sw);
+}
+
+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;
+ print_sw_state(sw, state);
+ }
+}
+
+static void gpio_sw_shutdown(struct device *dev)
+{
+}
+
+static struct device_driver gpio_sw_driver = {
+ .name = "gpio-switch",
+ .bus = &platform_bus_type,
+ .shutdown = gpio_sw_shutdown,
+};
+
+static int __init gpio_sw_init(void)
+{
+ int r;
+
+ printk(KERN_INFO "OMAP GPIO switch handler initializing\n");
+
+ r = 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)) {
+ driver_unregister(&gpio_sw_driver);
+ return PTR_ERR(gpio_sw_platform_dev);
+ }
+
+ r = add_atag_switches();
+ if (r < 0) {
+ platform_device_unregister(gpio_sw_platform_dev);
+ driver_unregister(&gpio_sw_driver);
+ gpio_sw_cleanup();
+ return r;
+ }
+
+ report_initial_state();
+
+ return 0;
+}
+
+static void __exit gpio_sw_exit(void)
+{
+ gpio_sw_cleanup();
+ platform_device_unregister(gpio_sw_platform_dev);
+ 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");
static inline struct gpio_bank *get_gpio_bank(int gpio)
{
#ifdef CONFIG_ARCH_OMAP15XX
- if (cpu_is_omap1510()) {
+ if (cpu_is_omap15xx()) {
if (OMAP_GPIO_IS_MPUIO(gpio))
return &gpio_bank[0];
return &gpio_bank[1];
return 0;
}
#ifdef CONFIG_ARCH_OMAP15XX
- if (cpu_is_omap1510() && gpio < 16)
+ if (cpu_is_omap15xx() && gpio < 16)
return 0;
#endif
#if defined(CONFIG_ARCH_OMAP16XX)
u32 gpio_bit = 1 << gpio;
MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT0, gpio_bit,
- trigger & IRQT_LOW);
+ trigger & __IRQT_LOWLVL);
MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT1, gpio_bit,
- trigger & IRQT_HIGH);
+ trigger & __IRQT_HIGHLVL);
MOD_REG_BIT(OMAP24XX_GPIO_RISINGDETECT, gpio_bit,
- trigger & IRQT_RISING);
+ trigger & __IRQT_RISEDGE);
MOD_REG_BIT(OMAP24XX_GPIO_FALLINGDETECT, gpio_bit,
- trigger & IRQT_FALLING);
+ trigger & __IRQT_FALEDGE);
/* FIXME: Possibly do 'set_irq_handler(j, do_level_IRQ)' if only level
* triggering requested. */
}
case METHOD_MPUIO:
reg += OMAP_MPUIO_GPIO_INT_EDGE;
l = __raw_readl(reg);
- if (trigger == IRQT_RISING)
+ if (trigger & __IRQT_RISEDGE)
l |= 1 << gpio;
- else if (trigger == IRQT_FALLING)
+ else if (trigger & __IRQT_FALEDGE)
l &= ~(1 << gpio);
else
goto bad;
case METHOD_GPIO_1510:
reg += OMAP1510_GPIO_INT_CONTROL;
l = __raw_readl(reg);
- if (trigger == IRQT_RISING)
+ if (trigger & __IRQT_RISEDGE)
l |= 1 << gpio;
- else if (trigger == IRQT_FALLING)
+ else if (trigger & __IRQT_FALEDGE)
l &= ~(1 << gpio);
else
goto bad;
reg += OMAP1610_GPIO_EDGE_CTRL1;
gpio &= 0x07;
/* We allow only edge triggering, i.e. two lowest bits */
- if (trigger & ~IRQT_BOTHEDGE)
+ if (trigger & (__IRQT_LOWLVL | __IRQT_HIGHLVL))
BUG();
- /* NOTE: knows __IRQT_{FAL,RIS}EDGE match OMAP hardware */
- trigger &= 0x03;
l = __raw_readl(reg);
l &= ~(3 << (gpio << 1));
- l |= trigger << (gpio << 1);
+ if (trigger & __IRQT_RISEDGE)
+ l |= 2 << (gpio << 1);
+ if (trigger & __IRQT_FALEDGE)
+ l |= 1 << (gpio << 1);
break;
case METHOD_GPIO_730:
reg += OMAP730_GPIO_INT_CONTROL;
l = __raw_readl(reg);
- if (trigger == IRQT_RISING)
+ if (trigger & __IRQT_RISEDGE)
l |= 1 << gpio;
- else if (trigger == IRQT_FALLING)
+ else if (trigger & __IRQT_FALEDGE)
l &= ~(1 << gpio);
else
goto bad;
if (check_gpio(gpio) < 0)
return -EINVAL;
- if (type & (__IRQT_LOWLVL|__IRQT_HIGHLVL|IRQT_PROBE))
+ if (type & IRQT_PROBE)
+ return -EINVAL;
+ if (!cpu_is_omap24xx() && (type & (__IRQT_LOWLVL|__IRQT_HIGHLVL)))
return -EINVAL;
bank = get_gpio_bank(gpio);
if (bank->method == METHOD_GPIO_24XX)
isr_reg = bank->base + OMAP24XX_GPIO_IRQSTATUS1;
#endif
-
while(1) {
- isr = __raw_readl(isr_reg);
- _enable_gpio_irqbank(bank, isr, 0);
- _clear_gpio_irqbank(bank, isr);
- _enable_gpio_irqbank(bank, isr, 1);
- desc->chip->unmask(irq);
+ u32 isr_saved, level_mask = 0;
+
+ isr_saved = isr = __raw_readl(isr_reg);
+
+ if (cpu_is_omap15xx() && (bank->method == METHOD_MPUIO))
+ isr &= 0x0000ffff;
+
+ if (cpu_is_omap24xx())
+ level_mask =
+ __raw_readl(bank->base +
+ OMAP24XX_GPIO_LEVELDETECT0) |
+ __raw_readl(bank->base +
+ OMAP24XX_GPIO_LEVELDETECT1);
+
+ /* clear edge sensitive interrupts before handler(s) are
+ called so that we don't miss any interrupt occurred while
+ executing them */
+ _enable_gpio_irqbank(bank, isr_saved & ~level_mask, 0);
+ _clear_gpio_irqbank(bank, isr_saved & ~level_mask);
+ _enable_gpio_irqbank(bank, isr_saved & ~level_mask, 1);
+
+ /* if there is only edge sensitive GPIO pin interrupts
+ configured, we could unmask GPIO bank interrupt immediately */
+ if (!level_mask)
+ desc->chip->unmask(irq);
if (!isr)
break;
d = irq_desc + gpio_irq;
desc_handle_irq(gpio_irq, d, regs);
}
+
+ if (cpu_is_omap24xx()) {
+ /* clear level sensitive interrupts after handler(s) */
+ _enable_gpio_irqbank(bank, isr_saved & level_mask, 0);
+ _clear_gpio_irqbank(bank, isr_saved & level_mask);
+ _enable_gpio_irqbank(bank, isr_saved & level_mask, 1);
+ }
+
+ /* if bank has any level sensitive GPIO pin interrupt
+ configured, we must unmask the bank interrupt only after
+ handler(s) are executed in order to avoid spurious bank
+ interrupt */
+ if (level_mask)
+ desc->chip->unmask(irq);
}
}
initialized = 1;
- if (cpu_is_omap1510()) {
+ if (cpu_is_omap15xx()) {
gpio_ick = clk_get(NULL, "arm_gpio_ck");
if (IS_ERR(gpio_ick))
printk("Could not get arm_gpio_ck\n");
}
#ifdef CONFIG_ARCH_OMAP15XX
- if (cpu_is_omap1510()) {
+ if (cpu_is_omap15xx()) {
printk(KERN_INFO "OMAP1510 GPIO hardware\n");
gpio_bank_count = 2;
gpio_bank = gpio_bank_1510;
#ifdef CONFIG_MCBSP_DEBUG
#define DBG(x...) printk(x)
#else
-#define DBG(x...) do { } while (0)
+#define DBG(x...) do { } while (0)
#endif
struct omap_mcbsp {
omap_mcbsp_word_length rx_word_length;
omap_mcbsp_word_length tx_word_length;
+ omap_mcbsp_io_type_t io_type; /* IRQ or poll */
/* IRQ based TX/RX */
int rx_irq;
int tx_irq;
};
static struct omap_mcbsp mcbsp[OMAP_MAX_MCBSP_COUNT];
+#ifdef CONFIG_ARCH_OMAP1
static struct clk *mcbsp_dsp_ck = 0;
static struct clk *mcbsp_api_ck = 0;
static struct clk *mcbsp_dspxor_ck = 0;
-
+#endif
+#ifdef CONFIG_ARCH_OMAP2
+static struct clk *mcbsp1_ick = 0;
+static struct clk *mcbsp1_fck = 0;
+static struct clk *mcbsp2_ick = 0;
+static struct clk *mcbsp2_fck = 0;
+static struct clk *sys_ck = 0;
+static struct clk *sys_clkout = 0;
+#endif
static void omap_mcbsp_dump_reg(u8 id)
{
DBG("***********************\n");
}
-
static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
{
struct omap_mcbsp * mcbsp_tx = (struct omap_mcbsp *)(dev_id);
return IRQ_HANDLED;
}
-
static void omap_mcbsp_tx_dma_callback(int lch, u16 ch_status, void *data)
{
struct omap_mcbsp * mcbsp_dma_tx = (struct omap_mcbsp *)(data);
return 0;
}
- if (cpu_is_omap1510() || cpu_is_omap16xx()) {
+ if (cpu_is_omap15xx() || cpu_is_omap16xx() || cpu_is_omap24xx()) {
if (id > OMAP_MAX_MCBSP_COUNT) {
printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1);
return -1;
return -1;
}
+#ifdef CONFIG_ARCH_OMAP1
static void omap_mcbsp_dsp_request(void)
{
- if (cpu_is_omap1510() || cpu_is_omap16xx()) {
+ if (cpu_is_omap15xx() || cpu_is_omap16xx()) {
+ omap_dsp_request_mem();
clk_enable(mcbsp_dsp_ck);
clk_enable(mcbsp_api_ck);
static void omap_mcbsp_dsp_free(void)
{
- if (cpu_is_omap1510() || cpu_is_omap16xx()) {
+ if (cpu_is_omap15xx() || cpu_is_omap16xx()) {
+ omap_dsp_release_mem();
clk_disable(mcbsp_dspxor_ck);
clk_disable(mcbsp_dsp_ck);
clk_disable(mcbsp_api_ck);
}
}
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2
+static void omap2_mcbsp2_mux_setup(void)
+{
+ omap_cfg_reg(Y15_24XX_MCBSP2_CLKX);
+ omap_cfg_reg(R14_24XX_MCBSP2_FSX);
+ omap_cfg_reg(W15_24XX_MCBSP2_DR);
+ omap_cfg_reg(V15_24XX_MCBSP2_DX);
+ omap_cfg_reg(V14_24XX_GPIO117);
+ omap_cfg_reg(W14_24XX_SYS_CLKOUT);
+}
+#endif
+
+/*
+ * We can choose between IRQ based or polled IO.
+ * This needs to be called before omap_mcbsp_request().
+ */
+int omap_mcbsp_set_io_type(unsigned int id, omap_mcbsp_io_type_t io_type)
+{
+ if (omap_mcbsp_check(id) < 0)
+ return -EINVAL;
+
+ spin_lock(&mcbsp[id].lock);
+
+ if (!mcbsp[id].free) {
+ printk (KERN_ERR "OMAP-McBSP: McBSP%d is currently in use\n", id + 1);
+ spin_unlock(&mcbsp[id].lock);
+ return -EINVAL;
+ }
+
+ mcbsp[id].io_type = io_type;
+
+ spin_unlock(&mcbsp[id].lock);
+
+ return 0;
+}
int omap_mcbsp_request(unsigned int id)
{
if (omap_mcbsp_check(id) < 0)
return -EINVAL;
+#ifdef CONFIG_ARCH_OMAP1
/*
* On 1510, 1610 and 1710, McBSP1 and McBSP3
* are DSP public peripherals.
*/
if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3)
omap_mcbsp_dsp_request();
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2
+ if (cpu_is_omap24xx()) {
+ if (id == OMAP_MCBSP1) {
+ clk_enable(mcbsp1_ick);
+ clk_enable(mcbsp1_fck);
+ } else {
+ clk_enable(mcbsp2_ick);
+ clk_enable(mcbsp2_fck);
+ }
+ }
+#endif
spin_lock(&mcbsp[id].lock);
if (!mcbsp[id].free) {
mcbsp[id].free = 0;
spin_unlock(&mcbsp[id].lock);
- /* We need to get IRQs here */
- err = request_irq(mcbsp[id].tx_irq, omap_mcbsp_tx_irq_handler, 0,
- "McBSP",
- (void *) (&mcbsp[id]));
- if (err != 0) {
- printk(KERN_ERR "OMAP-McBSP: Unable to request TX IRQ %d for McBSP%d\n",
- mcbsp[id].tx_irq, mcbsp[id].id);
- return err;
- }
-
- init_completion(&(mcbsp[id].tx_irq_completion));
-
-
- err = request_irq(mcbsp[id].rx_irq, omap_mcbsp_rx_irq_handler, 0,
- "McBSP",
- (void *) (&mcbsp[id]));
- if (err != 0) {
- printk(KERN_ERR "OMAP-McBSP: Unable to request RX IRQ %d for McBSP%d\n",
- mcbsp[id].rx_irq, mcbsp[id].id);
- free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id]));
- return err;
+ if (mcbsp[id].io_type == OMAP_MCBSP_IRQ_IO) {
+ /* We need to get IRQs here */
+ err = request_irq(mcbsp[id].tx_irq, omap_mcbsp_tx_irq_handler, 0,
+ "McBSP",
+ (void *) (&mcbsp[id]));
+ if (err != 0) {
+ printk(KERN_ERR "OMAP-McBSP: Unable to request TX IRQ %d for McBSP%d\n",
+ mcbsp[id].tx_irq, mcbsp[id].id);
+ return err;
+ }
+
+ init_completion(&(mcbsp[id].tx_irq_completion));
+
+
+ err = request_irq(mcbsp[id].rx_irq, omap_mcbsp_rx_irq_handler, 0,
+ "McBSP",
+ (void *) (&mcbsp[id]));
+ if (err != 0) {
+ printk(KERN_ERR "OMAP-McBSP: Unable to request RX IRQ %d for McBSP%d\n",
+ mcbsp[id].rx_irq, mcbsp[id].id);
+ free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id]));
+ return err;
+ }
+
+ init_completion(&(mcbsp[id].rx_irq_completion));
}
-
- init_completion(&(mcbsp[id].rx_irq_completion));
+
return 0;
}
if (omap_mcbsp_check(id) < 0)
return;
- if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3)
- omap_mcbsp_dsp_free();
+#ifdef CONFIG_ARCH_OMAP1
+ if (cpu_class_is_omap1()) {
+ if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3)
+ omap_mcbsp_dsp_free();
+ }
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2
+ if (cpu_is_omap24xx()) {
+ if (id == OMAP_MCBSP1) {
+ clk_disable(mcbsp1_ick);
+ clk_disable(mcbsp1_fck);
+ } else {
+ clk_disable(mcbsp2_ick);
+ clk_disable(mcbsp2_fck);
+ }
+ }
+#endif
spin_lock(&mcbsp[id].lock);
if (mcbsp[id].free) {
mcbsp[id].free = 1;
spin_unlock(&mcbsp[id].lock);
-
- /* Free IRQs */
- free_irq(mcbsp[id].rx_irq, (void *) (&mcbsp[id]));
- free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id]));
+
+ if (mcbsp[id].io_type == OMAP_MCBSP_IRQ_IO) {
+ /* Free IRQs */
+ free_irq(mcbsp[id].rx_irq, (void *) (&mcbsp[id]));
+ free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id]));
+ }
}
/*
}
+int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word)
+{
+ u32 io_base = mcbsp[id].io_base;
+ omap_mcbsp_word_length tx_word_length = mcbsp[id].tx_word_length;
+ omap_mcbsp_word_length rx_word_length = mcbsp[id].rx_word_length;
+ u16 spcr2, spcr1, attempts = 0, word_lsb, word_msb = 0;
+
+ if (tx_word_length != rx_word_length)
+ return -EINVAL;
+
+ /* First we wait for the transmitter to be ready */
+ spcr2 = OMAP_MCBSP_READ(io_base, SPCR2);
+ while (!(spcr2 & XRDY)) {
+ spcr2 = OMAP_MCBSP_READ(io_base, SPCR2);
+ if (attempts++ > 1000) {
+ /* We must reset the transmitter */
+ OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 & (~XRST));
+ udelay(10);
+ OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 | XRST);
+ udelay(10);
+ printk("McBSP transmitter not ready\n");
+ return -EAGAIN;
+ }
+ }
+
+ /* Now we can push the data */
+ if (tx_word_length > OMAP_MCBSP_WORD_16)
+ OMAP_MCBSP_WRITE(io_base, DXR2, word >> 16);
+ OMAP_MCBSP_WRITE(io_base, DXR1, word & 0xffff);
+
+ /* We wait for the receiver to be ready */
+ spcr1 = OMAP_MCBSP_READ(io_base, SPCR1);
+ while (!(spcr1 & RRDY)) {
+ spcr1 = OMAP_MCBSP_READ(io_base, SPCR1);
+ if (attempts++ > 1000) {
+ /* We must reset the receiver */
+ OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 & (~RRST));
+ udelay(10);
+ OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 | RRST);
+ udelay(10);
+ printk("McBSP receiver not ready\n");
+ return -EAGAIN;
+ }
+ }
+
+ /* Receiver is ready, let's read the dummy data */
+ if (rx_word_length > OMAP_MCBSP_WORD_16)
+ word_msb = OMAP_MCBSP_READ(io_base, DRR2);
+ word_lsb = OMAP_MCBSP_READ(io_base, DRR1);
+
+ return 0;
+}
+
+int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 * word)
+{
+ u32 io_base = mcbsp[id].io_base, clock_word = 0;
+ omap_mcbsp_word_length tx_word_length = mcbsp[id].tx_word_length;
+ omap_mcbsp_word_length rx_word_length = mcbsp[id].rx_word_length;
+ u16 spcr2, spcr1, attempts = 0, word_lsb, word_msb = 0;
+
+ if (tx_word_length != rx_word_length)
+ return -EINVAL;
+
+ /* First we wait for the transmitter to be ready */
+ spcr2 = OMAP_MCBSP_READ(io_base, SPCR2);
+ while (!(spcr2 & XRDY)) {
+ spcr2 = OMAP_MCBSP_READ(io_base, SPCR2);
+ if (attempts++ > 1000) {
+ /* We must reset the transmitter */
+ OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 & (~XRST));
+ udelay(10);
+ OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 | XRST);
+ udelay(10);
+ printk("McBSP transmitter not ready\n");
+ return -EAGAIN;
+ }
+ }
+
+ /* We first need to enable the bus clock */
+ if (tx_word_length > OMAP_MCBSP_WORD_16)
+ OMAP_MCBSP_WRITE(io_base, DXR2, clock_word >> 16);
+ OMAP_MCBSP_WRITE(io_base, DXR1, clock_word & 0xffff);
+
+ /* We wait for the receiver to be ready */
+ spcr1 = OMAP_MCBSP_READ(io_base, SPCR1);
+ while (!(spcr1 & RRDY)) {
+ spcr1 = OMAP_MCBSP_READ(io_base, SPCR1);
+ if (attempts++ > 1000) {
+ /* We must reset the receiver */
+ OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 & (~RRST));
+ udelay(10);
+ OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 | RRST);
+ udelay(10);
+ printk("McBSP receiver not ready\n");
+ return -EAGAIN;
+ }
+ }
+
+ /* Receiver is ready, there is something for us */
+ if (rx_word_length > OMAP_MCBSP_WORD_16)
+ word_msb = OMAP_MCBSP_READ(io_base, DRR2);
+ word_lsb = OMAP_MCBSP_READ(io_base, DRR1);
+
+ word[0] = (word_lsb | (word_msb << 16));
+
+ return 0;
+}
+
+
/*
* Simple DMA based buffer rx/tx routines.
* Nothing fancy, just a single buffer tx/rx through DMA.
int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int length)
{
int dma_tx_ch;
+ int src_port = 0;
+ int dest_port = 0;
+ int sync_dev = 0;
if (omap_mcbsp_check(id) < 0)
return -EINVAL;
init_completion(&(mcbsp[id].tx_dma_completion));
+ if (cpu_class_is_omap1()) {
+ src_port = OMAP_DMA_PORT_TIPB;
+ dest_port = OMAP_DMA_PORT_EMIFF;
+ }
+ if (cpu_is_omap24xx())
+ sync_dev = mcbsp[id].dma_tx_sync;
+
omap_set_dma_transfer_params(mcbsp[id].dma_tx_lch,
OMAP_DMA_DATA_TYPE_S16,
length >> 1, 1,
OMAP_DMA_SYNC_ELEMENT,
- 0, 0);
+ sync_dev, 0);
omap_set_dma_dest_params(mcbsp[id].dma_tx_lch,
- OMAP_DMA_PORT_TIPB,
+ src_port,
OMAP_DMA_AMODE_CONSTANT,
mcbsp[id].io_base + OMAP_MCBSP_REG_DXR1,
0, 0);
omap_set_dma_src_params(mcbsp[id].dma_tx_lch,
- OMAP_DMA_PORT_EMIFF,
+ dest_port,
OMAP_DMA_AMODE_POST_INC,
buffer,
0, 0);
int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int length)
{
int dma_rx_ch;
+ int src_port = 0;
+ int dest_port = 0;
+ int sync_dev = 0;
if (omap_mcbsp_check(id) < 0)
return -EINVAL;
init_completion(&(mcbsp[id].rx_dma_completion));
+ if (cpu_class_is_omap1()) {
+ src_port = OMAP_DMA_PORT_TIPB;
+ dest_port = OMAP_DMA_PORT_EMIFF;
+ }
+ if (cpu_is_omap24xx())
+ sync_dev = mcbsp[id].dma_rx_sync;
+
omap_set_dma_transfer_params(mcbsp[id].dma_rx_lch,
OMAP_DMA_DATA_TYPE_S16,
length >> 1, 1,
OMAP_DMA_SYNC_ELEMENT,
- 0, 0);
+ sync_dev, 0);
omap_set_dma_src_params(mcbsp[id].dma_rx_lch,
- OMAP_DMA_PORT_TIPB,
+ src_port,
OMAP_DMA_AMODE_CONSTANT,
mcbsp[id].io_base + OMAP_MCBSP_REG_DRR1,
0, 0);
omap_set_dma_dest_params(mcbsp[id].dma_rx_lch,
- OMAP_DMA_PORT_EMIFF,
+ dest_port,
OMAP_DMA_AMODE_POST_INC,
buffer,
0, 0);
};
#endif
+#if defined(CONFIG_ARCH_OMAP24XX)
+static const struct omap_mcbsp_info mcbsp_24xx[] = {
+ [0] = { .virt_base = IO_ADDRESS(OMAP24XX_MCBSP1_BASE),
+ .dma_rx_sync = OMAP24XX_DMA_MCBSP1_RX,
+ .dma_tx_sync = OMAP24XX_DMA_MCBSP1_TX,
+ .rx_irq = INT_24XX_MCBSP1_IRQ_RX,
+ .tx_irq = INT_24XX_MCBSP1_IRQ_TX,
+ },
+ [1] = { .virt_base = IO_ADDRESS(OMAP24XX_MCBSP2_BASE),
+ .dma_rx_sync = OMAP24XX_DMA_MCBSP2_RX,
+ .dma_tx_sync = OMAP24XX_DMA_MCBSP2_TX,
+ .rx_irq = INT_24XX_MCBSP2_IRQ_RX,
+ .tx_irq = INT_24XX_MCBSP2_IRQ_TX,
+ },
+};
+#endif
+
static int __init omap_mcbsp_init(void)
{
int mcbsp_count = 0, i;
printk("Initializing OMAP McBSP system\n");
+#ifdef CONFIG_ARCH_OMAP1
mcbsp_dsp_ck = clk_get(0, "dsp_ck");
if (IS_ERR(mcbsp_dsp_ck)) {
printk(KERN_ERR "mcbsp: could not acquire dsp_ck handle.\n");
printk(KERN_ERR "mcbsp: could not acquire dspxor_ck handle.\n");
return PTR_ERR(mcbsp_dspxor_ck);
}
+#endif
+#ifdef CONFIG_ARCH_OMAP2
+ mcbsp1_ick = clk_get(0, "mcbsp1_ick");
+ if (IS_ERR(mcbsp1_ick)) {
+ printk(KERN_ERR "mcbsp: could not acquire mcbsp1_ick handle.\n");
+ return PTR_ERR(mcbsp1_ick);
+ }
+ mcbsp1_fck = clk_get(0, "mcbsp1_fck");
+ if (IS_ERR(mcbsp1_fck)) {
+ printk(KERN_ERR "mcbsp: could not acquire mcbsp1_fck handle.\n");
+ return PTR_ERR(mcbsp1_fck);
+ }
+ mcbsp2_ick = clk_get(0, "mcbsp2_ick");
+ if (IS_ERR(mcbsp2_ick)) {
+ printk(KERN_ERR "mcbsp: could not acquire mcbsp2_ick handle.\n");
+ return PTR_ERR(mcbsp2_ick);
+ }
+ mcbsp2_fck = clk_get(0, "mcbsp2_fck");
+ if (IS_ERR(mcbsp2_fck)) {
+ printk(KERN_ERR "mcbsp: could not acquire mcbsp2_fck handle.\n");
+ return PTR_ERR(mcbsp2_fck);
+ }
+#endif
#ifdef CONFIG_ARCH_OMAP730
if (cpu_is_omap730()) {
}
#endif
#ifdef CONFIG_ARCH_OMAP15XX
- if (cpu_is_omap1510()) {
+ if (cpu_is_omap15xx()) {
mcbsp_info = mcbsp_1510;
mcbsp_count = ARRAY_SIZE(mcbsp_1510);
}
mcbsp_info = mcbsp_1610;
mcbsp_count = ARRAY_SIZE(mcbsp_1610);
}
+#endif
+#if defined(CONFIG_ARCH_OMAP24XX)
+ if (cpu_is_omap24xx()) {
+ mcbsp_info = mcbsp_24xx;
+ mcbsp_count = ARRAY_SIZE(mcbsp_24xx);
+
+ /* REVISIT: where's the right place? */
+ omap2_mcbsp2_mux_setup();
+ sys_ck = clk_get(0, "sys_ck");
+ sys_clkout = clk_get(0, "sys_clkout");
+ clk_set_parent(sys_clkout, sys_ck);
+ clk_enable(sys_clkout);
+ }
#endif
for (i = 0; i < OMAP_MAX_MCBSP_COUNT ; i++) {
if (i >= mcbsp_count) {
mcbsp[i].dma_rx_lch = -1;
mcbsp[i].io_base = mcbsp_info[i].virt_base;
+ mcbsp[i].io_type = OMAP_MCBSP_IRQ_IO; /* Default I/O is IRQ based */
mcbsp[i].tx_irq = mcbsp_info[i].tx_irq;
mcbsp[i].rx_irq = mcbsp_info[i].rx_irq;
mcbsp[i].dma_rx_sync = mcbsp_info[i].dma_rx_sync;
return 0;
}
-
arch_initcall(omap_mcbsp_init);
EXPORT_SYMBOL(omap_mcbsp_config);
EXPORT_SYMBOL(omap_mcbsp_request);
+EXPORT_SYMBOL(omap_mcbsp_set_io_type);
EXPORT_SYMBOL(omap_mcbsp_free);
EXPORT_SYMBOL(omap_mcbsp_start);
EXPORT_SYMBOL(omap_mcbsp_stop);
EXPORT_SYMBOL(omap_mcbsp_recv_word);
EXPORT_SYMBOL(omap_mcbsp_xmit_buffer);
EXPORT_SYMBOL(omap_mcbsp_recv_buffer);
+EXPORT_SYMBOL(omap_mcbsp_spi_master_xmit_word_poll);
+EXPORT_SYMBOL(omap_mcbsp_spi_master_recv_word_poll);
EXPORT_SYMBOL(omap_mcbsp_set_spi_mode);
if (!cpu_is_omap16xx())
return -ENODEV;
- /* Make sure there's clock for OCPI */
- clk_enable(ocpi_ck);
-
/* Enable access for OHCI in OCPI */
val = omap_readl(OCPI_PROT);
val &= ~0xff;
#include <linux/pm.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
+#include <linux/pm.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <asm/mach/map.h>
#include <asm/tlb.h>
#include <asm/io.h>
#include <asm/cacheflush.h>
+#include <asm/mach/map.h>
+
#include <asm/arch/sram.h>
+#include <asm/arch/board.h>
#define OMAP1_SRAM_PA 0x20000000
#define OMAP1_SRAM_VA 0xd0000000
#define OMAP2_SRAM_PA 0x40200000
+#define OMAP2_SRAM_PUB_PA 0x4020f800
#define OMAP2_SRAM_VA 0xd0000000
+#define OMAP2_SRAM_PUB_VA 0xd0000800
+#if defined(CONFIG_ARCH_OMAP24XX)
+#define SRAM_BOOTLOADER_SZ 0x00
+#else
#define SRAM_BOOTLOADER_SZ 0x80
+#endif
+
+#define VA_REQINFOPERM0 IO_ADDRESS(0x68005048)
+#define VA_READPERM0 IO_ADDRESS(0x68005050)
+#define VA_WRITEPERM0 IO_ADDRESS(0x68005058)
+#define VA_CONTROL_STAT IO_ADDRESS(0x480002F8)
+#define GP_DEVICE 0x300
+#define TYPE_MASK 0x700
+
+#define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1)))
static unsigned long omap_sram_base;
static unsigned long omap_sram_size;
static unsigned long omap_sram_ceil;
+unsigned long omap_fb_sram_start;
+unsigned long omap_fb_sram_size;
+
+/* Depending on the target RAMFS firewall setup, the public usable amount of
+ * SRAM varies. The default accessable size for all device types is 2k. A GP
+ * device allows ARM11 but not other initators for full size. This
+ * functionality seems ok until some nice security API happens.
+ */
+static int is_sram_locked(void)
+{
+ int type = 0;
+
+ if (cpu_is_omap242x())
+ type = __raw_readl(VA_CONTROL_STAT) & TYPE_MASK;
+
+ if (type == GP_DEVICE) {
+ /* RAMFW: R/W access to all initators for all qualifier sets */
+ if (cpu_is_omap242x()) {
+ __raw_writel(0xFF, VA_REQINFOPERM0); /* all q-vects */
+ __raw_writel(0xCFDE, VA_READPERM0); /* all i-read */
+ __raw_writel(0xCFDE, VA_WRITEPERM0); /* all i-write */
+ }
+ return 0;
+ } else
+ return 1; /* assume locked with no PPA or security driver */
+}
+
+void get_fb_sram_conf(unsigned long start_avail, unsigned size_avail,
+ unsigned long *start, unsigned long *size)
+{
+ const struct omap_fbmem_config *fbmem_conf;
+
+ fbmem_conf = omap_get_config(OMAP_TAG_FBMEM, struct omap_fbmem_config);
+ if (fbmem_conf != NULL) {
+ *start = fbmem_conf->fb_sram_start;
+ *size = fbmem_conf->fb_sram_size;
+ } else {
+ *size = 0;
+ *start = 0;
+ }
+
+ if (*size && (
+ *start < start_avail ||
+ *start + *size > start_avail + size_avail)) {
+ printk(KERN_ERR "invalid FB SRAM configuration\n");
+ *start = start_avail;
+ *size = size_avail;
+ }
+
+ if (*size)
+ pr_info("Reserving %lu bytes SRAM for frame buffer\n", *size);
+}
+
/*
* The amount of SRAM depends on the core type.
* Note that we cannot try to test for SRAM here because writes
*/
void __init omap_detect_sram(void)
{
- if (!cpu_is_omap24xx())
+ unsigned long sram_start;
+
+ if (cpu_is_omap24xx()) {
+ if (is_sram_locked()) {
+ omap_sram_base = OMAP2_SRAM_PUB_VA;
+ sram_start = OMAP2_SRAM_PUB_PA;
+ omap_sram_size = 0x800; /* 2K */
+ } else {
+ omap_sram_base = OMAP2_SRAM_VA;
+ sram_start = OMAP2_SRAM_PA;
+ if (cpu_is_omap242x())
+ omap_sram_size = 0xa0000; /* 640K */
+ else if (cpu_is_omap243x())
+ omap_sram_size = 0x10000; /* 64K */
+ }
+ } else {
omap_sram_base = OMAP1_SRAM_VA;
- else
- omap_sram_base = OMAP2_SRAM_VA;
-
- if (cpu_is_omap730())
- omap_sram_size = 0x32000; /* 200K */
- else if (cpu_is_omap15xx())
- omap_sram_size = 0x30000; /* 192K */
- else if (cpu_is_omap1610() || cpu_is_omap1621() || cpu_is_omap1710())
- omap_sram_size = 0x4000; /* 16K */
- else if (cpu_is_omap1611())
- omap_sram_size = 0x3e800; /* 250K */
- else if (cpu_is_omap2420())
- omap_sram_size = 0xa0014; /* 640K */
- else {
- printk(KERN_ERR "Could not detect SRAM size\n");
- omap_sram_size = 0x4000;
+ sram_start = OMAP1_SRAM_PA;
+
+ if (cpu_is_omap730())
+ omap_sram_size = 0x32000; /* 200K */
+ else if (cpu_is_omap15xx())
+ omap_sram_size = 0x30000; /* 192K */
+ else if (cpu_is_omap1610() || cpu_is_omap1621() ||
+ cpu_is_omap1710())
+ omap_sram_size = 0x4000; /* 16K */
+ else if (cpu_is_omap1611())
+ omap_sram_size = 0x3e800; /* 250K */
+ else {
+ printk(KERN_ERR "Could not detect SRAM size\n");
+ omap_sram_size = 0x4000;
+ }
}
-
+ get_fb_sram_conf(sram_start + SRAM_BOOTLOADER_SZ,
+ omap_sram_size - SRAM_BOOTLOADER_SZ,
+ &omap_fb_sram_start, &omap_fb_sram_size);
+ if (omap_fb_sram_size)
+ omap_sram_size -= sram_start + omap_sram_size -
+ omap_fb_sram_start;
omap_sram_ceil = omap_sram_base + omap_sram_size;
}
*/
void __init omap_map_sram(void)
{
+ unsigned long base;
+
if (omap_sram_size == 0)
return;
if (cpu_is_omap24xx()) {
omap_sram_io_desc[0].virtual = OMAP2_SRAM_VA;
- omap_sram_io_desc[0].pfn = __phys_to_pfn(OMAP2_SRAM_PA);
+
+ if (is_sram_locked())
+ base = OMAP2_SRAM_PUB_PA;
+ else
+ base = OMAP2_SRAM_PA;
+ base = ROUND_DOWN(base, PAGE_SIZE);
+ omap_sram_io_desc[0].pfn = __phys_to_pfn(base);
}
omap_sram_io_desc[0].length = (omap_sram_size + PAGE_SIZE-1)/PAGE_SIZE;
iotable_init(omap_sram_io_desc, ARRAY_SIZE(omap_sram_io_desc));
printk(KERN_INFO "SRAM: Mapped pa 0x%08lx to va 0x%08lx size: 0x%lx\n",
- omap_sram_io_desc[0].pfn, omap_sram_io_desc[0].virtual,
+ __pfn_to_phys(omap_sram_io_desc[0].pfn),
+ omap_sram_io_desc[0].virtual,
omap_sram_io_desc[0].length);
/*
printk(KERN_ERR "Not enough space in SRAM\n");
return NULL;
}
+
omap_sram_ceil -= size;
- omap_sram_ceil &= ~0x3;
+ omap_sram_ceil = ROUND_DOWN(omap_sram_ceil, sizeof(void *));
memcpy((void *)omap_sram_ceil, start, size);
return (void *)omap_sram_ceil;
--- /dev/null
+obj-y += sti.o sti-fifo.o
+
+obj-$(CONFIG_OMAP_STI_CONSOLE) += sti-console.o
+obj-$(CONFIG_NET) += sti-netlink.o
--- /dev/null
+/*
+ * 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;
+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;
+ }
+
+ 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 (default 32)");
+MODULE_AUTHOR("Paul Mundt");
+MODULE_DESCRIPTION("OMAP STI console support");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * 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");
--- /dev/null
+/*
+ * OMAP STI/XTI communications interface via netlink socket.
+ *
+ * Copyright (C) 2004, 2005 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 <net/sock.h>
+#include <asm/arch/sti.h>
+
+static struct sock *sti_sock;
+static DECLARE_MUTEX(sti_netlink_sem);
+
+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 (down_trylock(&sti_netlink_sem))
+ 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);
+
+ up(&sti_netlink_sem);
+}
+
+static int __init sti_netlink_init(void)
+{
+ sti_sock = netlink_kernel_create(NETLINK_USERSOCK, 0,
+ sti_netlink_receive, THIS_MODULE);
+ if (!sti_sock) {
+ printk(KERN_ERR "STI: Failed to create netlink socket\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+module_init(sti_netlink_init);
+
+MODULE_AUTHOR("Paul Mundt");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("STI netlink-driven communications interface");
--- /dev/null
+/*
+ * 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/config.h>
+#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, struct pt_regs *regs)
+{
+ 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,
+ SA_INTERRUPT, "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");
--- /dev/null
+/*
+ * linux/arch/arm/plat-omap/timer32k.c
+ *
+ * OMAP 32K Timer
+ *
+ * Copyright (C) 2004 - 2005 Nokia Corporation
+ * Partial timer rewrite and additional dynamic tick timer support by
+ * Tony Lindgen <tony@atomide.com> and
+ * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ *
+ * MPU timer code based on the older MPU timer code for OMAP
+ * Copyright (C) 2000 RidgeRun, Inc.
+ * Author: Greg Lonnon <glonnon@ridgerun.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/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <asm/system.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/leds.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+
+struct sys_timer omap_timer;
+
+/*
+ * ---------------------------------------------------------------------------
+ * 32KHz OS timer
+ *
+ * This currently works only on 16xx, as 1510 does not have the continuous
+ * 32KHz synchronous timer. The 32KHz synchronous timer is used to keep track
+ * of time in addition to the 32KHz OS timer. Using only the 32KHz OS timer
+ * on 1510 would be possible, but the timer would not be as accurate as
+ * with the 32KHz synchronized timer.
+ * ---------------------------------------------------------------------------
+ */
+
+#if defined(CONFIG_ARCH_OMAP16XX)
+#define TIMER_32K_SYNCHRONIZED 0xfffbc410
+#elif defined(CONFIG_ARCH_OMAP24XX)
+#define TIMER_32K_SYNCHRONIZED 0x48004010
+#else
+#error OMAP 32KHz timer does not currently work on 15XX!
+#endif
+
+/* 16xx specific defines */
+#define OMAP1_32K_TIMER_BASE 0xfffb9000
+#define OMAP1_32K_TIMER_CR 0x08
+#define OMAP1_32K_TIMER_TVR 0x00
+#define OMAP1_32K_TIMER_TCR 0x04
+
+/* 24xx specific defines */
+#define OMAP2_GP_TIMER_BASE 0x48028000
+#define CM_CLKSEL_WKUP 0x48008440
+#define GP_TIMER_TIDR 0x00
+#define GP_TIMER_TISR 0x18
+#define GP_TIMER_TIER 0x1c
+#define GP_TIMER_TCLR 0x24
+#define GP_TIMER_TCRR 0x28
+#define GP_TIMER_TLDR 0x2c
+#define GP_TIMER_TTGR 0x30
+#define GP_TIMER_TSICR 0x40
+
+#define OMAP_32K_TICKS_PER_HZ (32768 / HZ)
+
+/*
+ * TRM says 1 / HZ = ( TVR + 1) / 32768, so TRV = (32768 / HZ) - 1
+ * so with HZ = 128, TVR = 255.
+ */
+#define OMAP_32K_TIMER_TICK_PERIOD ((32768 / HZ) - 1)
+
+#define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \
+ (((nr_jiffies) * (clock_rate)) / HZ)
+
+static inline void omap_32k_timer_write(int val, int reg)
+{
+ if (cpu_class_is_omap1())
+ omap_writew(val, OMAP1_32K_TIMER_BASE + reg);
+
+ if (cpu_is_omap24xx())
+ omap_writel(val, OMAP2_GP_TIMER_BASE + reg);
+}
+
+static inline unsigned long omap_32k_timer_read(int reg)
+{
+ if (cpu_class_is_omap1())
+ return omap_readl(OMAP1_32K_TIMER_BASE + reg) & 0xffffff;
+
+ if (cpu_is_omap24xx())
+ return omap_readl(OMAP2_GP_TIMER_BASE + reg);
+}
+
+/*
+ * The 32KHz synchronized timer is an additional timer on 16xx.
+ * It is always running.
+ */
+static inline unsigned long omap_32k_sync_timer_read(void)
+{
+ return omap_readl(TIMER_32K_SYNCHRONIZED);
+}
+
+static inline void omap_32k_timer_start(unsigned long load_val)
+{
+ if (cpu_class_is_omap1()) {
+ omap_32k_timer_write(load_val, OMAP1_32K_TIMER_TVR);
+ omap_32k_timer_write(0x0f, OMAP1_32K_TIMER_CR);
+ }
+
+ if (cpu_is_omap24xx()) {
+ omap_32k_timer_write(0xffffffff - load_val, GP_TIMER_TCRR);
+ omap_32k_timer_write((1 << 1), GP_TIMER_TIER);
+ omap_32k_timer_write((1 << 1) | 1, GP_TIMER_TCLR);
+ }
+}
+
+static inline void omap_32k_timer_stop(void)
+{
+ if (cpu_class_is_omap1())
+ omap_32k_timer_write(0x0, OMAP1_32K_TIMER_CR);
+
+ if (cpu_is_omap24xx())
+ omap_32k_timer_write(0x0, GP_TIMER_TCLR);
+}
+
+/*
+ * Rounds down to nearest usec. Note that this will overflow for larger values.
+ */
+static inline unsigned long omap_32k_ticks_to_usecs(unsigned long ticks_32k)
+{
+ return (ticks_32k * 5*5*5*5*5*5) >> 9;
+}
+
+/*
+ * Rounds down to nearest nsec.
+ */
+static inline unsigned long long
+omap_32k_ticks_to_nsecs(unsigned long ticks_32k)
+{
+ return (unsigned long long) ticks_32k * 1000 * 5*5*5*5*5*5 >> 9;
+}
+
+static unsigned long omap_32k_last_tick = 0;
+
+/*
+ * Returns elapsed usecs since last 32k timer interrupt
+ */
+static unsigned long omap_32k_timer_gettimeoffset(void)
+{
+ unsigned long now = omap_32k_sync_timer_read();
+ return omap_32k_ticks_to_usecs(now - omap_32k_last_tick);
+}
+
+/*
+ * Returns current time from boot in nsecs. It's OK for this to wrap
+ * around for now, as it's just a relative time stamp.
+ */
+unsigned long long sched_clock(void)
+{
+ return omap_32k_ticks_to_nsecs(omap_32k_sync_timer_read());
+}
+
+/*
+ * Timer interrupt for 32KHz timer. When dynamic tick is enabled, this
+ * function is also called from other interrupts to remove latency
+ * issues with dynamic tick. In the dynamic tick case, we need to lock
+ * with irqsave.
+ */
+static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ unsigned long flags;
+ unsigned long now;
+
+ write_seqlock_irqsave(&xtime_lock, flags);
+
+ if (cpu_is_omap24xx()) {
+ u32 status = omap_32k_timer_read(GP_TIMER_TISR);
+ omap_32k_timer_write(status, GP_TIMER_TISR);
+ }
+
+ now = omap_32k_sync_timer_read();
+
+ while (now - omap_32k_last_tick >= OMAP_32K_TICKS_PER_HZ) {
+ omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ;
+ timer_tick(regs);
+ }
+
+ /* Restart timer so we don't drift off due to modulo or dynamic tick.
+ * By default we program the next timer to be continuous to avoid
+ * latencies during high system load. During dynamic tick operation the
+ * continuous timer can be overridden from pm_idle to be longer.
+ */
+ omap_32k_timer_start(omap_32k_last_tick + OMAP_32K_TICKS_PER_HZ - now);
+ write_sequnlock_irqrestore(&xtime_lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_NO_IDLE_HZ
+/*
+ * Programs the next timer interrupt needed. Called when dynamic tick is
+ * enabled, and to reprogram the ticks to skip from pm_idle. Note that
+ * we can keep the timer continuous, and don't need to set it to run in
+ * one-shot mode. This is because the timer will get reprogrammed again
+ * after next interrupt.
+ */
+void omap_32k_timer_reprogram(unsigned long next_tick)
+{
+ omap_32k_timer_start(JIFFIES_TO_HW_TICKS(next_tick, 32768) + 1);
+}
+
+static struct irqaction omap_32k_timer_irq;
+extern struct timer_update_handler timer_update;
+
+static int omap_32k_timer_enable_dyn_tick(void)
+{
+ /* No need to reprogram timer, just use the next interrupt */
+ return 0;
+}
+
+static int omap_32k_timer_disable_dyn_tick(void)
+{
+ omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD);
+ return 0;
+}
+
+static struct dyn_tick_timer omap_dyn_tick_timer = {
+ .enable = omap_32k_timer_enable_dyn_tick,
+ .disable = omap_32k_timer_disable_dyn_tick,
+ .reprogram = omap_32k_timer_reprogram,
+ .handler = omap_32k_timer_interrupt,
+};
+#endif /* CONFIG_NO_IDLE_HZ */
+
+static struct irqaction omap_32k_timer_irq = {
+ .name = "32KHz timer",
+ .flags = SA_INTERRUPT | SA_TIMER,
+ .handler = omap_32k_timer_interrupt,
+};
+
+static struct clk * gpt1_ick;
+static struct clk * gpt1_fck;
+
+static __init void omap_init_32k_timer(void)
+{
+#ifdef CONFIG_NO_IDLE_HZ
+ omap_timer.dyn_tick = &omap_dyn_tick_timer;
+#endif
+
+ if (cpu_class_is_omap1())
+ setup_irq(INT_OS_TIMER, &omap_32k_timer_irq);
+ if (cpu_is_omap24xx())
+ setup_irq(37, &omap_32k_timer_irq);
+ omap_timer.offset = omap_32k_timer_gettimeoffset;
+ omap_32k_last_tick = omap_32k_sync_timer_read();
+
+ /* REVISIT: Check 24xx TIOCP_CFG settings after idle works */
+ if (cpu_is_omap24xx()) {
+ omap_32k_timer_write(0, GP_TIMER_TCLR);
+ omap_writel(0, CM_CLKSEL_WKUP); /* 32KHz clock source */
+
+ gpt1_ick = clk_get(NULL, "gpt1_ick");
+ if (IS_ERR(gpt1_ick))
+ printk(KERN_ERR "Could not get gpt1_ick\n");
+ else
+ clk_enable(gpt1_ick);
+
+ gpt1_fck = clk_get(NULL, "gpt1_fck");
+ if (IS_ERR(gpt1_fck))
+ printk(KERN_ERR "Could not get gpt1_fck\n");
+ else
+ clk_enable(gpt1_fck);
+
+ mdelay(100); /* Wait for clocks to stabilize */
+
+ omap_32k_timer_write(0x7, GP_TIMER_TISR);
+ }
+
+ omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD);
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * Timer initialization
+ * ---------------------------------------------------------------------------
+ */
+static void __init omap_timer_init(void)
+{
+ omap_init_32k_timer();
+}
+
+struct sys_timer omap_timer = {
+ .init = omap_timer_init,
+ .offset = NULL, /* Initialized later */
+};
source "drivers/edac/Kconfig"
+source "drivers/ssi/Kconfig"
+
endmenu
obj-$(CONFIG_SERIO) += input/serio/
obj-y += serial/
obj-$(CONFIG_PARPORT) += parport/
-obj-y += base/ block/ misc/ mfd/ net/ media/
+obj-y += base/ block/ misc/ mfd/ net/
+obj-$(CONFIG_I2C) += i2c/
+obj-y += media/ ssi/ cbus/
obj-$(CONFIG_NUBUS) += nubus/
obj-$(CONFIG_ATM) += atm/
obj-$(CONFIG_PPC_PMAC) += macintosh/
obj-$(CONFIG_GAMEPORT) += input/gameport/
obj-$(CONFIG_INPUT) += input/
obj-$(CONFIG_I2O) += message/
-obj-$(CONFIG_I2C) += i2c/
obj-$(CONFIG_W1) += w1/
obj-$(CONFIG_HWMON) += hwmon/
obj-$(CONFIG_PHONE) += telephony/
Say Y here to compile support for HCI UART devices into the
kernel or say M to compile it as module (btuart_cs).
+config BT_HCIBRF6150
+ tristate "HCI TI BRF6150 driver with H4 extensions"
+ depends on BT && ARCH_OMAP
+ help
+ Bluetooth HCI driver for TI BRF6150 with H4 extensions.
+ This driver provides support for BRF6150 Bluetooth chip
+ with vendor-specific H4 extensions.
+
+ Say Y here to compile support for TI BRF6150 devices into the
+ kernel or say M to compile it as module (brf6150).
+
config BT_HCIVHCI
tristate "HCI VHCI (Virtual HCI device) driver"
help
obj-$(CONFIG_BT_HCIBT3C) += bt3c_cs.o
obj-$(CONFIG_BT_HCIBLUECARD) += bluecard_cs.o
obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o
+obj-$(CONFIG_BT_HCIBRF6150) += brf6150.o
hci_uart-y := hci_ldisc.o
hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
--- /dev/null
+/*
+ * 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/config.h>
+#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/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 pt_regs *regs)
+{
+ 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 pt_regs *regs)
+{
+ 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>");
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+#
+# CBUS device configuration
+#
+
+menu "CBUS support"
+
+config CBUS
+ depends on ARCH_OMAP
+ bool "CBUS support on OMAP"
+ ---help---
+ CBUS is a proprietary serial protocol by Nokia. It is mainly
+ used for accessing Energy Management auxiliary chips.
+
+ If you want CBUS support, you should say Y here.
+
+config CBUS_TAHVO
+ depends on CBUS
+ bool "Support for Tahvo"
+ ---help---
+ Tahvo is a mixed signal ASIC with some system features
+
+ If you want Tahvo support, you should say Y here.
+
+config CBUS_TAHVO_USER
+ depends on CBUS_TAHVO
+ bool "Support for Tahvo user space functions"
+ ---help---
+ If you want support for Tahvo's user space read/write etc. functions,
+ you should say Y here.
+
+config CBUS_TAHVO_USB
+ depends on CBUS_TAHVO && USB
+ tristate "Support for Tahvo USB transceiver"
+ ---help---
+ If you want Tahvo support for USB transceiver, say Y or M here.
+
+config CBUS_TAHVO_USB_HOST_BY_DEFAULT
+ depends on CBUS_TAHVO_USB && USB_OTG
+ boolean "Device in USB host mode by default"
+ ---help---
+ Say Y here, if you want the device to enter USB host mode
+ by default on bootup.
+
+config CBUS_RETU
+ depends on CBUS
+ bool "Support for Retu"
+ ---help---
+ Retu is a mixed signal ASIC with some system features
+
+ If you want Retu support, you should say Y here.
+
+config CBUS_RETU_USER
+ depends on CBUS_RETU
+ bool "Support for Retu user space functions"
+ ---help---
+ If you want support for Retu's user space read/write etc. functions,
+ you should say Y here.
+
+config CBUS_RETU_POWERBUTTON
+ depends on CBUS_RETU
+ bool "Support for Retu power button"
+ ---help---
+ The power button on Nokia 770 is connected to the Retu ASIC.
+
+ If you want support for the Retu power button, you should say Y here.
+
+config CBUS_RETU_RTC
+ depends on CBUS_RETU && SYSFS
+ tristate "Support for Retu pseudo-RTC"
+ ---help---
+ Say Y here if you want support for the device that alleges to be an
+ RTC in Retu. This will expose a sysfs interface for it.
+
+config CBUS_RETU_WDT
+ depends on CBUS_RETU && SYSFS
+ tristate "Support for Retu watchdog timer"
+ ---help---
+ Say Y here if you want support for the watchdog in Retu. This will
+ expose a sysfs interface to grok it.
+
+endmenu
--- /dev/null
+#
+# Makefile for CBUS.
+#
+
+obj-$(CONFIG_CBUS) += cbus.o
+obj-$(CONFIG_CBUS_TAHVO) += tahvo.o
+obj-$(CONFIG_CBUS_RETU) += retu.o
+obj-$(CONFIG_CBUS_TAHVO_USB) += tahvo-usb.o
+obj-$(CONFIG_CBUS_RETU_POWERBUTTON) += retu-pwrbutton.o
+obj-$(CONFIG_CBUS_RETU_RTC) += retu-rtc.o
+obj-$(CONFIG_CBUS_RETU_WDT) += retu-wdt.o
+obj-$(CONFIG_CBUS_TAHVO_USER) += tahvo-user.o
+obj-$(CONFIG_CBUS_RETU_USER) += retu-user.o
--- /dev/null
+/*
+ * drivers/cbus/cbus.c
+ *
+ * Support functions for CBUS serial protocol
+ *
+ * Copyright (C) 2004, 2005 Nokia Corporation
+ *
+ * Written by Juha Yrjölä <juha.yrjola@nokia.com>,
+ * David Weinehall <david.weinehall@nokia.com>, and
+ * Mikko Ylinen <mikko.k.ylinen@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.
+ *
+ * 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/device.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/board.h>
+
+#include <asm/io.h>
+
+#include "cbus.h"
+
+struct cbus_host *cbus_host = NULL;
+
+#ifdef CONFIG_ARCH_OMAP1
+/* We use our own MPUIO functions to get closer to 1MHz bus speed */
+
+static inline void cbus_set_gpio_direction(u32 base, int mpuio, int is_input)
+{
+ u16 w;
+
+ mpuio &= 0x0f;
+ w = __raw_readw(base + OMAP_MPUIO_IO_CNTL);
+ if (is_input)
+ w |= 1 << mpuio;
+ else
+ w &= ~(1 << mpuio);
+ __raw_writew(w, base + OMAP_MPUIO_IO_CNTL);
+
+}
+
+static inline void cbus_set_gpio_dataout(u32 base, int mpuio, int enable)
+{
+ u16 w;
+
+ mpuio &= 0x0f;
+ w = __raw_readw(base + OMAP_MPUIO_OUTPUT);
+ if (enable)
+ w |= 1 << mpuio;
+ else
+ w &= ~(1 << mpuio);
+ __raw_writew(w, base + OMAP_MPUIO_OUTPUT);
+}
+
+static inline int cbus_get_gpio_datain(u32 base, int mpuio)
+{
+ mpuio &= 0x0f;
+
+ return (__raw_readw(base + OMAP_MPUIO_INPUT_LATCH) & (1 << mpuio)) != 0;
+}
+
+static void cbus_send_bit(struct cbus_host *host, u32 base, int bit,
+ int set_to_input)
+{
+ cbus_set_gpio_dataout(base, host->dat_gpio, bit ? 1 : 0);
+ cbus_set_gpio_dataout(base, host->clk_gpio, 1);
+
+ /* The data bit is read on the rising edge of CLK */
+ if (set_to_input)
+ cbus_set_gpio_direction(base, host->dat_gpio, 1);
+
+ cbus_set_gpio_dataout(base, host->clk_gpio, 0);
+}
+
+static u8 cbus_receive_bit(struct cbus_host *host, u32 base)
+{
+ u8 ret;
+
+ cbus_set_gpio_dataout(base, host->clk_gpio, 1);
+ ret = cbus_get_gpio_datain(base, host->dat_gpio);
+ cbus_set_gpio_dataout(base, host->clk_gpio, 0);
+
+ return ret;
+}
+
+#else
+
+#define cbus_set_gpio_direction(base, gpio, is_input) omap_set_gpio_direction(gpio, is_input)
+#define cbus_set_gpio_dataout(base, gpio, enable) omap_set_gpio_dataout(gpio, enable)
+#define cbus_get_gpio_datain(base, int, gpio) omap_get_gpio_datain(gpio)
+
+static void _cbus_send_bit(struct cbus_host *host, int bit, int set_to_input)
+{
+ omap_set_gpio_dataout(host->dat_gpio, bit ? 1 : 0);
+ omap_set_gpio_dataout(host->clk_gpio, 1);
+
+ /* The data bit is read on the rising edge of CLK */
+ if (set_to_input)
+ omap_set_gpio_direction(host->dat_gpio, 1);
+
+ omap_set_gpio_dataout(host->clk_gpio, 0);
+}
+
+static u8 _cbus_receive_bit(struct cbus_host *host)
+{
+ u8 ret;
+
+ omap_set_gpio_dataout(host->clk_gpio, 1);
+ ret = omap_get_gpio_datain(host->dat_gpio);
+ omap_set_gpio_dataout(host->clk_gpio, 0);
+
+ return ret;
+}
+
+#define cbus_send_bit(host, base, bit, set_to_input) _cbus_send_bit(host, bit, set_to_input)
+#define cbus_receive_bit(host, base) _cbus_receive_bit(host)
+
+#endif
+
+static int cbus_transfer(struct cbus_host *host, int dev, int reg, int data)
+{
+ int i;
+ int is_read = 0;
+ unsigned long flags;
+ u32 base;
+
+#ifdef CONFIG_ARCH_OMAP1
+ base = (u32) io_p2v(OMAP_MPUIO_BASE);
+#else
+ base = 0;
+#endif
+
+ if (data < 0)
+ is_read = 1;
+
+ /* We don't want interrupts disturbing our transfer */
+ spin_lock_irqsave(&host->lock, flags);
+
+ /* Reset state and start of transfer, SEL stays down during transfer */
+ cbus_set_gpio_dataout(base, host->sel_gpio, 0);
+
+ /* Set the DAT pin to output */
+ cbus_set_gpio_direction(base, host->dat_gpio, 0);
+
+ /* Send the device address */
+ for (i = 3; i > 0; i--)
+ cbus_send_bit(host, base, dev & (1 << (i - 1)), 0);
+
+ /* Send the rw flag */
+ cbus_send_bit(host, base, is_read, 0);
+
+ /* Send the register address */
+ for (i = 5; i > 0; i--) {
+ int set_to_input = 0;
+
+ if (is_read && i == 1)
+ set_to_input = 1;
+
+ cbus_send_bit(host, base, reg & (1 << (i - 1)), set_to_input);
+ }
+
+ if (!is_read) {
+ for (i = 16; i > 0; i--)
+ cbus_send_bit(host, base, data & (1 << (i - 1)), 0);
+ } else {
+ cbus_set_gpio_dataout(base, host->clk_gpio, 1);
+ data = 0;
+
+ for (i = 16; i > 0; i--) {
+ u8 bit = cbus_receive_bit(host, base);
+
+ if (bit)
+ data |= 1 << (i - 1);
+ }
+ }
+
+ /* Indicate end of transfer, SEL goes up until next transfer */
+ cbus_set_gpio_dataout(base, host->sel_gpio, 1);
+ cbus_set_gpio_dataout(base, host->clk_gpio, 1);
+ cbus_set_gpio_dataout(base, host->clk_gpio, 0);
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return is_read ? data : 0;
+}
+
+/*
+ * Read a given register from the device
+ */
+int cbus_read_reg(struct cbus_host *host, int dev, int reg)
+{
+ return cbus_host ? cbus_transfer(host, dev, reg, -1) : -ENODEV;
+}
+
+/*
+ * Write to a given register of the device
+ */
+int cbus_write_reg(struct cbus_host *host, int dev, int reg, u16 val)
+{
+ return cbus_host ? cbus_transfer(host, dev, reg, (int)val) : -ENODEV;
+}
+
+int __init cbus_bus_init(void)
+{
+ const struct omap_cbus_config * cbus_config;
+ struct cbus_host *chost;
+ int ret;
+
+ chost = kmalloc(sizeof (*chost), GFP_KERNEL);
+ if (chost == NULL)
+ return -ENOMEM;
+
+ memset(chost, 0, sizeof (*chost));
+
+ spin_lock_init(&chost->lock);
+
+ cbus_config = omap_get_config(OMAP_TAG_CBUS, struct omap_cbus_config);
+
+ if (cbus_config == NULL) {
+ printk(KERN_ERR "cbus: Unable to retrieve config data\n");
+ return -ENODATA;
+ }
+
+ chost->clk_gpio = cbus_config->clk_gpio;
+ chost->dat_gpio = cbus_config->dat_gpio;
+ chost->sel_gpio = cbus_config->sel_gpio;
+
+#ifdef CONFIG_ARCH_OMAP1
+ if (!OMAP_GPIO_IS_MPUIO(chost->clk_gpio) ||
+ !OMAP_GPIO_IS_MPUIO(chost->dat_gpio) ||
+ !OMAP_GPIO_IS_MPUIO(chost->sel_gpio)) {
+ printk(KERN_ERR "cbus: Only MPUIO pins supported\n");
+ ret = -ENODEV;
+ goto exit1;
+ }
+#endif
+
+ if ((ret = omap_request_gpio(chost->clk_gpio)) < 0)
+ goto exit1;
+
+ if ((ret = omap_request_gpio(chost->dat_gpio)) < 0)
+ goto exit2;
+
+ if ((ret = omap_request_gpio(chost->sel_gpio)) < 0)
+ goto exit3;
+
+ omap_set_gpio_dataout(chost->clk_gpio, 0);
+ omap_set_gpio_dataout(chost->sel_gpio, 1);
+
+ omap_set_gpio_direction(chost->clk_gpio, 0);
+ omap_set_gpio_direction(chost->dat_gpio, 1);
+ omap_set_gpio_direction(chost->sel_gpio, 0);
+
+ omap_set_gpio_dataout(chost->clk_gpio, 1);
+ omap_set_gpio_dataout(chost->clk_gpio, 0);
+
+ cbus_host = chost;
+
+ return 0;
+exit3:
+ omap_free_gpio(chost->dat_gpio);
+exit2:
+ omap_free_gpio(chost->clk_gpio);
+exit1:
+ kfree(chost);
+ return ret;
+}
+
+subsys_initcall(cbus_bus_init);
+
+EXPORT_SYMBOL(cbus_host);
+EXPORT_SYMBOL(cbus_read_reg);
+EXPORT_SYMBOL(cbus_write_reg);
+
+MODULE_DESCRIPTION("CBUS serial protocol");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Juha Yrjölä, David Weinehall, and Mikko Ylinen");
--- /dev/null
+/*
+ * drivers/cbus/cbus.h
+ *
+ * Copyright (C) 2004, 2005 Nokia Corporation
+ *
+ * Written by Juha Yrjölä <juha.yrjola@nokia.com> and
+ * David Weinehall <david.weinehall@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.
+ *
+ * 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 __DRIVERS_CBUS_CBUS_H
+#define __DRIVERS_CBUS_CBUS_H
+
+struct cbus_host {
+ int clk_gpio, dat_gpio, sel_gpio;
+ spinlock_t lock;
+};
+
+extern struct cbus_host *cbus_host;
+
+extern int cbus_read_reg(struct cbus_host *host, int dev, int reg);
+extern int cbus_write_reg(struct cbus_host *host, int dev, int reg, u16 val);
+
+#endif /* __DRIVERS_CBUS_CBUS_H */
--- /dev/null
+/**
+ * drivers/cbus/retu-pwrbutton.c
+ *
+ * Driver for sending retu power button event to input-layer
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ *
+ * Written by Ari Saastamoinen <ari.saastamoinen@elektrobit.com>
+ *
+ * Contact Juha Yrjölä <juha.yrjola@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.
+ *
+ * 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/init.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+
+#include "retu.h"
+
+#define RETU_STATUS_PWRONX (1 << 5)
+
+#define PWRBTN_DELAY 20
+#define PWRBTN_UP 0
+#define PWRBTN_PRESSED 1
+
+static int pwrbtn_state;
+static struct input_dev *pwrbtn_dev;
+static struct timer_list pwrbtn_timer;
+
+static void retubutton_timer_func(unsigned long arg)
+{
+ int state;
+
+ if (retu_read_reg(RETU_REG_STATUS) & RETU_STATUS_PWRONX)
+ state = PWRBTN_UP;
+ else
+ state = PWRBTN_PRESSED;
+
+ if (pwrbtn_state != state) {
+ input_report_key(pwrbtn_dev, KEY_POWER, state);
+ pwrbtn_state = state;
+ }
+}
+
+/**
+ * Interrupt function is called whenever power button key is pressed
+ * or released.
+ */
+static void retubutton_irq(unsigned long arg)
+{
+ retu_ack_irq(RETU_INT_PWR);
+ mod_timer(&pwrbtn_timer, jiffies + msecs_to_jiffies(PWRBTN_DELAY));
+}
+
+/**
+ * Init function.
+ * Allocates interrupt for power button and registers itself to input layer.
+ */
+static int __init retubutton_init(void)
+{
+ int irq;
+
+ printk(KERN_INFO "Retu power button driver initialized\n");
+ irq = RETU_INT_PWR;
+
+ init_timer(&pwrbtn_timer);
+ pwrbtn_timer.function = retubutton_timer_func;
+
+ if (retu_request_irq(irq, &retubutton_irq, 0, "PwrOnX") < 0) {
+ printk(KERN_ERR "%s@%s: Cannot allocate irq\n",
+ __FUNCTION__, __FILE__);
+ return -EBUSY;
+ }
+
+ pwrbtn_dev = input_allocate_device();
+ if (!pwrbtn_dev)
+ return -ENOMEM;
+
+ pwrbtn_dev->evbit[0] = BIT(EV_KEY);
+ pwrbtn_dev->keybit[LONG(KEY_POWER)] = BIT(KEY_POWER);
+ pwrbtn_dev->name = "retu-pwrbutton";
+
+ input_register_device(pwrbtn_dev);
+
+ return 0;
+}
+
+/**
+ * Cleanup function which is called when driver is unloaded
+ */
+static void __exit retubutton_exit(void)
+{
+ retu_free_irq(RETU_INT_PWR);
+ del_timer_sync(&pwrbtn_timer);
+ input_unregister_device(pwrbtn_dev);
+}
+
+module_init(retubutton_init);
+module_exit(retubutton_exit);
+
+MODULE_DESCRIPTION("Retu Power Button");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ari Saastamoinen");
--- /dev/null
+/**
+ * drivers/cbus/retu-rtc.c
+ *
+ * Support for Retu RTC
+ *
+ * Copyright (C) 2004, 2005 Nokia Corporation
+ *
+ * Written by Paul Mundt <paul.mundt@nokia.com> and
+ * Igor Stoppa <igor.stoppa@nokia.com>
+ *
+ * The Retu RTC is essentially a partial read-only RTC that gives us Retu's
+ * idea of what time actually is. It's left as a userspace excercise to map
+ * this back to time in the real world and ensure that calibration settings
+ * are sane to compensate for any horrible drift (on account of not being able
+ * to set the clock to anything).
+ *
+ * Days are semi-writeable. Namely, Retu will only track 255 days for us
+ * consecutively, after which the counter is explicitly stuck at 255 until
+ * someone comes along and clears it with a write. In the event that no one
+ * comes along and clears it, we no longer have any idea what day it is.
+ *
+ * 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.
+ *
+ * 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/device.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
+#include <asm/semaphore.h>
+
+#include "cbus.h"
+#include "retu.h"
+
+static struct semaphore retu_rtc_sem;
+static u16 retu_rtc_alarm_expired;
+static u16 retu_rtc_reset_occurred;
+
+static DECLARE_COMPLETION(retu_rtc_exited);
+static DECLARE_COMPLETION(retu_rtc_sync);
+
+static void retu_rtc_barrier(void);
+
+static void retu_rtc_device_release(struct device *dev)
+{
+ complete(&retu_rtc_exited);
+}
+
+static ssize_t retu_rtc_time_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ u16 dsr, hmr, dsr2;
+
+ down(&retu_rtc_sem);
+
+ do {
+ u16 dummy;
+
+ /*
+ * Not being in_interrupt() for a retu rtc IRQ, we need to
+ * read twice for consistency..
+ */
+ dummy = retu_read_reg(RETU_REG_RTCDSR);
+ dsr = retu_read_reg(RETU_REG_RTCDSR);
+
+ dummy = retu_read_reg(RETU_REG_RTCHMR);
+ hmr = retu_read_reg(RETU_REG_RTCHMR);
+
+ dummy = retu_read_reg(RETU_REG_RTCDSR);
+ dsr2 = retu_read_reg(RETU_REG_RTCDSR);
+ } while ((dsr != dsr2));
+
+ up(&retu_rtc_sem);
+
+ /*
+ * Format a 32-bit date-string for userspace
+ *
+ * days | hours | minutes | seconds
+ *
+ * 8 bits for each.
+ *
+ * This mostly sucks because days and seconds are tracked in RTCDSR
+ * while hours and minutes are tracked in RTCHMR. And yes, there
+ * really are no words that can describe an 8 bit day register (or
+ * rather, none that will be reprinted here).
+ */
+ return sprintf(buf, "0x%08x\n", (((dsr >> 8) & 0xff) << 24) |
+ (((hmr >> 8) & 0x1f) << 16) |
+ ((hmr & 0x3f) << 8) | (dsr & 0x3f));
+}
+
+static ssize_t retu_rtc_time_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ down(&retu_rtc_sem);
+ /*
+ * Writing anything to the day counter forces it to 0
+ * The seconds counter would be cleared by resetting the minutes counter,
+ * however this won't happen, since we are using the hh:mm counters as
+ * a set of free running counters and the day counter as a multiple
+ * overflow holder.
+ */
+
+ /* Reset day counter, but keep Temperature Shutdown state */
+ retu_write_reg(RETU_REG_RTCDSR,
+ retu_read_reg(RETU_REG_RTCDSR) & (1 << 6));
+
+ up(&retu_rtc_sem);
+
+ return count;
+}
+
+static DEVICE_ATTR(time, S_IRUGO | S_IWUSR, retu_rtc_time_show,
+ retu_rtc_time_store);
+
+
+static ssize_t retu_rtc_reset_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ /*
+ * Returns the status of the rtc
+ *
+ * 0: no reset has occurred or the status has been cleared
+ * 1: a reset has occurred
+ *
+ * RTC needs to be reset only when both main battery
+ * _AND_ backup battery are discharged
+ */
+ return sprintf(buf, "%u\n", retu_rtc_reset_occurred);
+}
+
+static void retu_rtc_do_reset(void)
+{
+ u16 ccr1;
+
+ ccr1 = retu_read_reg(RETU_REG_CC1);
+ /* RTC in reset */
+ retu_write_reg(RETU_REG_CC1, ccr1 | 0x0001);
+ /* RTC in normal operating mode */
+ retu_write_reg(RETU_REG_CC1, ccr1 & ~0x0001);
+
+ retu_rtc_barrier();
+ /* Disable alarm and RTC WD */
+ retu_write_reg(RETU_REG_RTCHMAR, 0x7f3f);
+ /* Set Calibration register to default value */
+ retu_write_reg(RETU_REG_RTCCALR, 0x00c0);
+
+ retu_rtc_alarm_expired = 0;
+ retu_rtc_reset_occurred = 1;
+}
+
+static ssize_t retu_rtc_reset_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned choice;
+
+ if(sscanf(buf, "%u", &choice) != 1)
+ return count;
+ down(&retu_rtc_sem);
+ if (choice == 0)
+ retu_rtc_reset_occurred = 0;
+ else if (choice == 1)
+ retu_rtc_do_reset();
+ up(&retu_rtc_sem);
+ return count;
+}
+
+static DEVICE_ATTR(reset, S_IRUGO | S_IWUSR, retu_rtc_reset_show,
+ retu_rtc_reset_store);
+
+static ssize_t retu_rtc_alarm_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ u16 chmar;
+ ssize_t retval;
+
+ down(&retu_rtc_sem);
+ /*
+ * Format a 16-bit date-string for userspace
+ *
+ * hours | minutes
+ * 8 bits for each.
+ */
+ chmar = retu_read_reg(RETU_REG_RTCHMAR);
+ /* No shifting needed, only masking unrelated bits */
+ retval = sprintf(buf, "0x%04x\n", chmar & 0x1f3f);
+ up(&retu_rtc_sem);
+
+ return retval;
+}
+
+static ssize_t retu_rtc_alarm_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ u16 chmar;
+ unsigned alrm;
+ unsigned hours;
+ unsigned minutes;
+
+ down(&retu_rtc_sem);
+
+ if(sscanf(buf, "%x", &alrm) != 1)
+ return count;
+ hours = (alrm >> 8) & 0x001f;
+ minutes = (alrm >> 0) & 0x003f;
+ if ((hours < 24 && minutes < 60) || (hours == 24 && minutes == 60)) {
+ /*
+ * OK, the time format for the alarm is valid (including the
+ * disabling values)
+ */
+ /* Keeps the RTC watchdog status */
+ chmar = retu_read_reg(RETU_REG_RTCHMAR) & 0x6000;
+ chmar |= alrm & 0x1f3f; /* Stores the requested alarm */
+ retu_rtc_barrier();
+ retu_write_reg(RETU_REG_RTCHMAR, chmar);
+ /* If the alarm is being disabled */
+ if (hours == 24 && minutes == 60) {
+ /* disable the interrupt */
+ retu_disable_irq(RETU_INT_RTCA);
+ retu_rtc_alarm_expired = 0;
+ } else
+ /* enable the interrupt */
+ retu_enable_irq(RETU_INT_RTCA);
+ }
+ up(&retu_rtc_sem);
+
+ return count;
+}
+
+static DEVICE_ATTR(alarm, S_IRUGO | S_IWUSR, retu_rtc_alarm_show,
+ retu_rtc_alarm_store);
+
+static ssize_t retu_rtc_alarm_expired_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ ssize_t retval;
+
+ retval = sprintf(buf, "%u\n", retu_rtc_alarm_expired);
+
+ return retval;
+}
+
+static ssize_t retu_rtc_alarm_expired_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ retu_rtc_alarm_expired = 0;
+
+ return count;
+}
+
+static DEVICE_ATTR(alarm_expired, S_IRUGO | S_IWUSR, retu_rtc_alarm_expired_show,
+ retu_rtc_alarm_expired_store);
+
+
+static ssize_t retu_rtc_cal_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ u16 rtccalr1;
+
+ down(&retu_rtc_sem);
+ rtccalr1 = retu_read_reg(RETU_REG_RTCCALR);
+ up(&retu_rtc_sem);
+
+ /*
+ * Shows the status of the Calibration Register.
+ *
+ * Default, after power loss: 0x0000
+ * Default, for R&D: 0x00C0
+ * Default, for factory: 0x00??
+ *
+ */
+ return sprintf(buf, "0x%04x\n", rtccalr1 & 0x00ff);
+}
+
+static ssize_t retu_rtc_cal_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned calibration_value;
+
+ if (sscanf(buf, "%x", &calibration_value) != 1)
+ return count;
+
+ down(&retu_rtc_sem);
+ retu_rtc_barrier();
+ retu_write_reg(RETU_REG_RTCCALR, calibration_value & 0x00ff);
+ up(&retu_rtc_sem);
+
+ return count;
+}
+
+static DEVICE_ATTR(cal, S_IRUGO | S_IWUSR, retu_rtc_cal_show,
+ retu_rtc_cal_store);
+
+static struct device_driver retu_rtc_driver;
+
+static void retu_rtca_disable(void)
+{
+ retu_disable_irq(RETU_INT_RTCA);
+ retu_rtc_alarm_expired = 1;
+ retu_rtc_barrier();
+ retu_write_reg(RETU_REG_RTCHMAR, (24 << 8) | 60);
+}
+
+static void retu_rtca_expired(void *data)
+{
+ retu_rtca_disable();
+ kobject_uevent(&retu_rtc_driver.kobj, KOBJ_CHANGE);
+}
+
+DECLARE_WORK(retu_rtca_work, retu_rtca_expired, NULL);
+
+/*
+ * RTCHMR RTCHMAR RTCCAL must be accessed within 0.9 s since the seconds
+ * interrupt has been signaled in the IDR register
+ */
+static void retu_rtcs_interrupt(unsigned long unused)
+{
+ retu_ack_irq(RETU_INT_RTCS);
+ complete(&retu_rtc_sync);
+}
+
+static void retu_rtca_interrupt(unsigned long unused)
+{
+ retu_ack_irq(RETU_INT_RTCA);
+ schedule_work(&retu_rtca_work);
+}
+
+static int retu_rtc_init_irq(void)
+{
+ int ret;
+
+ ret = retu_request_irq(RETU_INT_RTCS, retu_rtcs_interrupt, 0, "RTCS");
+ if (ret != 0)
+ return ret;
+ /*
+ * We will take care of enabling and disabling the interrupt
+ * elsewhere, so leave it off by default..
+ */
+ retu_disable_irq(RETU_INT_RTCS);
+
+ ret = retu_request_irq(RETU_INT_RTCA, retu_rtca_interrupt, 0, "RTCA");
+ if (ret != 0) {
+ retu_free_irq(RETU_INT_RTCS);
+ return ret;
+ }
+ retu_disable_irq(RETU_INT_RTCA);
+
+ return 0;
+}
+
+
+static int __devinit retu_rtc_probe(struct device *dev)
+{
+ int r;
+
+ retu_rtc_alarm_expired = retu_read_reg(RETU_REG_IDR) &
+ (0x1 << RETU_INT_RTCA);
+
+ if ((r = retu_rtc_init_irq()) != 0)
+ return r;
+
+ init_MUTEX(&retu_rtc_sem);
+
+ /* If the calibration register is zero, we've probably lost
+ * power */
+ if (retu_read_reg(RETU_REG_RTCCALR) & 0x00ff)
+ retu_rtc_reset_occurred = 0;
+ else
+ retu_rtc_do_reset();
+
+ if ((r = device_create_file(dev, &dev_attr_time)) != 0)
+ return r;
+ else if ((r = device_create_file(dev, &dev_attr_reset)) != 0)
+ goto err_unregister_time;
+ else if ((r = device_create_file(dev, &dev_attr_alarm)) != 0)
+ goto err_unregister_reset;
+ else if ((r = device_create_file(dev, &dev_attr_alarm_expired)) != 0)
+ goto err_unregister_alarm;
+ else if ((r = device_create_file(dev, &dev_attr_cal)) != 0)
+ goto err_unregister_alarm_expired;
+ else
+ return r;
+
+err_unregister_alarm_expired:
+ device_remove_file(dev, &dev_attr_alarm_expired);
+err_unregister_alarm:
+ device_remove_file(dev, &dev_attr_alarm);
+err_unregister_reset:
+ device_remove_file(dev, &dev_attr_reset);
+err_unregister_time:
+ device_remove_file(dev, &dev_attr_time);
+ return r;
+}
+
+static int __devexit retu_rtc_remove(struct device *dev)
+{
+ retu_disable_irq(RETU_INT_RTCS);
+ retu_free_irq(RETU_INT_RTCS);
+ retu_free_irq(RETU_INT_RTCA);
+ device_remove_file(dev, &dev_attr_cal);
+ device_remove_file(dev, &dev_attr_alarm_expired);
+ device_remove_file(dev, &dev_attr_alarm);
+ device_remove_file(dev, &dev_attr_reset);
+ device_remove_file(dev, &dev_attr_time);
+ return 0;
+}
+
+static struct device_driver retu_rtc_driver = {
+ .name = "retu-rtc",
+ .bus = &platform_bus_type,
+ .probe = retu_rtc_probe,
+ .remove = __devexit_p(retu_rtc_remove),
+};
+
+static struct platform_device retu_rtc_device = {
+ .name = "retu-rtc",
+ .id = -1,
+ .dev = {
+ .release = retu_rtc_device_release,
+ },
+};
+
+/* This function provides syncronization with the RTCS interrupt handler */
+static void retu_rtc_barrier(void)
+{
+ init_completion(&retu_rtc_sync);
+ retu_ack_irq(RETU_INT_RTCS);
+ retu_enable_irq(RETU_INT_RTCS);
+ wait_for_completion(&retu_rtc_sync);
+ retu_disable_irq(RETU_INT_RTCS);
+}
+
+static int __init retu_rtc_init(void)
+{
+ int ret;
+
+ init_completion(&retu_rtc_exited);
+
+ if ((ret = driver_register(&retu_rtc_driver)) != 0)
+ return ret;
+
+ if ((ret = platform_device_register(&retu_rtc_device)) != 0)
+ goto err_unregister_driver;
+
+ return 0;
+
+err_unregister_driver:
+ driver_unregister(&retu_rtc_driver);
+ return ret;
+}
+
+static void __exit retu_rtc_exit(void)
+{
+ platform_device_unregister(&retu_rtc_device);
+ driver_unregister(&retu_rtc_driver);
+
+ wait_for_completion(&retu_rtc_exited);
+}
+
+module_init(retu_rtc_init);
+module_exit(retu_rtc_exit);
+
+MODULE_DESCRIPTION("Retu RTC");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Paul Mundt and Igor Stoppa");
--- /dev/null
+/**
+ * drivers/cbus/retu-user.c
+ *
+ * Retu user space interface functions
+ *
+ * Copyright (C) 2004, 2005 Nokia Corporation
+ *
+ * Written by Mikko Ylinen <mikko.k.ylinen@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.
+ *
+ * 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/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+#include <asm/uaccess.h>
+
+#include "retu.h"
+
+#include "user_retu_tahvo.h"
+
+/* Maximum size of IRQ node buffer/pool */
+#define RETU_MAX_IRQ_BUF_LEN 16
+
+#define PFX "retu-user: "
+
+/* Bitmap for marking the interrupt sources as having the handlers */
+static u32 retu_irq_bits;
+
+/* For allowing only one user process to subscribe to the retu interrupts */
+static struct file *retu_irq_subscr = NULL;
+
+/* For poll and IRQ passing */
+struct retu_irq {
+ u32 id;
+ struct list_head node;
+};
+
+static spinlock_t retu_irqs_lock;
+static struct retu_irq *retu_irq_block;
+static LIST_HEAD(retu_irqs);
+static LIST_HEAD(retu_irqs_reserve);
+
+/* Wait queue - used when user wants to read the device */
+DECLARE_WAIT_QUEUE_HEAD(retu_user_waitqueue);
+
+/* Semaphore to protect irq subscription sequence */
+static struct semaphore retu_sem;
+
+/* This array specifies RETU register types (read/write/toggle) */
+static const u8 retu_access_bits[] = {
+ 1,
+ 4,
+ 3,
+ 3,
+ 1,
+ 3,
+ 3,
+ 0,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 4,
+ 4,
+ 3,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3
+};
+
+/*
+ * The handler for all RETU interrupts.
+ *
+ * arg is the interrupt source in RETU.
+ */
+static void retu_user_irq_handler(unsigned long arg)
+{
+ struct retu_irq *irq;
+
+ retu_ack_irq(arg);
+
+ spin_lock(&retu_irqs_lock);
+ if (list_empty(&retu_irqs_reserve)) {
+ spin_unlock(&retu_irqs_lock);
+ return;
+ }
+ irq = list_entry((&retu_irqs_reserve)->next, struct retu_irq, node);
+ irq->id = arg;
+ list_move_tail(&irq->node, &retu_irqs);
+ spin_unlock(&retu_irqs_lock);
+
+ /* wake up waiting thread */
+ wake_up(&retu_user_waitqueue);
+}
+
+/*
+ * This routine sets up the interrupt handler and marks an interrupt source
+ * in RETU as a candidate for signal delivery to the user process.
+ */
+static int retu_user_subscribe_to_irq(int id, struct file *filp)
+{
+ int ret;
+
+ down(&retu_sem);
+ if ((retu_irq_subscr != NULL) && (retu_irq_subscr != filp)) {
+ up(&retu_sem);
+ return -EBUSY;
+ }
+ /* Store the file pointer of the first user process registering IRQs */
+ retu_irq_subscr = filp;
+ up(&retu_sem);
+
+ if (retu_irq_bits & (1 << id))
+ return 0;
+
+ ret = retu_request_irq(id, retu_user_irq_handler, id, "");
+ if (ret < 0)
+ return ret;
+
+ /* Mark that this interrupt has a handler */
+ retu_irq_bits |= 1 << id;
+
+ return 0;
+}
+
+/*
+ * Unregisters all RETU interrupt handlers.
+ */
+static void retu_unreg_irq_handlers(void)
+{
+ int id;
+
+ if (!retu_irq_bits)
+ return;
+
+ for (id = 0; id < MAX_RETU_IRQ_HANDLERS; id++)
+ if (retu_irq_bits & (1 << id))
+ retu_free_irq(id);
+
+ retu_irq_bits = 0;
+}
+
+/*
+ * Write to RETU register.
+ * Returns 0 upon success, a negative error value otherwise.
+ */
+static int retu_user_write_with_mask(u32 field, u16 value)
+{
+ u32 mask;
+ u32 reg;
+ u_short tmp;
+ unsigned long flags;
+
+ mask = MASK(field);
+ reg = REG(field);
+
+ /* Detect bad mask and reg */
+ if (mask == 0 || reg > RETU_REG_MAX ||
+ retu_access_bits[reg] == READ_ONLY) {
+ printk(KERN_ERR PFX "invalid arguments (reg=%#x, mask=%#x)\n",
+ reg, mask);
+ return -EINVAL;
+ }
+
+ /* Justify value according to mask */
+ while (!(mask & 1)) {
+ value = value << 1;
+ mask = mask >> 1;
+ }
+
+ spin_lock_irqsave(&retu_lock, flags);
+ if (retu_access_bits[reg] == TOGGLE) {
+ /* No need to detect previous content of register */
+ tmp = 0;
+ } else {
+ /* Read current value of register */
+ tmp = retu_read_reg(reg);
+ }
+
+ /* Generate new value */
+ tmp = (tmp & ~MASK(field)) | (value & MASK(field));
+ /* Write data to RETU */
+ retu_write_reg(reg, tmp);
+ spin_unlock_irqrestore(&retu_lock, flags);
+
+ return 0;
+}
+
+/*
+ * Read RETU register.
+ */
+static u32 retu_user_read_with_mask(u32 field)
+{
+ u_short value;
+ u32 mask, reg;
+
+ mask = MASK(field);
+ reg = REG(field);
+
+ /* Detect bad mask and reg */
+ if (mask == 0 || reg > RETU_REG_MAX) {
+ printk(KERN_ERR PFX "invalid arguments (reg=%#x, mask=%#x)\n",
+ reg, mask);
+ return -EINVAL;
+ }
+
+ /* Read the register */
+ value = retu_read_reg(reg) & mask;
+
+ /* Right justify value */
+ while (!(mask & 1)) {
+ value = value >> 1;
+ mask = mask >> 1;
+ }
+
+ return value;
+}
+
+/*
+ * Close device
+ */
+static int retu_close(struct inode *inode, struct file *filp)
+{
+ /* Unregister all interrupts that have been registered */
+ if (retu_irq_subscr == filp) {
+ retu_unreg_irq_handlers();
+ retu_irq_subscr = NULL;
+ }
+
+ return 0;
+}
+
+/*
+ * Device control (ioctl)
+ */
+static int retu_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ struct retu_tahvo_write_parms par;
+
+ switch (cmd) {
+ case URT_IOCT_IRQ_SUBSCR:
+ return retu_user_subscribe_to_irq(arg, filp);
+ case RETU_IOCH_READ:
+ return retu_user_read_with_mask(arg);
+ case RETU_IOCX_WRITE:
+ copy_from_user(&par, (void __user *) arg, sizeof(par));
+ par.result = retu_user_write_with_mask(par.field, par.value);
+ copy_to_user((void __user *) arg, &par, sizeof(par));
+ break;
+ case RETU_IOCH_ADC_READ:
+ return retu_read_adc(arg);
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+/*
+ * Read from device
+ */
+static ssize_t retu_read(struct file *filp, char *buf, size_t count,
+ loff_t * offp)
+{
+ struct retu_irq *irq;
+
+ u32 nr, i;
+
+ /* read not permitted if neither filp nor anyone has registered IRQs */
+ if (retu_irq_subscr != filp)
+ return -EPERM;
+
+ if ((count < sizeof(u32)) || ((count % sizeof(u32)) != 0))
+ return -EINVAL;
+
+ nr = count / sizeof(u32);
+
+ for (i = 0; i < nr; i++) {
+ unsigned long flags;
+ u32 irq_id;
+ int ret;
+
+ ret = wait_event_interruptible(retu_user_waitqueue,
+ !list_empty(&retu_irqs));
+ if (ret < 0)
+ return ret;
+
+ spin_lock_irqsave(&retu_irqs_lock, flags);
+ irq = list_entry((&retu_irqs)->next, struct retu_irq, node);
+ irq_id = irq->id;
+ list_move(&irq->node, &retu_irqs_reserve);
+ spin_unlock_irqrestore(&retu_irqs_lock, flags);
+
+ copy_to_user(buf + i * sizeof(irq_id), &irq_id, sizeof(irq_id));
+
+ }
+
+ return count;
+}
+
+/*
+ * Poll method
+ */
+static unsigned retu_poll(struct file *filp, struct poll_table_struct *pt)
+{
+ if (!list_empty(&retu_irqs))
+ return POLLIN;
+
+ poll_wait(filp, &retu_user_waitqueue, pt);
+
+ if (!list_empty(&retu_irqs))
+ return POLLIN;
+ else
+ return 0;
+}
+
+static struct file_operations retu_user_fileops = {
+ .owner = THIS_MODULE,
+ .ioctl = retu_ioctl,
+ .read = retu_read,
+ .release = retu_close,
+ .poll = retu_poll
+};
+
+static struct miscdevice retu_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "retu",
+ .fops = &retu_user_fileops
+};
+
+/*
+ * Initialization
+ *
+ * @return 0 if successful, error value otherwise.
+ */
+int retu_user_init(void)
+{
+ struct retu_irq *irq;
+ int res, i;
+
+ irq = kmalloc(sizeof(*irq) * RETU_MAX_IRQ_BUF_LEN, GFP_KERNEL);
+ if (irq == NULL) {
+ printk(KERN_ERR PFX "kmalloc failed\n");
+ return -ENOMEM;
+ }
+ memset(irq, 0, sizeof(*irq) * RETU_MAX_IRQ_BUF_LEN);
+ for (i = 0; i < RETU_MAX_IRQ_BUF_LEN; i++)
+ list_add(&irq[i].node, &retu_irqs_reserve);
+
+ retu_irq_block = irq;
+
+ spin_lock_init(&retu_irqs_lock);
+ sema_init(&retu_sem, 1);
+
+ /* Request a misc device */
+ res = misc_register(&retu_device);
+ if (res < 0) {
+ printk(KERN_ERR PFX "unable to register misc device for %s\n",
+ retu_device.name);
+ kfree(irq);
+ return res;
+ }
+
+ return 0;
+}
+
+/*
+ * Cleanup.
+ */
+void retu_user_cleanup(void)
+{
+ /* Unregister our misc device */
+ misc_deregister(&retu_device);
+ /* Unregister and disable all RETU interrupts used by this module */
+ retu_unreg_irq_handlers();
+ kfree(retu_irq_block);
+}
+
+MODULE_DESCRIPTION("Retu ASIC user space functions");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mikko Ylinen");
--- /dev/null
+/**
+ * drivers/cbus/retu-wdt.c
+ *
+ * Driver for Retu watchdog
+ *
+ * Copyright (C) 2004, 2005 Nokia Corporation
+ *
+ * Written by Amit Kucheria <amit.kucheria@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.
+ *
+ * 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/device.h>
+#include <linux/init.h>
+
+#include <linux/completion.h>
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+
+#include "cbus.h"
+#include "retu.h"
+
+/* Watchdog timeout in seconds */
+#define RETU_WDT_MIN_TIMER 0
+#define RETU_WDT_DEFAULT_TIMER 32
+#define RETU_WDT_MAX_TIMER 63
+
+static struct completion retu_wdt_completion;
+static DECLARE_MUTEX(retu_wdt_mutex); /* Avoid simultaneous writes to watchdog register */
+
+static unsigned int period_val = RETU_WDT_DEFAULT_TIMER; /* Current period of watchdog */
+static int counter_param = RETU_WDT_MAX_TIMER;
+
+static int retu_modify_counter(unsigned int new)
+{
+ int ret = 0;
+
+ if (new < RETU_WDT_MIN_TIMER || new > RETU_WDT_MAX_TIMER)
+ return -EINVAL;
+
+ down_interruptible(&retu_wdt_mutex);
+
+ period_val = new;
+ retu_write_reg(RETU_REG_WATCHDOG, (u16)period_val);
+
+ up(&retu_wdt_mutex);
+ return ret;
+}
+
+static ssize_t retu_wdt_period_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ /* Show current max counter */
+ return sprintf(buf, "%u\n", (u16)period_val);
+}
+
+static ssize_t retu_wdt_period_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned int new_period;
+ int ret;
+
+ if (sscanf(buf, "%u", &new_period) != 1) {
+ printk(KERN_ALERT "retu_wdt_period_store: Invalid input\n");
+ return -EINVAL;
+ }
+
+ ret = retu_modify_counter(new_period);
+ if (ret < 0)
+ return ret;
+
+ return strnlen(buf, count);
+}
+
+static ssize_t retu_wdt_counter_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ u16 counter;
+
+ /* Show current value in watchdog counter */
+ counter = retu_read_reg(RETU_REG_WATCHDOG);
+
+ /* Only the 5 LSB are important */
+ return snprintf(buf, PAGE_SIZE, "%u\n", (counter & 0x3F));
+}
+
+static DEVICE_ATTR(period, S_IRUGO | S_IWUSR, retu_wdt_period_show, \
+ retu_wdt_period_store);
+static DEVICE_ATTR(counter, S_IRUGO, retu_wdt_counter_show, NULL);
+
+static int __devinit retu_wdt_probe(struct device *dev)
+{
+ int ret;
+
+ ret = device_create_file(dev, &dev_attr_period);
+ if (ret) {
+ printk(KERN_ERR "retu_wdt_probe: Error creating sys device file: period\n");
+ return ret;
+ }
+
+ ret = device_create_file(dev, &dev_attr_counter);
+ if (ret) {
+ device_remove_file(dev, &dev_attr_period);
+ printk(KERN_ERR "retu_wdt_probe: Error creating sys device file: counter\n");
+ }
+
+ return ret;
+}
+
+static int __devexit retu_wdt_remove(struct device *dev)
+{
+ device_remove_file(dev, &dev_attr_period);
+ device_remove_file(dev, &dev_attr_counter);
+ return 0;
+}
+
+static void retu_wdt_device_release(struct device *dev)
+{
+ complete(&retu_wdt_completion);
+}
+
+static struct platform_device retu_wdt_device = {
+ .name = "retu-watchdog",
+ .id = -1,
+ .dev = {
+ .release = retu_wdt_device_release,
+ },
+};
+
+static struct device_driver retu_wdt_driver = {
+ .name = "retu-watchdog",
+ .bus = &platform_bus_type,
+ .probe = retu_wdt_probe,
+ .remove = __devexit_p(retu_wdt_remove),
+};
+
+static int __init retu_wdt_init(void)
+{
+ int ret;
+
+ init_completion(&retu_wdt_completion);
+
+ ret = driver_register(&retu_wdt_driver);
+ if (ret)
+ return ret;
+
+ ret = platform_device_register(&retu_wdt_device);
+ if (ret)
+ goto exit1;
+
+ /* passed as module parameter? */
+ ret = retu_modify_counter(counter_param);
+ if (ret == -EINVAL) {
+ ret = retu_modify_counter(RETU_WDT_DEFAULT_TIMER);
+ printk(KERN_INFO
+ "retu_wdt_init: Intializing to default value\n");
+ }
+
+ printk(KERN_INFO "Retu watchdog driver initialized\n");
+ return ret;
+
+exit1:
+ driver_unregister(&retu_wdt_driver);
+ wait_for_completion(&retu_wdt_completion);
+
+ return ret;
+}
+
+static void __exit retu_wdt_exit(void)
+{
+ platform_device_unregister(&retu_wdt_device);
+ driver_unregister(&retu_wdt_driver);
+
+ wait_for_completion(&retu_wdt_completion);
+}
+
+module_init(retu_wdt_init);
+module_exit(retu_wdt_exit);
+module_param(counter_param, int, 0);
+
+MODULE_DESCRIPTION("Retu WatchDog");
+MODULE_AUTHOR("Amit Kucheria");
+MODULE_LICENSE("GPL");
+
--- /dev/null
+/**
+ * drivers/cbus/retu.c
+ *
+ * Support functions for Retu ASIC
+ *
+ * Copyright (C) 2004, 2005 Nokia Corporation
+ *
+ * Written by Juha Yrjölä <juha.yrjola@nokia.com>,
+ * David Weinehall <david.weinehall@nokia.com>, and
+ * Mikko Ylinen <mikko.k.ylinen@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.
+ *
+ * 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/init.h>
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <asm/uaccess.h>
+
+#include <asm/arch/mux.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/board.h>
+
+#include "cbus.h"
+#include "retu.h"
+
+#define RETU_ID 0x01
+#define PFX "retu: "
+
+static int retu_initialized;
+static int retu_irq_pin;
+static int retu_is_vilma;
+
+static struct tasklet_struct retu_tasklet;
+spinlock_t retu_lock = SPIN_LOCK_UNLOCKED;
+
+static struct completion device_release;
+
+struct retu_irq_handler_desc {
+ int (*func)(unsigned long);
+ unsigned long arg;
+ char name[8];
+};
+
+static struct retu_irq_handler_desc retu_irq_handlers[MAX_RETU_IRQ_HANDLERS];
+
+/**
+ * retu_read_reg - Read a value from a register in Retu
+ * @reg: the register to read from
+ *
+ * This function returns the contents of the specified register
+ */
+int retu_read_reg(int reg)
+{
+ BUG_ON(!retu_initialized);
+ return cbus_read_reg(cbus_host, RETU_ID, reg);
+}
+
+/**
+ * retu_write_reg - Write a value to a register in Retu
+ * @reg: the register to write to
+ * @reg: the value to write to the register
+ *
+ * This function writes a value to the specified register
+ */
+void retu_write_reg(int reg, u16 val)
+{
+ BUG_ON(!retu_initialized);
+ cbus_write_reg(cbus_host, RETU_ID, reg, val);
+}
+
+#define ADC_MAX_CHAN_NUMBER 13
+
+int retu_read_adc(int channel)
+{
+ unsigned long flags;
+ int res;
+
+ if (channel < 0 || channel > ADC_MAX_CHAN_NUMBER)
+ return -EINVAL;
+
+ spin_lock_irqsave(&retu_lock, flags);
+ /* Select the channel and read result */
+ retu_write_reg(RETU_REG_ADCR, channel << 10);
+ res = retu_read_reg(RETU_REG_ADCR) & 0x3ff;
+ /* Unlock retu */
+ spin_unlock_irqrestore(&retu_lock, flags);
+
+ return res;
+}
+
+
+static u16 retu_disable_bogus_irqs(u16 mask)
+{
+ int i;
+
+ for (i = 0; i < MAX_RETU_IRQ_HANDLERS; i++) {
+ if (mask & (1 << i))
+ continue;
+ if (retu_irq_handlers[i].func != NULL)
+ continue;
+ /* an IRQ was enabled but we don't have a handler for it */
+ printk(KERN_INFO PFX "disabling bogus IRQ %d\n", i);
+ mask |= (1 << i);
+ }
+ return mask;
+}
+
+/*
+ * Disable given RETU interrupt
+ */
+void retu_disable_irq(int id)
+{
+ unsigned long flags;
+ u16 mask;
+
+ spin_lock_irqsave(&retu_lock, flags);
+ mask = retu_read_reg(RETU_REG_IMR);
+ mask |= 1 << id;
+ mask = retu_disable_bogus_irqs(mask);
+ retu_write_reg(RETU_REG_IMR, mask);
+ spin_unlock_irqrestore(&retu_lock, flags);
+}
+
+/*
+ * Enable given RETU interrupt
+ */
+void retu_enable_irq(int id)
+{
+ unsigned long flags;
+ u16 mask;
+
+ if (id == 3) {
+ printk("Enabling Retu IRQ %d\n", id);
+ dump_stack();
+ }
+ spin_lock_irqsave(&retu_lock, flags);
+ mask = retu_read_reg(RETU_REG_IMR);
+ mask &= ~(1 << id);
+ mask = retu_disable_bogus_irqs(mask);
+ retu_write_reg(RETU_REG_IMR, mask);
+ spin_unlock_irqrestore(&retu_lock, flags);
+}
+
+/*
+ * Acknowledge given RETU interrupt
+ */
+void retu_ack_irq(int id)
+{
+ retu_write_reg(RETU_REG_IDR, 1 << id);
+}
+
+/*
+ * RETU interrupt handler. Only schedules the tasklet.
+ */
+static irqreturn_t retu_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+ tasklet_schedule(&retu_tasklet);
+ return IRQ_HANDLED;
+}
+
+/*
+ * Tasklet handler
+ */
+static void retu_tasklet_handler(unsigned long data)
+{
+ struct retu_irq_handler_desc *hnd;
+ u16 id;
+ u16 im;
+ int i;
+
+ for (;;) {
+ id = retu_read_reg(RETU_REG_IDR);
+ im = ~retu_read_reg(RETU_REG_IMR);
+ id &= im;
+
+ if (!id)
+ break;
+
+ for (i = 0; id != 0; i++, id >>= 1) {
+ if (!(id & 1))
+ continue;
+ hnd = &retu_irq_handlers[i];
+ if (hnd->func == NULL) {
+ /* Spurious retu interrupt - disable and ack it */
+ printk(KERN_INFO "Spurious Retu interrupt "
+ "(id %d)\n", i);
+ retu_disable_irq(i);
+ retu_ack_irq(i);
+ continue;
+ }
+ hnd->func(hnd->arg);
+ /*
+ * Don't acknowledge the interrupt here
+ * It must be done explicitly
+ */
+ }
+ }
+}
+
+/*
+ * Register the handler for a given RETU interrupt source.
+ */
+int retu_request_irq(int id, void *irq_handler, unsigned long arg, char *name)
+{
+ struct retu_irq_handler_desc *hnd;
+
+ if (irq_handler == NULL || id >= MAX_RETU_IRQ_HANDLERS ||
+ name == NULL) {
+ printk(KERN_ERR PFX "Invalid arguments to %s\n",
+ __FUNCTION__);
+ return -EINVAL;
+ }
+ hnd = &retu_irq_handlers[id];
+ if (hnd->func != NULL) {
+ printk(KERN_ERR PFX "IRQ %d already reserved\n", id);
+ return -EBUSY;
+ }
+ printk(KERN_INFO PFX "Registering interrupt %d for device %s\n",
+ id, name);
+ hnd->func = irq_handler;
+ hnd->arg = arg;
+ strlcpy(hnd->name, name, sizeof(hnd->name));
+
+ retu_ack_irq(id);
+ retu_enable_irq(id);
+
+ return 0;
+}
+
+/*
+ * Unregister the handler for a given RETU interrupt source.
+ */
+void retu_free_irq(int id)
+{
+ struct retu_irq_handler_desc *hnd;
+
+ if (id >= MAX_RETU_IRQ_HANDLERS) {
+ printk(KERN_ERR PFX "Invalid argument to %s\n",
+ __FUNCTION__);
+ return;
+ }
+ hnd = &retu_irq_handlers[id];
+ if (hnd->func == NULL) {
+ printk(KERN_ERR PFX "IRQ %d already freed\n", id);
+ return;
+ }
+
+ retu_disable_irq(id);
+ hnd->func = NULL;
+}
+
+/**
+ * retu_power_off - Shut down power to system
+ *
+ * This function puts the system in power off state
+ */
+static void retu_power_off(void)
+{
+ /* Ignore power button state */
+ retu_write_reg(RETU_REG_CC1, retu_read_reg(RETU_REG_CC1) | 2);
+ /* Expire watchdog immediately */
+ retu_write_reg(RETU_REG_WATCHDOG, 0);
+ /* Wait for poweroff*/
+ for (;;);
+}
+
+/**
+ * retu_probe - Probe for Retu ASIC
+ * @dev: the Retu device
+ *
+ * Probe for the Retu ASIC and allocate memory
+ * for its device-struct if found
+ */
+static int __devinit retu_probe(struct device *dev)
+{
+ const struct omap_em_asic_bb5_config * em_asic_config;
+ int rev, ret;
+
+ /* Prepare tasklet */
+ tasklet_init(&retu_tasklet, retu_tasklet_handler, 0);
+
+ em_asic_config = omap_get_config(OMAP_TAG_EM_ASIC_BB5,
+ struct omap_em_asic_bb5_config);
+ if (em_asic_config == NULL) {
+ printk(KERN_ERR PFX "Unable to retrieve config data\n");
+ return -ENODATA;
+ }
+
+ retu_irq_pin = em_asic_config->retu_irq_gpio;
+
+ if ((ret = omap_request_gpio(retu_irq_pin)) < 0) {
+ printk(KERN_ERR PFX "Unable to reserve IRQ GPIO\n");
+ return ret;
+ }
+
+ /* Set the pin as input */
+ omap_set_gpio_direction(retu_irq_pin, 1);
+
+ /* Rising edge triggers the IRQ */
+ set_irq_type(OMAP_GPIO_IRQ(retu_irq_pin), IRQT_RISING);
+
+ retu_initialized = 1;
+
+ rev = retu_read_reg(RETU_REG_ASICR) & 0xff;
+ if (rev & (1 << 7))
+ retu_is_vilma = 1;
+
+ printk(KERN_INFO "%s v%d.%d found\n", retu_is_vilma ? "Vilma" : "Retu",
+ (rev >> 4) & 0x07, rev & 0x0f);
+
+ /* Mask all RETU interrupts */
+ retu_write_reg(RETU_REG_IMR, 0xffff);
+
+ ret = request_irq(OMAP_GPIO_IRQ(retu_irq_pin), retu_irq_handler, 0,
+ "retu", 0);
+
+ if (ret < 0) {
+ printk(KERN_ERR PFX "Unable to register IRQ handler\n");
+ omap_free_gpio(retu_irq_pin);
+ return ret;
+ }
+
+ /* Register power off function */
+ pm_power_off = retu_power_off;
+
+#ifdef CONFIG_CBUS_RETU_USER
+ /* Initialize user-space interface */
+ if (retu_user_init() < 0) {
+ printk(KERN_ERR "Unable to initialize driver\n");
+ free_irq(OMAP_GPIO_IRQ(retu_irq_pin), 0);
+ omap_free_gpio(retu_irq_pin);
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+
+static int retu_remove(struct device *dev)
+{
+#ifdef CONFIG_CBUS_RETU_USER
+ retu_user_cleanup();
+#endif
+ /* Mask all RETU interrupts */
+ retu_write_reg(RETU_REG_IMR, 0xffff);
+ free_irq(OMAP_GPIO_IRQ(retu_irq_pin), 0);
+ omap_free_gpio(retu_irq_pin);
+ tasklet_kill(&retu_tasklet);
+
+ return 0;
+}
+
+static void retu_device_release(struct device *dev)
+{
+ complete(&device_release);
+}
+
+static struct device_driver retu_driver = {
+ .name = "retu",
+ .bus = &platform_bus_type,
+ .probe = retu_probe,
+ .remove = retu_remove,
+};
+
+static struct platform_device retu_device = {
+ .name = "retu",
+ .id = -1,
+ .dev = {
+ .release = retu_device_release,
+ }
+};
+
+/**
+ * retu_init - initialise Retu driver
+ *
+ * Initialise the Retu driver and return 0 if everything worked ok
+ */
+static int __init retu_init(void)
+{
+ int ret = 0;
+
+ printk(KERN_INFO "Retu/Vilma driver initialising\n");
+
+ init_completion(&device_release);
+
+ if ((ret = driver_register(&retu_driver)) < 0)
+ return ret;
+
+ if ((ret = platform_device_register(&retu_device)) < 0) {
+ driver_unregister(&retu_driver);
+ return ret;
+ }
+ return 0;
+}
+
+/*
+ * Cleanup
+ */
+static void __exit retu_exit(void)
+{
+ platform_device_unregister(&retu_device);
+ driver_unregister(&retu_driver);
+ wait_for_completion(&device_release);
+}
+
+EXPORT_SYMBOL(retu_request_irq);
+EXPORT_SYMBOL(retu_free_irq);
+EXPORT_SYMBOL(retu_enable_irq);
+EXPORT_SYMBOL(retu_disable_irq);
+EXPORT_SYMBOL(retu_ack_irq);
+EXPORT_SYMBOL(retu_read_reg);
+EXPORT_SYMBOL(retu_write_reg);
+
+subsys_initcall(retu_init);
+module_exit(retu_exit);
+
+MODULE_DESCRIPTION("Retu ASIC control");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Juha Yrjölä, David Weinehall, and Mikko Ylinen");
--- /dev/null
+/**
+ * drivers/cbus/retu.h
+ *
+ * Copyright (C) 2004, 2005 Nokia Corporation
+ *
+ * Written by Juha Yrjölä <juha.yrjola@nokia.com> and
+ * David Weinehall <david.weinehall@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.
+ *
+ * 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 __DRIVERS_CBUS_RETU_H
+#define __DRIVERS_CBUS_RETU_H
+
+#include <linux/types.h>
+
+/* Registers */
+#define RETU_REG_ASICR 0x00 /* ASIC ID & revision */
+#define RETU_REG_IDR 0x01 /* Interrupt ID */
+#define RETU_REG_IMR 0x02 /* Interrupt mask */
+#define RETU_REG_RTCDSR 0x03 /* RTC seconds register */
+#define RETU_REG_RTCHMR 0x04 /* RTC hours and minutes register */
+#define RETU_REG_RTCHMAR 0x05 /* RTC hours and minutes alarm and time set register */
+#define RETU_REG_RTCCALR 0x06 /* RTC calibration register */
+#define RETU_REG_ADCR 0x08 /* ADC result */
+#define RETU_REG_CC1 0x0d /* Common control register 1 */
+#define RETU_REG_CC2 0x0e /* Common control register 2 */
+#define RETU_REG_CTRL_CLR 0x0f /* Regulator clear register */
+#define RETU_REG_CTRL_SET 0x10 /* Regulator set register */
+#define RETU_REG_STATUS 0x16 /* Status register */
+#define RETU_REG_WATCHDOG 0x17 /* Watchdog register */
+#define RETU_REG_MAX 0x1f
+
+/* Interrupt sources */
+#define RETU_INT_PWR 0
+#define RETU_INT_CHAR 1
+#define RETU_INT_RTCS 2
+#define RETU_INT_RTCM 3
+#define RETU_INT_RTCD 4
+#define RETU_INT_RTCA 5
+#define RETU_INT_ADCS 8
+
+#define MAX_RETU_IRQ_HANDLERS 16
+
+int retu_read_reg(int reg);
+void retu_write_reg(int reg, u16 val);
+int retu_read_adc(int channel);
+int retu_request_irq(int id, void *irq_handler, unsigned long arg, char *name);
+void retu_free_irq(int id);
+void retu_enable_irq(int id);
+void retu_disable_irq(int id);
+void retu_ack_irq(int id);
+
+#ifdef CONFIG_CBUS_RETU_USER
+int retu_user_init(void);
+void retu_user_cleanup(void);
+#endif
+
+extern spinlock_t retu_lock;
+
+#endif /* __DRIVERS_CBUS_RETU_H */
--- /dev/null
+/**
+ * drivers/cbus/tahvo-usb.c
+ *
+ * Tahvo USB transeiver
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ *
+ * Written by Juha Yrjölä <juha.yrjola@nokia.com>,
+ * Tony Lindgren <tony@atomide.com>, and
+ * Timo Teräs <timo.teras@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.
+ *
+ * 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/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+#include <linux/usb.h>
+#include <linux/usb_otg.h>
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+#include <linux/kobject.h>
+#include <linux/clk.h>
+
+#include <asm/irq.h>
+#include <asm/semaphore.h>
+#include <asm/arch/usb.h>
+
+#include "cbus.h"
+#include "tahvo.h"
+
+#define DRIVER_NAME "tahvo-usb"
+
+#define USBR_SLAVE_CONTROL (1 << 8)
+#define USBR_VPPVIO_SW (1 << 7)
+#define USBR_SPEED (1 << 6)
+#define USBR_REGOUT (1 << 5)
+#define USBR_MASTER_SW2 (1 << 4)
+#define USBR_MASTER_SW1 (1 << 3)
+#define USBR_SLAVE_SW (1 << 2)
+#define USBR_NSUSPEND (1 << 1)
+#define USBR_SEMODE (1 << 0)
+
+/* bits in OTG_CTRL_REG */
+
+/* Bits that are controlled by OMAP OTG and are read-only */
+#define OTG_CTRL_OMAP_MASK (OTG_PULLDOWN|OTG_PULLUP|OTG_DRV_VBUS|\
+ OTG_PD_VBUS|OTG_PU_VBUS|OTG_PU_ID)
+/* Bits that are controlled by transceiver */
+#define OTG_CTRL_XCVR_MASK (OTG_ASESSVLD|OTG_BSESSEND|\
+ OTG_BSESSVLD|OTG_VBUSVLD|OTG_ID)
+/* Bits that are controlled by system */
+#define OTG_CTRL_SYS_MASK (OTG_A_BUSREQ|OTG_A_SETB_HNPEN|OTG_B_BUSREQ|\
+ OTG_B_HNPEN|OTG_BUSDROP)
+
+#if defined(CONFIG_USB_OHCI_HCD) && !defined(CONFIG_USB_OTG)
+#error tahvo-otg.c does not work with OCHI yet!
+#endif
+
+#define TAHVO_MODE_HOST 0
+#define TAHVO_MODE_PERIPHERAL 1
+
+#ifdef CONFIG_USB_OTG
+#define TAHVO_MODE(tu) (tu)->tahvo_mode
+#elif defined(CONFIG_USB_GADGET_OMAP)
+#define TAHVO_MODE(tu) TAHVO_MODE_PERIPHERAL
+#else
+#define TAHVO_MODE(tu) TAHVO_MODE_HOST
+#endif
+
+extern int ohci_omap_host_enable(struct usb_bus *host, int enable);
+
+struct tahvo_usb {
+ struct platform_device *pt_dev;
+ struct otg_transceiver otg;
+ int vbus_state;
+ struct work_struct irq_work;
+ struct semaphore serialize;
+#ifdef CONFIG_USB_OTG
+ int tahvo_mode;
+#endif
+};
+static struct platform_device tahvo_usb_device;
+
+/*
+ * ---------------------------------------------------------------------------
+ * OTG related functions
+ *
+ * These shoud be separated into omap-otg.c driver module, as they are used
+ * by various transceivers. These functions are needed in the UDC-only case
+ * as well. These functions are copied from GPL isp1301_omap.c
+ * ---------------------------------------------------------------------------
+ */
+static struct platform_device *tahvo_otg_dev;
+
+static irqreturn_t omap_otg_irq(int irq, void *arg, struct pt_regs *regs)
+{
+ struct platform_device *otg_dev = (struct platform_device *) arg;
+ struct tahvo_usb *tu = (struct tahvo_usb *) otg_dev->dev.driver_data;
+ u16 otg_irq;
+
+ otg_irq = OTG_IRQ_SRC_REG;
+ if (otg_irq & OPRT_CHG) {
+ OTG_IRQ_SRC_REG = OPRT_CHG;
+ } else if (otg_irq & B_SRP_TMROUT) {
+ OTG_IRQ_SRC_REG = B_SRP_TMROUT;
+ } else if (otg_irq & B_HNP_FAIL) {
+ OTG_IRQ_SRC_REG = B_HNP_FAIL;
+ } else if (otg_irq & A_SRP_DETECT) {
+ OTG_IRQ_SRC_REG = A_SRP_DETECT;
+ } else if (otg_irq & A_REQ_TMROUT) {
+ OTG_IRQ_SRC_REG = A_REQ_TMROUT;
+ } else if (otg_irq & A_VBUS_ERR) {
+ OTG_IRQ_SRC_REG = A_VBUS_ERR;
+ } else if (otg_irq & DRIVER_SWITCH) {
+
+ if ((!(OTG_CTRL_REG & OTG_DRIVER_SEL)) &&
+ tu->otg.host && tu->otg.state == OTG_STATE_A_HOST) {
+ /* role is host */
+ usb_bus_start_enum(tu->otg.host,
+ tu->otg.host->otg_port);
+ }
+
+ OTG_IRQ_SRC_REG = DRIVER_SWITCH;
+ } else
+ return IRQ_NONE;
+
+ return IRQ_HANDLED;
+
+}
+
+static int omap_otg_init(void)
+{
+
+#ifdef CONFIG_USB_OTG
+ if (!tahvo_otg_dev) {
+ printk("tahvo-usb: no tahvo_otg_dev\n");
+ return -ENODEV;
+ }
+#endif
+
+ /* some of these values are board-specific... */
+ OTG_SYSCON_2_REG |= OTG_EN
+ /* for B-device: */
+ | SRP_GPDATA /* 9msec Bdev D+ pulse */
+ | SRP_GPDVBUS /* discharge after VBUS pulse */
+ // | (3 << 24) /* 2msec VBUS pulse */
+ /* for A-device: */
+ | (0 << 20) /* 200ms nominal A_WAIT_VRISE timer */
+ | SRP_DPW /* detect 167+ns SRP pulses */
+ | SRP_DATA | SRP_VBUS; /* accept both kinds of SRP pulse */
+
+ OTG_IRQ_EN_REG = DRIVER_SWITCH | OPRT_CHG
+ | B_SRP_TMROUT | B_HNP_FAIL
+ | A_VBUS_ERR | A_SRP_DETECT | A_REQ_TMROUT;
+ OTG_SYSCON_2_REG |= OTG_EN;
+
+ return 0;
+}
+
+static int omap_otg_probe(struct device *dev)
+{
+ int ret;
+
+ tahvo_otg_dev = to_platform_device(dev);
+ ret = omap_otg_init();
+ if (ret != 0) {
+ printk(KERN_ERR "tahvo-usb: omap_otg_init failed\n");
+ return ret;
+ }
+
+ return request_irq(tahvo_otg_dev->resource[1].start,
+ omap_otg_irq, SA_INTERRUPT, DRIVER_NAME,
+ &tahvo_usb_device);
+}
+
+static int omap_otg_remove(struct device *dev)
+{
+ tahvo_otg_dev = NULL;
+ free_irq(tahvo_otg_dev->resource[1].start, &tahvo_usb_device);
+ return 0;
+}
+
+struct device_driver omap_otg_driver = {
+ .name = "omap_otg",
+ .bus = &platform_bus_type,
+ .probe = omap_otg_probe,
+ .remove = omap_otg_remove,
+};
+
+/*
+ * ---------------------------------------------------------------------------
+ * Tahvo related functions
+ * These are Nokia proprietary code, except for the OTG register settings,
+ * which are copied from isp1301.c
+ * ---------------------------------------------------------------------------
+ */
+static ssize_t vbus_state_show(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct tahvo_usb *tu = (struct tahvo_usb*) device->driver_data;
+ return sprintf(buf, "%d\n", tu->vbus_state);
+}
+static DEVICE_ATTR(vbus_state, 0444, vbus_state_show, NULL);
+
+int vbus_active = 0;
+
+static void check_vbus_state(struct tahvo_usb *tu)
+{
+ int reg, prev_state;
+
+ reg = tahvo_read_reg(TAHVO_REG_IDSR);
+ if (reg & 0x01) {
+ vbus_active = 1;
+ switch (tu->otg.state) {
+ case OTG_STATE_B_IDLE:
+ /* Enable the gadget driver */
+ if (tu->otg.gadget)
+ usb_gadget_vbus_connect(tu->otg.gadget);
+ /* Set B-session valid and not B-sessio ended to indicate
+ * Vbus to be ok. */
+ OTG_CTRL_REG = (OTG_CTRL_REG & ~OTG_BSESSEND) | OTG_BSESSVLD;
+
+ tu->otg.state = OTG_STATE_B_PERIPHERAL;
+ break;
+ case OTG_STATE_A_IDLE:
+ /* Session is now valid assuming the USB hub is driving Vbus */
+ tu->otg.state = OTG_STATE_A_HOST;
+ if (tu->otg.host)
+ ohci_omap_host_enable(tu->otg.host, 1);
+ break;
+ default:
+ break;
+ }
+ printk("USB cable connected\n");
+ } else {
+ vbus_active = 0;
+ switch (tu->otg.state) {
+ case OTG_STATE_B_PERIPHERAL:
+ OTG_CTRL_REG = (OTG_CTRL_REG & ~OTG_BSESSVLD) | OTG_BSESSEND;
+ if (tu->otg.gadget)
+ usb_gadget_vbus_disconnect(tu->otg.gadget);
+ tu->otg.state = OTG_STATE_B_IDLE;
+ break;
+ case OTG_STATE_A_HOST:
+ tu->otg.state = OTG_STATE_A_IDLE;
+ if (tu->otg.host)
+ ohci_omap_host_enable(tu->otg.host, 0);
+
+ break;
+ default:
+ break;
+ }
+ printk("USB cable disconnected\n");
+ }
+
+ prev_state = tu->vbus_state;
+ tu->vbus_state = reg & 0x01;
+ if (prev_state != tu->vbus_state)
+ kobject_uevent(&tu->pt_dev->dev.kobj, KOBJ_CHANGE);
+}
+
+static void tahvo_usb_become_host(struct tahvo_usb *tu)
+{
+ /* Clear system and transceiver controlled bits
+ * also mark the A-session is always valid */
+ omap_otg_init();
+ OTG_CTRL_REG = (OTG_CTRL_REG & ~(OTG_CTRL_XCVR_MASK|OTG_CTRL_SYS_MASK))
+ | OTG_ASESSVLD;
+
+ /* Power up the transceiver in USB host mode */
+ tahvo_write_reg(TAHVO_REG_USBR, USBR_REGOUT | USBR_NSUSPEND |
+ USBR_MASTER_SW2 | USBR_MASTER_SW1);
+ tu->otg.state = OTG_STATE_A_IDLE;
+
+ check_vbus_state(tu);
+}
+
+static void tahvo_usb_stop_host(struct tahvo_usb *tu)
+{
+ if (tu->otg.host)
+ ohci_omap_host_enable(tu->otg.host, 0);
+ tu->otg.state = OTG_STATE_A_IDLE;
+}
+
+static void tahvo_usb_become_peripheral(struct tahvo_usb *tu)
+{
+ /* Clear system and transceiver controlled bits
+ * and enable ID to mark peripheral mode and
+ * BSESSEND to mark no Vbus */
+ omap_otg_init();
+ OTG_CTRL_REG = (OTG_CTRL_REG & ~(OTG_CTRL_XCVR_MASK|OTG_CTRL_SYS_MASK))
+ | OTG_ID | OTG_BSESSEND;
+
+ /* Power up transceiver and set it in USB perhiperal mode */
+ tahvo_write_reg(TAHVO_REG_USBR, USBR_SLAVE_CONTROL | USBR_REGOUT | USBR_NSUSPEND | USBR_SLAVE_SW);
+ tu->otg.state = OTG_STATE_B_IDLE;
+
+ check_vbus_state(tu);
+}
+
+static void tahvo_usb_stop_peripheral(struct tahvo_usb *tu)
+{
+ OTG_CTRL_REG = (OTG_CTRL_REG & ~OTG_BSESSVLD) | OTG_BSESSEND;
+ if (tu->otg.gadget)
+ usb_gadget_vbus_disconnect(tu->otg.gadget);
+ tu->otg.state = OTG_STATE_B_IDLE;
+
+}
+
+static void tahvo_usb_power_off(struct tahvo_usb *tu)
+{
+ int id;
+
+ /* Disable gadget controller if any */
+ if (tu->otg.gadget)
+ usb_gadget_vbus_disconnect(tu->otg.gadget);
+
+ if (tu->otg.host)
+ ohci_omap_host_enable(tu->otg.host, 0);
+
+ /* Disable OTG and interrupts */
+ if (TAHVO_MODE(tu) == TAHVO_MODE_PERIPHERAL)
+ id = OTG_ID;
+ else id = 0;
+ OTG_CTRL_REG = (OTG_CTRL_REG & ~(OTG_CTRL_XCVR_MASK|OTG_CTRL_SYS_MASK)) | id;
+ OTG_IRQ_EN_REG = 0;
+#if 0
+ OTG_SYSCON_2_REG &= ~OTG_EN;
+#endif
+
+ /* Power off transceiver */
+ tahvo_write_reg(TAHVO_REG_USBR, 0);
+ tu->otg.state = OTG_STATE_UNDEFINED;
+}
+
+
+static int tahvo_usb_set_power(struct otg_transceiver *dev, unsigned mA)
+{
+ if (dev->state == OTG_STATE_B_PERIPHERAL) {
+ /* REVISIT: Can Tahvo charge battery from VBUS? */
+ }
+ return 0;
+}
+
+static int tahvo_usb_set_suspend(struct otg_transceiver *dev, int suspend)
+{
+ u16 w;
+
+ w = tahvo_read_reg(TAHVO_REG_USBR);
+ if (suspend)
+ w &= ~USBR_NSUSPEND;
+ else
+ w |= USBR_NSUSPEND;
+ tahvo_write_reg(TAHVO_REG_USBR, w);
+
+ return 0;
+}
+
+static int tahvo_usb_start_srp(struct otg_transceiver *dev)
+{
+ struct tahvo_usb *tu = container_of(dev, struct tahvo_usb, otg);
+ u32 otg_ctrl;
+
+ if (!dev || tu->otg.state != OTG_STATE_B_IDLE)
+ return -ENODEV;
+
+ otg_ctrl = OTG_CTRL_REG;
+ if (!(otg_ctrl & OTG_BSESSEND))
+ return -EINVAL;
+
+ otg_ctrl |= OTG_B_BUSREQ;
+ otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_SYS_MASK;
+ OTG_CTRL_REG = otg_ctrl;
+ tu->otg.state = OTG_STATE_B_SRP_INIT;
+
+ pr_debug("otg: SRP, %s ... %06x\n", state_name(tu), OTG_CTRL_REG);
+
+ return 0;
+}
+
+static int tahvo_usb_start_hnp(struct otg_transceiver *dev)
+{
+#ifdef CONFIG_USB_OTG
+ /* REVISIT: Add this for OTG */
+#endif
+ return -EINVAL;
+}
+
+static int tahvo_usb_set_host(struct otg_transceiver *otg, struct usb_bus *host)
+{
+ struct tahvo_usb *tu = container_of(otg, struct tahvo_usb, otg);
+
+ if (!otg)
+ return -ENODEV;
+
+#if defined(CONFIG_USB_OTG) || !defined(CONFIG_USB_GADGET_OMAP)
+
+ down(&tu->serialize);
+
+ if (!host) {
+ if (TAHVO_MODE(tu) == TAHVO_MODE_HOST)
+ tahvo_usb_power_off(tu);
+ tu->otg.host = 0;
+ up(&tu->serialize);
+ return 0;
+ }
+
+ if (TAHVO_MODE(tu) == TAHVO_MODE_HOST) {
+ tu->otg.host = 0;
+ tahvo_usb_become_host(tu);
+ } else
+ ohci_omap_host_enable(host, 0);
+
+ tu->otg.host = host;
+
+ up(&tu->serialize);
+#else
+ /* No host mode configured, so do not allow host controlled to be set */
+ return -EINVAL;
+#endif
+
+ return 0;
+}
+
+static int tahvo_usb_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
+{
+ struct tahvo_usb *tu = container_of(otg, struct tahvo_usb, otg);
+
+ if (!otg)
+ return -ENODEV;
+
+#if defined(CONFIG_USB_OTG) || defined(CONFIG_USB_GADGET_OMAP)
+
+ down(&tu->serialize);
+
+ if (!gadget) {
+ if (TAHVO_MODE(tu) == TAHVO_MODE_PERIPHERAL)
+ tahvo_usb_power_off(tu);
+ tu->otg.gadget = 0;
+ up(&tu->serialize);
+ return 0;
+ }
+
+ tu->otg.gadget = gadget;
+ if (TAHVO_MODE(tu) == TAHVO_MODE_PERIPHERAL)
+ tahvo_usb_become_peripheral(tu);
+
+ up(&tu->serialize);
+#else
+ /* No gadget mode configured, so do not allow host controlled to be set */
+ return -EINVAL;
+#endif
+
+ return 0;
+}
+
+static void tahvo_usb_irq_work(void *data)
+{
+ struct tahvo_usb *tu = (struct tahvo_usb *)data;
+
+ down(&tu->serialize);
+ check_vbus_state(tu);
+ up(&tu->serialize);
+}
+
+static void tahvo_usb_vbus_interrupt(unsigned long arg)
+{
+ struct tahvo_usb *tu = (struct tahvo_usb *) arg;
+
+ tahvo_ack_irq(TAHVO_INT_VBUSON);
+ /* Seems we need this to acknowledge the interrupt */
+ tahvo_read_reg(TAHVO_REG_IDSR);
+ schedule_work(&tu->irq_work);
+}
+
+#ifdef CONFIG_USB_OTG
+static ssize_t otg_mode_show(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct tahvo_usb *tu = (struct tahvo_usb*) device->driver_data;
+ switch (tu->tahvo_mode) {
+ case TAHVO_MODE_HOST:
+ return sprintf(buf, "host\n");
+ case TAHVO_MODE_PERIPHERAL:
+ return sprintf(buf, "peripheral\n");
+ }
+ return sprintf(buf, "unknown\n");
+}
+
+static ssize_t otg_mode_store(struct device *device,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct tahvo_usb *tu = (struct tahvo_usb*) device->driver_data;
+ int r;
+
+ r = strlen(buf);
+ down(&tu->serialize);
+ if (strncmp(buf, "host", 4) == 0) {
+ if (tu->tahvo_mode == TAHVO_MODE_PERIPHERAL)
+ tahvo_usb_stop_peripheral(tu);
+ tu->tahvo_mode = TAHVO_MODE_HOST;
+ if (tu->otg.host) {
+ printk(KERN_INFO "Selected HOST mode: host controller present.\n");
+ tahvo_usb_become_host(tu);
+ } else {
+ printk(KERN_INFO "Selected HOST mode: no host controller, powering off.\n");
+ tahvo_usb_power_off(tu);
+ }
+ } else if (strncmp(buf, "peripheral", 10) == 0) {
+ if (tu->tahvo_mode == TAHVO_MODE_HOST)
+ tahvo_usb_stop_host(tu);
+ tu->tahvo_mode = TAHVO_MODE_PERIPHERAL;
+ if (tu->otg.gadget) {
+ printk(KERN_INFO "Selected PERIPHERAL mode: gadget driver present.\n");
+ tahvo_usb_become_peripheral(tu);
+ } else {
+ printk(KERN_INFO "Selected PERIPHERAL mode: no gadget driver, powering off.\n");
+ tahvo_usb_power_off(tu);
+ }
+ } else
+ r = -EINVAL;
+
+ up(&tu->serialize);
+ return r;
+}
+
+static DEVICE_ATTR(otg_mode, 0644, otg_mode_show, otg_mode_store);
+#endif
+
+static int tahvo_usb_probe(struct device *dev)
+{
+ struct tahvo_usb *tu;
+ int ret;
+
+ /* Create driver data */
+ tu = kmalloc(sizeof(*tu), GFP_KERNEL);
+ if (!tu)
+ return -ENOMEM;
+ memset(tu, 0, sizeof(*tu));
+ tu->pt_dev = container_of(dev, struct platform_device, dev);
+#ifdef CONFIG_USB_OTG
+ /* Default mode */
+#ifdef CONFIG_CBUS_TAHVO_USB_HOST_BY_DEFAULT
+ tu->tahvo_mode = TAHVO_MODE_HOST;
+#else
+ tu->tahvo_mode = TAHVO_MODE_PERIPHERAL;
+#endif
+#endif
+
+ INIT_WORK(&tu->irq_work, tahvo_usb_irq_work, tu);
+ init_MUTEX(&tu->serialize);
+
+ /* Set initial state, so that we generate kevents only on
+ * state changes */
+ tu->vbus_state = tahvo_read_reg(TAHVO_REG_IDSR) & 0x01;
+
+ /* We cannot enable interrupt until omap_udc is initialized */
+ ret = tahvo_request_irq(TAHVO_INT_VBUSON, tahvo_usb_vbus_interrupt,
+ (unsigned long) tu, "vbus_interrupt");
+ if (ret != 0) {
+ kfree(tu);
+ printk(KERN_ERR "Could not register Tahvo interrupt for VBUS\n");
+ return ret;
+ }
+
+ /* Attributes */
+ device_create_file(dev, &dev_attr_vbus_state);
+#ifdef CONFIG_USB_OTG
+ device_create_file(dev, &dev_attr_otg_mode);
+#endif
+
+ /* Create OTG interface */
+ tahvo_usb_power_off(tu);
+ tu->otg.state = OTG_STATE_UNDEFINED;
+ tu->otg.label = DRIVER_NAME;
+ tu->otg.set_host = tahvo_usb_set_host;
+ tu->otg.set_peripheral = tahvo_usb_set_peripheral;
+ tu->otg.set_power = tahvo_usb_set_power;
+ tu->otg.set_suspend = tahvo_usb_set_suspend;
+ tu->otg.start_srp = tahvo_usb_start_srp;
+ tu->otg.start_hnp = tahvo_usb_start_hnp;
+
+ ret = otg_set_transceiver(&tu->otg);
+ if (ret < 0) {
+ printk(KERN_ERR "Cannot register USB transceiver\n");
+ kfree(tu);
+ tahvo_free_irq(TAHVO_INT_VBUSON);
+ return ret;
+ }
+
+ dev->driver_data = tu;
+
+ /* Act upon current vbus state once at startup. A vbus state irq may or
+ * may not be generated in addition to this. */
+ schedule_work(&tu->irq_work);
+ return 0;
+}
+
+static int tahvo_usb_remove(struct device *dev)
+{
+ tahvo_free_irq(TAHVO_INT_VBUSON);
+ flush_scheduled_work();
+ otg_set_transceiver(0);
+ device_remove_file(dev, &dev_attr_vbus_state);
+#ifdef CONFIG_USB_OTG
+ device_remove_file(dev, &dev_attr_otg_mode);
+#endif
+ return 0;
+}
+
+static struct device_driver tahvo_usb_driver = {
+ .name = "tahvo-usb",
+ .bus = &platform_bus_type,
+ .probe = tahvo_usb_probe,
+ .remove = tahvo_usb_remove,
+};
+
+static struct platform_device tahvo_usb_device = {
+ .name = "tahvo-usb",
+ .id = -1,
+};
+
+static int __init tahvo_usb_init(void)
+{
+ int ret = 0;
+
+ printk(KERN_INFO "Tahvo USB transceiver driver initializing\n");
+ ret = driver_register(&tahvo_usb_driver);
+ if (ret)
+ return ret;
+ ret = platform_device_register(&tahvo_usb_device);
+ if (ret < 0) {
+ driver_unregister(&tahvo_usb_driver);
+ return ret;
+ }
+ ret = driver_register(&omap_otg_driver);
+ if (ret) {
+ platform_device_unregister(&tahvo_usb_device);
+ driver_unregister(&tahvo_usb_driver);
+ return ret;
+ }
+ return 0;
+}
+
+subsys_initcall(tahvo_usb_init);
+
+static void __exit tahvo_usb_exit(void)
+{
+ driver_unregister(&omap_otg_driver);
+ platform_device_unregister(&tahvo_usb_device);
+ driver_unregister(&tahvo_usb_driver);
+}
+module_exit(tahvo_usb_exit);
+
+MODULE_DESCRIPTION("Tahvo USB OTG Transceiver Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Juha Yrjölä, Tony Lindgren, and Timo Teräs");
--- /dev/null
+/**
+ * drivers/cbus/tahvo-user.c
+ *
+ * Tahvo user space interface functions
+ *
+ * Copyright (C) 2004, 2005 Nokia Corporation
+ *
+ * Written by Mikko Ylinen <mikko.k.ylinen@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.
+ *
+ * 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/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+#include <asm/uaccess.h>
+
+#include "tahvo.h"
+
+#include "user_retu_tahvo.h"
+
+/* Maximum size of IRQ node buffer/pool */
+#define TAHVO_MAX_IRQ_BUF_LEN 16
+
+#define PFX "tahvo-user: "
+
+/* Bitmap for marking the interrupt sources as having the handlers */
+static u32 tahvo_irq_bits;
+
+/* For allowing only one user process to subscribe to the tahvo interrupts */
+static struct file *tahvo_irq_subscr = NULL;
+
+/* For poll and IRQ passing */
+struct tahvo_irq {
+ u32 id;
+ struct list_head node;
+};
+
+static spinlock_t tahvo_irqs_lock;
+static struct tahvo_irq *tahvo_irq_block;
+static LIST_HEAD(tahvo_irqs);
+static LIST_HEAD(tahvo_irqs_reserve);
+
+/* Wait queue - used when user wants to read the device */
+DECLARE_WAIT_QUEUE_HEAD(tahvo_user_waitqueue);
+
+/* Semaphore to protect irq subscription sequence */
+static struct semaphore tahvo_sem;
+
+/* This array specifies TAHVO register types (read/write/toggle) */
+static const u8 tahvo_access_bits[] = {
+ 1,
+ 4,
+ 1,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 1
+};
+
+/*
+ * The handler for all TAHVO interrupts.
+ *
+ * arg is the interrupt source in TAHVO.
+ */
+static void tahvo_user_irq_handler(unsigned long arg)
+{
+ struct tahvo_irq *irq;
+
+ /* user has to re-enable the interrupt once ready
+ * for receiving them again */
+ tahvo_disable_irq(arg);
+ tahvo_ack_irq(arg);
+
+ spin_lock(&tahvo_irqs_lock);
+ if (list_empty(&tahvo_irqs_reserve)) {
+ spin_unlock(&tahvo_irqs_lock);
+ return;
+ }
+ irq = list_entry((&tahvo_irqs_reserve)->next, struct tahvo_irq, node);
+ irq->id = arg;
+ list_move_tail(&irq->node, &tahvo_irqs);
+ spin_unlock(&tahvo_irqs_lock);
+
+ /* wake up waiting thread */
+ wake_up(&tahvo_user_waitqueue);
+}
+
+/*
+ * This routine sets up the interrupt handler and marks an interrupt source
+ * in TAHVO as a candidate for signal delivery to the user process.
+ */
+static int tahvo_user_subscribe_to_irq(int id, struct file *filp)
+{
+ int ret;
+
+ down(&tahvo_sem);
+ if ((tahvo_irq_subscr != NULL) && (tahvo_irq_subscr != filp)) {
+ up(&tahvo_sem);
+ return -EBUSY;
+ }
+ /* Store the file pointer of the first user process registering IRQs */
+ tahvo_irq_subscr = filp;
+ up(&tahvo_sem);
+
+ if (tahvo_irq_bits & (1 << id))
+ return 0;
+
+ ret = tahvo_request_irq(id, tahvo_user_irq_handler, id, "");
+ if (ret < 0)
+ return ret;
+
+ /* Mark that this interrupt has a handler */
+ tahvo_irq_bits |= 1 << id;
+
+ return 0;
+}
+
+/*
+ * Unregister all TAHVO interrupt handlers
+ */
+static void tahvo_unreg_irq_handlers(void)
+{
+ int id;
+
+ if (!tahvo_irq_bits)
+ return;
+
+ for (id = 0; id < MAX_TAHVO_IRQ_HANDLERS; id++)
+ if (tahvo_irq_bits & (1 << id))
+ tahvo_free_irq(id);
+
+ tahvo_irq_bits = 0;
+}
+
+/*
+ * Write to TAHVO register.
+ * Returns 0 upon success, a negative error value otherwise.
+ */
+static int tahvo_user_write_with_mask(u32 field, u16 value)
+{
+ u32 mask;
+ u32 reg;
+ u_short tmp;
+ unsigned long flags;
+
+ mask = MASK(field);
+ reg = REG(field);
+
+ /* Detect bad mask and reg */
+ if (mask == 0 || reg > TAHVO_REG_MAX ||
+ tahvo_access_bits[reg] == READ_ONLY) {
+ printk(KERN_ERR PFX "invalid arguments (reg=%#x, mask=%#x)\n",
+ reg, mask);
+ return -EINVAL;
+ }
+
+ /* Justify value according to mask */
+ while (!(mask & 1)) {
+ value = value << 1;
+ mask = mask >> 1;
+ }
+
+ spin_lock_irqsave(&tahvo_lock, flags);
+ if (tahvo_access_bits[reg] == TOGGLE) {
+ /* No need to detect previous content of register */
+ tmp = 0;
+ } else {
+ /* Read current value of register */
+ tmp = tahvo_read_reg(reg);
+ }
+ /* Generate a new value */
+ tmp = (tmp & ~MASK(field)) | (value & MASK(field));
+ /* Write data to TAHVO */
+ tahvo_write_reg(reg, tmp);
+ spin_unlock_irqrestore(&tahvo_lock, flags);
+
+ return 0;
+}
+
+/*
+ * Read TAHVO register.
+ */
+static u32 tahvo_user_read_with_mask(u32 field)
+{
+ u_short value;
+ u32 mask, reg;
+
+ mask = MASK(field);
+ reg = REG(field);
+
+ /* Detect bad mask and reg */
+ if (mask == 0 || reg > TAHVO_REG_MAX) {
+ printk(KERN_ERR PFX "invalid arguments (reg=%#x, mask=%#x)\n",
+ reg, mask);
+ return -EINVAL;
+ }
+
+ /* Read the register */
+ value = tahvo_read_reg(reg) & mask;
+
+ /* Right justify value */
+ while (!(mask & 1)) {
+ value = value >> 1;
+ mask = mask >> 1;
+ }
+
+ return value;
+}
+
+/*
+ * Close device
+ */
+static int tahvo_close(struct inode *inode, struct file *filp)
+{
+ /* Unregister all interrupts that have been registered */
+ if (tahvo_irq_subscr == filp) {
+ tahvo_unreg_irq_handlers();
+ tahvo_irq_subscr = NULL;
+ }
+
+ return 0;
+}
+
+/*
+ * Device control (ioctl)
+ */
+static int tahvo_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ struct retu_tahvo_write_parms par;
+
+ switch (cmd) {
+ case URT_IOCT_IRQ_SUBSCR:
+ return tahvo_user_subscribe_to_irq(arg, filp);
+ case TAHVO_IOCH_READ:
+ return tahvo_user_read_with_mask(arg);
+ case TAHVO_IOCX_WRITE:
+ copy_from_user(&par, (void __user *) arg, sizeof(par));
+ par.result = tahvo_user_write_with_mask(par.field, par.value);
+ copy_to_user((void __user *) arg, &par, sizeof(par));
+ break;
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+/*
+ * Read from device
+ */
+static ssize_t tahvo_read(struct file *filp, char *buf, size_t count,
+ loff_t * offp)
+{
+ struct tahvo_irq *irq;
+
+ u32 nr, i;
+
+ /* read not permitted if neither filp nor anyone has registered IRQs */
+ if (tahvo_irq_subscr != filp)
+ return -EPERM;
+
+ if ((count < sizeof(u32)) || ((count % sizeof(u32)) != 0))
+ return -EINVAL;
+
+ nr = count / sizeof(u32);
+
+ for (i = 0; i < nr; i++) {
+ unsigned long flags;
+ u32 irq_id;
+ int ret;
+
+ ret = wait_event_interruptible(tahvo_user_waitqueue,
+ !list_empty(&tahvo_irqs));
+ if (ret < 0)
+ return ret;
+
+ spin_lock_irqsave(&tahvo_irqs_lock, flags);
+ irq = list_entry((&tahvo_irqs)->next, struct tahvo_irq, node);
+ irq_id = irq->id;
+ list_move(&irq->node, &tahvo_irqs_reserve);
+ spin_unlock_irqrestore(&tahvo_irqs_lock, flags);
+
+ copy_to_user(buf + i * sizeof(irq_id), &irq_id, sizeof(irq_id));
+ }
+
+ return count;
+}
+
+/*
+ * Poll method
+ */
+static unsigned tahvo_poll(struct file *filp, struct poll_table_struct *pt)
+{
+ if (!list_empty(&tahvo_irqs))
+ return POLLIN;
+
+ poll_wait(filp, &tahvo_user_waitqueue, pt);
+
+ if (!list_empty(&tahvo_irqs))
+ return POLLIN;
+ else
+ return 0;
+}
+
+static struct file_operations tahvo_user_fileops = {
+ .owner = THIS_MODULE,
+ .ioctl = tahvo_ioctl,
+ .read = tahvo_read,
+ .release = tahvo_close,
+ .poll = tahvo_poll
+};
+
+static struct miscdevice tahvo_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "tahvo",
+ .fops = &tahvo_user_fileops
+};
+
+/*
+ * Initialization
+ *
+ * @return 0 if successful, error value otherwise.
+ */
+int tahvo_user_init(void)
+{
+ struct tahvo_irq *irq;
+ int res, i;
+
+ irq = kmalloc(sizeof(*irq) * TAHVO_MAX_IRQ_BUF_LEN, GFP_KERNEL);
+ if (irq == NULL) {
+ printk(KERN_ERR PFX "kmalloc failed\n");
+ return -ENOMEM;
+ }
+ memset(irq, 0, sizeof(*irq) * TAHVO_MAX_IRQ_BUF_LEN);
+ for (i = 0; i < TAHVO_MAX_IRQ_BUF_LEN; i++)
+ list_add(&irq[i].node, &tahvo_irqs_reserve);
+
+ tahvo_irq_block = irq;
+
+ spin_lock_init(&tahvo_irqs_lock);
+ sema_init(&tahvo_sem, 1);
+
+ /* Request a misc device */
+ res = misc_register(&tahvo_device);
+ if (res < 0) {
+ printk(KERN_ERR PFX "unable to register misc device for %s\n",
+ tahvo_device.name);
+ kfree(irq);
+ return res;
+ }
+
+ return 0;
+}
+
+/*
+ * Cleanup.
+ */
+void tahvo_user_cleanup(void)
+{
+ /* Unregister our misc device */
+ misc_deregister(&tahvo_device);
+ /* Unregister and disable all TAHVO interrupts */
+ tahvo_unreg_irq_handlers();
+ kfree(tahvo_irq_block);
+}
+
+MODULE_DESCRIPTION("Tahvo ASIC user space functions");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mikko Ylinen");
--- /dev/null
+/**
+ * drivers/cbus/tahvo.c
+ *
+ * Support functions for Tahvo ASIC
+ *
+ * Copyright (C) 2004, 2005 Nokia Corporation
+ *
+ * Written by Juha Yrjölä <juha.yrjola@nokia.com>,
+ * David Weinehall <david.weinehall@nokia.com>, and
+ * Mikko Ylinen <mikko.k.ylinen@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.
+ *
+ * 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/init.h>
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <asm/uaccess.h>
+
+#include <asm/arch/mux.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/board.h>
+
+#include "cbus.h"
+#include "tahvo.h"
+
+#define TAHVO_ID 0x02
+#define PFX "tahvo: "
+
+static int tahvo_initialized;
+static int tahvo_irq_pin;
+static int tahvo_is_betty;
+
+static struct tasklet_struct tahvo_tasklet;
+spinlock_t tahvo_lock = SPIN_LOCK_UNLOCKED;
+
+static struct completion device_release;
+
+struct tahvo_irq_handler_desc {
+ int (*func)(unsigned long);
+ unsigned long arg;
+ char name[8];
+};
+
+static struct tahvo_irq_handler_desc tahvo_irq_handlers[MAX_TAHVO_IRQ_HANDLERS];
+
+/**
+ * tahvo_read_reg - Read a value from a register in Tahvo
+ * @reg: the register to read from
+ *
+ * This function returns the contents of the specified register
+ */
+int tahvo_read_reg(int reg)
+{
+ BUG_ON(!tahvo_initialized);
+ return cbus_read_reg(cbus_host, TAHVO_ID, reg);
+}
+
+/**
+ * tahvo_write_reg - Write a value to a register in Tahvo
+ * @reg: the register to write to
+ * @reg: the value to write to the register
+ *
+ * This function writes a value to the specified register
+ */
+void tahvo_write_reg(int reg, u16 val)
+{
+ BUG_ON(!tahvo_initialized);
+ cbus_write_reg(cbus_host, TAHVO_ID, reg, val);
+}
+
+/*
+ * Disable given TAHVO interrupt
+ */
+void tahvo_disable_irq(int id)
+{
+ unsigned long flags;
+ u16 mask;
+
+ spin_lock_irqsave(&tahvo_lock, flags);
+ mask = tahvo_read_reg(TAHVO_REG_IMR);
+ mask |= 1 << id;
+ tahvo_write_reg(TAHVO_REG_IMR, mask);
+ spin_unlock_irqrestore(&tahvo_lock, flags);
+}
+
+/*
+ * Enable given TAHVO interrupt
+ */
+void tahvo_enable_irq(int id)
+{
+ unsigned long flags;
+ u16 mask;
+
+ spin_lock_irqsave(&tahvo_lock, flags);
+ mask = tahvo_read_reg(TAHVO_REG_IMR);
+ mask &= ~(1 << id);
+ tahvo_write_reg(TAHVO_REG_IMR, mask);
+ spin_unlock_irqrestore(&tahvo_lock, flags);
+}
+
+/*
+ * Acknowledge given TAHVO interrupt
+ */
+void tahvo_ack_irq(int id)
+{
+ tahvo_write_reg(TAHVO_REG_IDR, 1 << id);
+}
+
+static int tahvo_7bit_backlight;
+
+int tahvo_get_backlight_level(void)
+{
+ int mask;
+
+ if (tahvo_7bit_backlight)
+ mask = 0x7f;
+ else
+ mask = 0x0f;
+ return tahvo_read_reg(TAHVO_REG_LEDPWMR) & mask;
+}
+
+int tahvo_get_max_backlight_level(void)
+{
+ if (tahvo_7bit_backlight)
+ return 0x7f;
+ else
+ return 0x0f;
+}
+
+void tahvo_set_backlight_level(int level)
+{
+ int max_level;
+
+ max_level = tahvo_get_max_backlight_level();
+ if (level > max_level)
+ level = max_level;
+ tahvo_write_reg(TAHVO_REG_LEDPWMR, level);
+}
+
+/*
+ * TAHVO interrupt handler. Only schedules the tasklet.
+ */
+static irqreturn_t tahvo_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+ tasklet_schedule(&tahvo_tasklet);
+ return IRQ_HANDLED;
+}
+
+/*
+ * Tasklet handler
+ */
+static void tahvo_tasklet_handler(unsigned long data)
+{
+ struct tahvo_irq_handler_desc *hnd;
+ u16 id;
+ u16 im;
+ int i;
+
+ for (;;) {
+ id = tahvo_read_reg(TAHVO_REG_IDR);
+ im = ~tahvo_read_reg(TAHVO_REG_IMR);
+ id &= im;
+
+ if (!id)
+ break;
+
+ for (i = 0; id != 0; i++, id >>= 1) {
+ if (!(id & 1))
+ continue;
+ hnd = &tahvo_irq_handlers[i];
+ if (hnd->func == NULL) {
+ /* Spurious tahvo interrupt - just ack it */
+ printk(KERN_INFO "Spurious Tahvo interrupt "
+ "(id %d)\n", i);
+ tahvo_disable_irq(i);
+ tahvo_ack_irq(i);
+ continue;
+ }
+ hnd->func(hnd->arg);
+ /*
+ * Don't acknowledge the interrupt here
+ * It must be done explicitly
+ */
+ }
+ }
+}
+
+/*
+ * Register the handler for a given TAHVO interrupt source.
+ */
+int tahvo_request_irq(int id, void *irq_handler, unsigned long arg, char *name)
+{
+ struct tahvo_irq_handler_desc *hnd;
+
+ if (irq_handler == NULL || id >= MAX_TAHVO_IRQ_HANDLERS ||
+ name == NULL) {
+ printk(KERN_ERR PFX "Invalid arguments to %s\n",
+ __FUNCTION__);
+ return -EINVAL;
+ }
+ hnd = &tahvo_irq_handlers[id];
+ if (hnd->func != NULL) {
+ printk(KERN_ERR PFX "IRQ %d already reserved\n", id);
+ return -EBUSY;
+ }
+ printk(KERN_INFO PFX "Registering interrupt %d for device %s\n",
+ id, name);
+ hnd->func = irq_handler;
+ hnd->arg = arg;
+ strlcpy(hnd->name, name, sizeof(hnd->name));
+
+ tahvo_ack_irq(id);
+ tahvo_enable_irq(id);
+
+ return 0;
+}
+
+/*
+ * Unregister the handler for a given TAHVO interrupt source.
+ */
+void tahvo_free_irq(int id)
+{
+ struct tahvo_irq_handler_desc *hnd;
+
+ if (id >= MAX_TAHVO_IRQ_HANDLERS) {
+ printk(KERN_ERR PFX "Invalid argument to %s\n",
+ __FUNCTION__);
+ return;
+ }
+ hnd = &tahvo_irq_handlers[id];
+ if (hnd->func == NULL) {
+ printk(KERN_ERR PFX "IRQ %d already freed\n", id);
+ return;
+ }
+
+ tahvo_disable_irq(id);
+ hnd->func = NULL;
+}
+
+/**
+ * tahvo_probe - Probe for Tahvo ASIC
+ * @dev: the Tahvo device
+ *
+ * Probe for the Tahvo ASIC and allocate memory
+ * for its device-struct if found
+ */
+static int __devinit tahvo_probe(struct device *dev)
+{
+ const struct omap_em_asic_bb5_config * em_asic_config;
+ int rev, id, ret;
+
+ /* Prepare tasklet */
+ tasklet_init(&tahvo_tasklet, tahvo_tasklet_handler, 0);
+
+ em_asic_config = omap_get_config(OMAP_TAG_EM_ASIC_BB5,
+ struct omap_em_asic_bb5_config);
+ if (em_asic_config == NULL) {
+ printk(KERN_ERR PFX "Unable to retrieve config data\n");
+ return -ENODATA;
+ }
+
+ tahvo_initialized = 1;
+
+ rev = tahvo_read_reg(TAHVO_REG_ASICR);
+
+ id = (rev >> 8) & 0xff;
+ if (id == 0x03) {
+ if ((rev & 0xff) >= 0x50)
+ tahvo_7bit_backlight = 1;
+ } else if (id == 0x0b) {
+ tahvo_is_betty = 1;
+ tahvo_7bit_backlight = 1;
+ } else {
+ printk(KERN_ERR "Tahvo/Betty chip not found");
+ return -ENODEV;
+ }
+
+ printk(KERN_INFO "%s v%d.%d found\n", tahvo_is_betty ? "Betty" : "Tahvo",
+ (rev >> 4) & 0x0f, rev & 0x0f);
+
+ tahvo_irq_pin = em_asic_config->tahvo_irq_gpio;
+
+ if ((ret = omap_request_gpio(tahvo_irq_pin)) < 0) {
+ printk(KERN_ERR PFX "Unable to reserve IRQ GPIO\n");
+ return ret;
+ }
+
+ /* Set the pin as input */
+ omap_set_gpio_direction(tahvo_irq_pin, 1);
+
+ /* Rising edge triggers the IRQ */
+ set_irq_type(OMAP_GPIO_IRQ(tahvo_irq_pin), IRQT_RISING);
+
+ /* Mask all TAHVO interrupts */
+ tahvo_write_reg(TAHVO_REG_IMR, 0xffff);
+
+ ret = request_irq(OMAP_GPIO_IRQ(tahvo_irq_pin), tahvo_irq_handler, 0,
+ "tahvo", 0);
+ if (ret < 0) {
+ printk(KERN_ERR PFX "Unable to register IRQ handler\n");
+ omap_free_gpio(tahvo_irq_pin);
+ return ret;
+ }
+#ifdef CONFIG_CBUS_TAHVO_USER
+ /* Initialize user-space interface */
+ if (tahvo_user_init() < 0) {
+ printk(KERN_ERR "Unable to initialize driver\n");
+ free_irq(OMAP_GPIO_IRQ(tahvo_irq_pin), 0);
+ omap_free_gpio(tahvo_irq_pin);
+ return ret;
+ }
+#endif
+ return 0;
+}
+
+static int tahvo_remove(struct device *dev)
+{
+#ifdef CONFIG_CBUS_TAHVO_USER
+ tahvo_user_cleanup();
+#endif
+ /* Mask all TAHVO interrupts */
+ tahvo_write_reg(TAHVO_REG_IMR, 0xffff);
+ free_irq(OMAP_GPIO_IRQ(tahvo_irq_pin), 0);
+ omap_free_gpio(tahvo_irq_pin);
+ tasklet_kill(&tahvo_tasklet);
+
+ return 0;
+}
+
+static void tahvo_device_release(struct device *dev)
+{
+ complete(&device_release);
+}
+
+static struct device_driver tahvo_driver = {
+ .name = "tahvo",
+ .bus = &platform_bus_type,
+ .probe = tahvo_probe,
+ .remove = tahvo_remove,
+};
+
+static struct platform_device tahvo_device = {
+ .name = "tahvo",
+ .id = -1,
+ .dev = {
+ .release = tahvo_device_release,
+ }
+};
+
+/**
+ * tahvo_init - initialise Tahvo driver
+ *
+ * Initialise the Tahvo driver and return 0 if everything worked ok
+ */
+static int __init tahvo_init(void)
+{
+ int ret = 0;
+
+ printk(KERN_INFO "Tahvo/Betty driver initialising\n");
+
+ init_completion(&device_release);
+
+ if ((ret = driver_register(&tahvo_driver)) < 0)
+ return ret;
+
+ if ((ret = platform_device_register(&tahvo_device)) < 0) {
+ driver_unregister(&tahvo_driver);
+ return ret;
+ }
+ return 0;
+}
+
+/*
+ * Cleanup
+ */
+static void __exit tahvo_exit(void)
+{
+ platform_device_unregister(&tahvo_device);
+ driver_unregister(&tahvo_driver);
+ wait_for_completion(&device_release);
+}
+
+EXPORT_SYMBOL(tahvo_request_irq);
+EXPORT_SYMBOL(tahvo_free_irq);
+EXPORT_SYMBOL(tahvo_enable_irq);
+EXPORT_SYMBOL(tahvo_disable_irq);
+EXPORT_SYMBOL(tahvo_ack_irq);
+EXPORT_SYMBOL(tahvo_read_reg);
+EXPORT_SYMBOL(tahvo_write_reg);
+EXPORT_SYMBOL(tahvo_get_backlight_level);
+EXPORT_SYMBOL(tahvo_get_max_backlight_level);
+EXPORT_SYMBOL(tahvo_set_backlight_level);
+
+subsys_initcall(tahvo_init);
+module_exit(tahvo_exit);
+
+MODULE_DESCRIPTION("Tahvo ASIC control");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Juha Yrjölä, David Weinehall, and Mikko Ylinen");
--- /dev/null
+/*
+ * drivers/cbus/tahvo.h
+ *
+ * Copyright (C) 2004, 2005 Nokia Corporation
+ *
+ * Written by Juha Yrjölä <juha.yrjola@nokia.com> and
+ * David Weinehall <david.weinehall@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.
+ *
+ * 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 __DRIVERS_CBUS_TAHVO_H
+#define __DRIVERS_CBUS_TAHVO_H
+
+#include <linux/types.h>
+
+/* Registers */
+#define TAHVO_REG_ASICR 0x00 /* ASIC ID & revision */
+#define TAHVO_REG_IDR 0x01 /* Interrupt ID */
+#define TAHVO_REG_IDSR 0x02 /* Interrupt status */
+#define TAHVO_REG_IMR 0x03 /* Interrupt mask */
+#define TAHVO_REG_LEDPWMR 0x05 /* LED PWM */
+#define TAHVO_REG_USBR 0x06 /* USB control */
+#define TAHVO_REG_MAX 0x0d
+
+/* Interrupt sources */
+#define TAHVO_INT_VBUSON 0
+
+#define MAX_TAHVO_IRQ_HANDLERS 8
+
+int tahvo_read_reg(int reg);
+void tahvo_write_reg(int reg, u16 val);
+int tahvo_request_irq(int id, void *irq_handler, unsigned long arg, char *name);
+void tahvo_free_irq(int id);
+void tahvo_enable_irq(int id);
+void tahvo_disable_irq(int id);
+void tahvo_ack_irq(int id);
+int tahvo_get_backlight_level(void);
+int tahvo_get_max_backlight_level(void);
+void tahvo_set_backlight_level(int level);
+
+#ifdef CONFIG_CBUS_TAHVO_USER
+int tahvo_user_init(void);
+void tahvo_user_cleanup(void);
+#endif
+
+extern spinlock_t tahvo_lock;
+
+#endif /* __DRIVERS_CBUS_TAHVO_H */
--- /dev/null
+/**
+ * drivers/cbus/user_retu_tahvo.h
+ *
+ * Copyright (C) 2004, 2005 Nokia Corporation
+ *
+ * Written by Mikko Ylinen <mikko.k.ylinen@nokia.com>
+ *
+ * Definitions and types used by both retu-user and tahvo-user.
+ *
+ * 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.
+ *
+ * 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 _USER_RETU_TAHVO_H
+#define _USER_RETU_TAHVO_H
+
+/* Chip IDs */
+#define CHIP_RETU 1
+#define CHIP_TAHVO 2
+
+/* Register access type bits */
+#define READ_ONLY 1
+#define WRITE_ONLY 2
+#define READ_WRITE 3
+#define TOGGLE 4
+
+#define MASK(field) ((u16)(field & 0xFFFF))
+#define REG(field) ((u16)((field >> 16) & 0x3F))
+
+/*** IOCTL definitions. These should be kept in sync with user space **********/
+
+#define URT_IOC_MAGIC '`'
+
+/*
+ * IOCTL function naming conventions:
+ * ==================================
+ * 0 -- No argument and return value
+ * S -- Set through a pointer
+ * T -- Tell directly with the argument value
+ * G -- Reply by setting through a pointer
+ * Q -- response is on the return value
+ * X -- S and G atomically
+ * H -- T and Q atomically
+ */
+
+/* General */
+#define URT_IOCT_IRQ_SUBSCR _IO(URT_IOC_MAGIC, 0)
+
+/* RETU */
+#define RETU_IOCH_READ _IO(URT_IOC_MAGIC, 1)
+#define RETU_IOCX_WRITE _IO(URT_IOC_MAGIC, 2)
+#define RETU_IOCH_ADC_READ _IO(URT_IOC_MAGIC, 3)
+
+/* TAHVO */
+#define TAHVO_IOCH_READ _IO(URT_IOC_MAGIC, 4)
+#define TAHVO_IOCX_WRITE _IO(URT_IOC_MAGIC, 5)
+
+/* This structure is used for writing RETU/TAHVO registers */
+struct retu_tahvo_write_parms {
+ u32 field;
+ u16 value;
+ u8 result;
+};
+
+#endif
If unsure, say N.
+config OMAP_RNG
+ tristate "OMAP Random Number Generator support"
+ depends on ARCH_OMAP16XX || ARCH_OMAP24XX
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on OMAP16xx and OMAP24xx multimedia
+ processors.
+
+ If unsure, say N.
+
config NVRAM
tristate "/dev/nvram support"
depends on ATARI || X86 || ARM || GENERIC_NVRAM
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"
obj-$(CONFIG_DS1302) += ds1302.o
obj-$(CONFIG_S3C2410_RTC) += s3c2410-rtc.o
obj-$(CONFIG_RTC_VR41XX) += vr41xx_rtc.o
+obj-$(CONFIG_OMAP_RTC)+= omap-rtc.o
ifeq ($(CONFIG_GENERIC_NVRAM),y)
obj-$(CONFIG_NVRAM) += generic_nvram.o
else
obj-$(CONFIG_I8K) += i8k.o
obj-$(CONFIG_DS1620) += ds1620.o
obj-$(CONFIG_HW_RANDOM) += hw_random.o
+obj-$(CONFIG_OMAP_RNG) += omap-rng.o
obj-$(CONFIG_FTAPE) += ftape/
obj-$(CONFIG_COBALT_LCD) += lcd.o
obj-$(CONFIG_PPDEV) += ppdev.o
--- /dev/null
+/*
+ * drivers/char/omap-rng.c
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * OMAP16xx and OMAP24xx Random Number Generator driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/random.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+
+#if defined (CONFIG_ARCH_OMAP16XX)
+#define RNG_BASE 0xfffe5000
+#endif
+#if defined (CONFIG_ARCH_OMAP24XX)
+#define RNG_BASE 0x480A0000
+#endif
+
+#define RNG_OUT_REG 0x00 /* Output register */
+#define RNG_STAT_REG 0x04 /* Status register
+ [0] = STAT_BUSY */
+#define RNG_ALARM_REG 0x24 /* Alarm register
+ [7:0] = ALARM_COUNTER */
+#define RNG_CONFIG_REG 0x28 /* Configuration register
+ [11:6] = RESET_COUNT
+ [5:3] = RING2_DELAY
+ [2:0] = RING1_DELAY */
+#define RNG_REV_REG 0x3c /* Revision register
+ [7:0] = REV_NB */
+#define RNG_MASK_REG 0x40 /* Mask and reset register
+ [2] = IT_EN
+ [1] = SOFTRESET
+ [0] = AUTOIDLE */
+#define RNG_SYSSTATUS 0x44 /* System status
+ [0] = RESETDONE */
+
+#define ENTROPY_WORD_COUNT 128
+
+static u32 rng_base = io_p2v(RNG_BASE);
+
+static struct clk *rng_ick = NULL;
+
+static u32 rng_read_reg(int reg)
+{
+ return __raw_readl(rng_base + reg);
+}
+
+static void rng_write_reg(int reg, u32 val)
+{
+ __raw_writel(val, rng_base + reg);
+}
+
+static void rng_feed_entropy(int count)
+{
+ u32 l;
+
+ while (count--) {
+ while (rng_read_reg(RNG_STAT_REG));
+ l = rng_read_reg(RNG_OUT_REG);
+ add_input_randomness(0, 0, l);
+ }
+}
+
+static int __init rng_init(void)
+{
+ if (!cpu_is_omap16xx() && !cpu_is_omap24xx())
+ return -ENODEV;
+
+ if (cpu_is_omap24xx()) {
+ rng_ick = clk_get(NULL, "rng_ick");
+ if (IS_ERR(rng_ick)) {
+ printk(KERN_ERR "omap-rng.c: Could not get rng_ick\n");
+ return PTR_ERR(rng_ick);
+ }
+ clk_enable(rng_ick);
+ }
+
+ printk("OMAP Random Number Generator ver. %02x\n",
+ rng_read_reg(RNG_REV_REG));
+ rng_write_reg(RNG_MASK_REG, 0x00000001);
+ rng_feed_entropy(ENTROPY_WORD_COUNT);
+ rng_write_reg(RNG_MASK_REG, 0x00000000);
+ printk("%d words of entropy generated\n", ENTROPY_WORD_COUNT);
+
+ return 0;
+}
+late_initcall(rng_init);
--- /dev/null
+/*
+ * 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/config.h>
+#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 SA_INTERRUPT set.
+ */
+
+static irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ /*
+ * 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, SA_INTERRUPT,
+ 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, SA_INTERRUPT,
+ 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);
--- /dev/null
+/*
+ * 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)
Most people will say N.
+config OMAP_WATCHDOG
+ tristate "OMAP Watchdog"
+ depends on WATCHDOG && (ARCH_OMAP16XX || ARCH_OMAP24XX)
+ help
+ Support for TI OMAP1610/OMAP1710/OMAP2420 watchdog. Say 'Y' here to enable the
+ OMAP1610/OMAP1710 watchdog timer.
+
endmenu
obj-$(CONFIG_977_WATCHDOG) += wdt977.o
obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
+obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
--- /dev/null
+/*
+ * linux/drivers/char/omap_wdt.c
+ *
+ * Watchdog driver for the TI OMAP 16xx & 24xx 32KHz (non-secure) watchdog
+ *
+ * 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.
+ *
+ * History:
+ *
+ * 20030527: George G. Davis <gdavis@mvista.com>
+ * Initially based on linux-2.4.19-rmk7-pxa1/drivers/char/sa1100_wdt.c
+ * (c) Copyright 2000 Oleg Drokin <green@crimea.edu>
+ * Based on SoftDog driver by Alan Cox <alan@redhat.com>
+ *
+ * Copyright (c) 2004 Texas Instruments.
+ * 1. Modified to support OMAP1610 32-KHz watchdog timer
+ * 2. Ported to 2.6 kernel
+ *
+ * Copyright (c) 2005 David Brownell
+ * Use the driver model and standard identifiers; handle bigger timeouts.
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/reboot.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/moduleparam.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/hardware.h>
+#include <asm/bitops.h>
+
+#include <asm/arch/prcm.h>
+
+#include "omap_wdt.h"
+
+static unsigned timer_margin;
+module_param(timer_margin, uint, 0);
+MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
+
+static int omap_wdt_users;
+static struct clk *armwdt_ck = NULL;
+static struct clk *mpu_wdt_ick = NULL;
+static struct clk *mpu_wdt_fck = NULL;
+
+static unsigned int wdt_trgr_pattern = 0x1234;
+
+static void omap_wdt_ping(void)
+{
+ while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08) ; /* wait for posted write to complete */
+ wdt_trgr_pattern = ~wdt_trgr_pattern;
+ omap_writel(wdt_trgr_pattern, (OMAP_WATCHDOG_TGR));
+ while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08) ; /* wait for posted write to complete */
+ /* reloaded WCRR from WLDR */
+}
+
+static void omap_wdt_enable(void)
+{
+ /* Sequence to enable the watchdog */
+ omap_writel(0xBBBB, OMAP_WATCHDOG_SPR);
+ while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10) ;
+ omap_writel(0x4444, OMAP_WATCHDOG_SPR);
+ while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10) ;
+}
+
+static void omap_wdt_disable(void)
+{
+ /* sequence required to disable watchdog */
+ omap_writel(0xAAAA, OMAP_WATCHDOG_SPR); /* TIMER_MODE */
+ while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10) ;
+ omap_writel(0x5555, OMAP_WATCHDOG_SPR); /* TIMER_MODE */
+ while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10) ;
+}
+
+static void omap_wdt_adjust_timeout(unsigned new_timeout)
+{
+ if (new_timeout < TIMER_MARGIN_MIN)
+ new_timeout = TIMER_MARGIN_DEFAULT;
+ if (new_timeout > TIMER_MARGIN_MAX)
+ new_timeout = TIMER_MARGIN_MAX;
+ timer_margin = new_timeout;
+}
+
+static void omap_wdt_set_timeout(void)
+{
+ u32 pre_margin = GET_WLDR_VAL(timer_margin);
+
+ /* just count up at 32 KHz */
+ while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
+ continue;
+ omap_writel(pre_margin, OMAP_WATCHDOG_LDR);
+ while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
+ continue;
+}
+
+/*
+ * Allow only one task to hold it open
+ */
+
+static int omap_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(1, (unsigned long *)&omap_wdt_users))
+ return -EBUSY;
+
+ if (cpu_is_omap16xx()) {
+ clk_enable(armwdt_ck); /* Enable the clock */
+ }
+
+ if (cpu_is_omap24xx()) {
+ clk_enable(mpu_wdt_ick); /* Enable the interface clock */
+ clk_enable(mpu_wdt_fck); /* Enable the functional clock */
+ }
+
+ /* initialize prescaler */
+ while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
+ continue;
+ omap_writel((1 << 5) | (PTV << 2), OMAP_WATCHDOG_CNTRL);
+ while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
+ continue;
+
+ omap_wdt_set_timeout();
+ omap_wdt_enable();
+ return 0;
+}
+
+static int omap_wdt_release(struct inode *inode, struct file *file)
+{
+ /*
+ * Shut off the timer unless NOWAYOUT is defined.
+ */
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+ omap_wdt_disable();
+
+ if (cpu_is_omap16xx()) {
+ clk_disable(armwdt_ck); /* Disable the clock */
+ clk_put(armwdt_ck);
+ armwdt_ck = NULL;
+ }
+
+ if (cpu_is_omap24xx()) {
+ clk_disable(mpu_wdt_ick); /* Disable the clock */
+ clk_disable(mpu_wdt_fck); /* Disable the clock */
+ clk_put(mpu_wdt_ick);
+ clk_put(mpu_wdt_fck);
+ mpu_wdt_ick = NULL;
+ mpu_wdt_fck = NULL;
+ }
+#else
+ printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n");
+#endif
+ omap_wdt_users = 0;
+ return 0;
+}
+
+static ssize_t
+omap_wdt_write(struct file *file, const char __user * data,
+ size_t len, loff_t * ppos)
+{
+ /* Refresh LOAD_TIME. */
+ if (len)
+ omap_wdt_ping();
+ return len;
+}
+
+static int
+omap_wdt_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int new_margin;
+ static struct watchdog_info ident = {
+ .identity = "OMAP Watchdog",
+ .options = WDIOF_SETTIMEOUT,
+ .firmware_version = 0,
+ };
+
+ switch (cmd) {
+ default:
+ return -ENOIOCTLCMD;
+ case WDIOC_GETSUPPORT:
+ return copy_to_user((struct watchdog_info __user *)arg, &ident,
+ sizeof(ident));
+ case WDIOC_GETSTATUS:
+ return put_user(0, (int __user *)arg);
+ case WDIOC_GETBOOTSTATUS:
+ if (cpu_is_omap16xx())
+ return put_user(omap_readw(ARM_SYSST),
+ (int __user *)arg);
+ if (cpu_is_omap24xx())
+ return put_user(omap_prcm_get_reset_sources(),
+ (int __user *)arg);
+ case WDIOC_KEEPALIVE:
+ omap_wdt_ping();
+ return 0;
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_margin, (int __user *)arg))
+ return -EFAULT;
+ omap_wdt_adjust_timeout(new_margin);
+
+ omap_wdt_disable();
+ omap_wdt_set_timeout();
+ omap_wdt_enable();
+
+ omap_wdt_ping();
+ /* Fall */
+ case WDIOC_GETTIMEOUT:
+ return put_user(timer_margin, (int __user *)arg);
+ }
+}
+
+static struct file_operations omap_wdt_fops = {
+ .owner = THIS_MODULE,
+ .write = omap_wdt_write,
+ .ioctl = omap_wdt_ioctl,
+ .open = omap_wdt_open,
+ .release = omap_wdt_release,
+};
+
+static struct miscdevice omap_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &omap_wdt_fops
+};
+
+static int __init omap_wdt_probe(struct platform_device *pdev)
+{
+ struct resource *res, *mem;
+ int ret;
+
+ /* reserve static register mappings */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENOENT;
+
+ mem = request_mem_region(res->start, res->end - res->start + 1,
+ pdev->name);
+ if (mem == NULL)
+ return -EBUSY;
+
+ platform_set_drvdata(pdev, mem);
+
+ omap_wdt_users = 0;
+
+ if (cpu_is_omap16xx()) {
+ armwdt_ck = clk_get(&pdev->dev, "armwdt_ck");
+ if (IS_ERR(armwdt_ck)) {
+ ret = PTR_ERR(armwdt_ck);
+ armwdt_ck = NULL;
+ goto fail;
+ }
+ }
+
+ if (cpu_is_omap24xx()) {
+ mpu_wdt_ick = clk_get(&pdev->dev, "mpu_wdt_ick");
+ if (IS_ERR(mpu_wdt_ick)) {
+ ret = PTR_ERR(mpu_wdt_ick);
+ mpu_wdt_ick = NULL;
+ goto fail;
+ }
+ mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck");
+ if (IS_ERR(mpu_wdt_fck)) {
+ ret = PTR_ERR(mpu_wdt_fck);
+ mpu_wdt_fck = NULL;
+ goto fail;
+ }
+ }
+
+ omap_wdt_disable();
+ omap_wdt_adjust_timeout(timer_margin);
+
+ omap_wdt_miscdev.dev = &pdev->dev;
+ ret = misc_register(&omap_wdt_miscdev);
+ if (ret)
+ goto fail;
+
+ pr_info("OMAP Watchdog Timer: initial timeout %d sec\n", timer_margin);
+
+ /* autogate OCP interface clock */
+ omap_writel(0x01, OMAP_WATCHDOG_SYS_CONFIG);
+ return 0;
+
+fail:
+ if (armwdt_ck)
+ clk_put(armwdt_ck);
+ if (mpu_wdt_ick)
+ clk_put(mpu_wdt_ick);
+ if (mpu_wdt_fck)
+ clk_put(mpu_wdt_fck);
+ release_resource(mem);
+ return ret;
+}
+
+static void omap_wdt_shutdown(struct platform_device *pdev)
+{
+ omap_wdt_disable();
+}
+
+static int omap_wdt_remove(struct platform_device *pdev)
+{
+ struct resource *mem = platform_get_drvdata(pdev);
+ misc_deregister(&omap_wdt_miscdev);
+ release_resource(mem);
+ if (armwdt_ck)
+ clk_put(armwdt_ck);
+ if (mpu_wdt_ick)
+ clk_put(mpu_wdt_ick);
+ if (mpu_wdt_fck)
+ clk_put(mpu_wdt_fck);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+/* REVISIT ... not clear this is the best way to handle system suspend; and
+ * it's very inappropriate for selective device suspend (e.g. suspending this
+ * through sysfs rather than by stopping the watchdog daemon). Also, this
+ * may not play well enough with NOWAYOUT...
+ */
+
+static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ if (omap_wdt_users)
+ omap_wdt_disable();
+ return 0;
+}
+
+static int omap_wdt_resume(struct platform_device *pdev)
+{
+ if (omap_wdt_users) {
+ omap_wdt_enable();
+ omap_wdt_ping();
+ }
+ return 0;
+}
+
+#else
+#define omap_wdt_suspend NULL
+#define omap_wdt_resume NULL
+#endif
+
+static struct platform_driver omap_wdt_driver = {
+ .probe = omap_wdt_probe,
+ .remove = omap_wdt_remove,
+ .shutdown = omap_wdt_shutdown,
+ .suspend = omap_wdt_suspend,
+ .resume = omap_wdt_resume,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "omap_wdt",
+ },
+};
+
+static int __init omap_wdt_init(void)
+{
+ return platform_driver_register(&omap_wdt_driver);
+}
+
+static void __exit omap_wdt_exit(void)
+{
+ platform_driver_unregister(&omap_wdt_driver);
+}
+
+module_init(omap_wdt_init);
+module_exit(omap_wdt_exit);
+
+MODULE_AUTHOR("George G. Davis");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
--- /dev/null
+/*
+ * linux/drivers/char/watchdog/omap_wdt.h
+ *
+ * BRIEF MODULE DESCRIPTION
+ * OMAP Watchdog timer register definitions
+ *
+ * Copyright (C) 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.
+ */
+
+#ifndef _OMAP_WATCHDOG_H
+#define _OMAP_WATCHDOG_H
+
+#define OMAP1610_WATCHDOG_BASE 0xfffeb000
+#define OMAP2420_WATCHDOG_BASE 0x48022000 /*WDT Timer 2 */
+
+#ifdef CONFIG_ARCH_OMAP24XX
+#define OMAP_WATCHDOG_BASE OMAP2420_WATCHDOG_BASE
+#else
+#define OMAP_WATCHDOG_BASE OMAP1610_WATCHDOG_BASE
+#define RM_RSTST_WKUP 0
+#endif
+
+#define OMAP_WATCHDOG_REV (OMAP_WATCHDOG_BASE + 0x00)
+#define OMAP_WATCHDOG_SYS_CONFIG (OMAP_WATCHDOG_BASE + 0x10)
+#define OMAP_WATCHDOG_STATUS (OMAP_WATCHDOG_BASE + 0x14)
+#define OMAP_WATCHDOG_CNTRL (OMAP_WATCHDOG_BASE + 0x24)
+#define OMAP_WATCHDOG_CRR (OMAP_WATCHDOG_BASE + 0x28)
+#define OMAP_WATCHDOG_LDR (OMAP_WATCHDOG_BASE + 0x2c)
+#define OMAP_WATCHDOG_TGR (OMAP_WATCHDOG_BASE + 0x30)
+#define OMAP_WATCHDOG_WPS (OMAP_WATCHDOG_BASE + 0x34)
+#define OMAP_WATCHDOG_SPR (OMAP_WATCHDOG_BASE + 0x48)
+
+/* Using the prescaler, the OMAP watchdog could go for many
+ * months before firing. These limits work without scaling,
+ * with the 60 second default assumed by most tools and docs.
+ */
+#define TIMER_MARGIN_MAX (24 * 60 * 60) /* 1 day */
+#define TIMER_MARGIN_DEFAULT 60 /* 60 secs */
+#define TIMER_MARGIN_MIN 1
+
+#define PTV 0 /* prescale */
+#define GET_WLDR_VAL(secs) (0xffffffff - ((secs) * (32768/(1<<PTV))) + 1)
+
+#endif /* _OMAP_WATCHDOG_H */
config I2C
tristate "I2C support"
+ default y if MACH_OMAP_H3 || MACH_OMAP_OSK
---help---
I2C (pronounce: I-square-C) is a slow serial bus protocol used in
many micro controller applications and developed by Philips. SMBus,
This driver can also be built as a module. If so, the module
will be called i2c-mv64xxx.
+config I2C_OMAP
+ tristate "OMAP I2C adapter"
+ depends on I2C && ARCH_OMAP
+ default y if MACH_OMAP_H3 || MACH_OMAP_OSK
+ help
+ Support for TI OMAP I2C driver. Say yes if you want to use the OMAP
+ I2C interface.
endmenu
obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o
obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
+obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
ifeq ($(CONFIG_I2C_DEBUG_BUS),y)
EXTRA_CFLAGS += -DDEBUG
--- /dev/null
+/*
+ * linux/drivers/i2c/i2c-omap.c
+ *
+ * TI OMAP I2C master mode driver
+ *
+ * Copyright (C) 2003 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * Updated to work with multiple I2C interfaces on 24xx by
+ * Tony Lindgren <tony@atomide.com> and Imre Deak <imre.deak@nokia.com>
+ * Copyright (C) 2005 Nokia Corporation
+ *
+ * Cleaned up by Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * ----------------------------------------------------------------------------
+ * This file was highly leveraged from i2c-elektor.c:
+ *
+ * Copyright 1995-97 Simon G. Vogl
+ * 1998-99 Hans Berglund
+ *
+ * With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
+ * Frodo Looijaard <frodol@dds.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+// #define DEBUG
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+
+/* ----- global defines ----------------------------------------------- */
+static const char driver_name[] = "i2c_omap";
+
+#define MODULE_NAME "OMAP I2C"
+#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000)) /* timeout waiting for the controller to respond */
+
+#define DEFAULT_OWN 1 /* default own I2C address */
+#define MAX_MESSAGES 65536 /* max number of messages */
+
+#define OMAP_I2C_REV_REG 0x00
+#define OMAP_I2C_IE_REG 0x04
+#define OMAP_I2C_STAT_REG 0x08
+#define OMAP_I2C_IV_REG 0x0c
+#define OMAP_I2C_SYSS_REG 0x10
+#define OMAP_I2C_BUF_REG 0x14
+#define OMAP_I2C_CNT_REG 0x18
+#define OMAP_I2C_DATA_REG 0x1c
+#define OMAP_I2C_SYSC_REG 0x20
+#define OMAP_I2C_CON_REG 0x24
+#define OMAP_I2C_OA_REG 0x28
+#define OMAP_I2C_SA_REG 0x2c
+#define OMAP_I2C_PSC_REG 0x30
+#define OMAP_I2C_SCLL_REG 0x34
+#define OMAP_I2C_SCLH_REG 0x38
+#define OMAP_I2C_SYSTEST_REG 0x3c
+
+/* I2C Interrupt Enable Register (OMAP_I2C_IE): */
+#define OMAP_I2C_IE_XRDY (1 << 4) /* TX data ready int enable */
+#define OMAP_I2C_IE_RRDY (1 << 3) /* RX data ready int enable */
+#define OMAP_I2C_IE_ARDY (1 << 2) /* Access ready int enable */
+#define OMAP_I2C_IE_NACK (1 << 1) /* No ack interrupt enable */
+#define OMAP_I2C_IE_AL (1 << 0) /* Arbitration lost int ena */
+
+/* I2C Status Register (OMAP_I2C_STAT): */
+#define OMAP_I2C_STAT_SBD (1 << 15) /* Single byte data */
+#define OMAP_I2C_STAT_BB (1 << 12) /* Bus busy */
+#define OMAP_I2C_STAT_ROVR (1 << 11) /* Receive overrun */
+#define OMAP_I2C_STAT_XUDF (1 << 10) /* Transmit underflow */
+#define OMAP_I2C_STAT_AAS (1 << 9) /* Address as slave */
+#define OMAP_I2C_STAT_AD0 (1 << 8) /* Address zero */
+#define OMAP_I2C_STAT_XRDY (1 << 4) /* Transmit data ready */
+#define OMAP_I2C_STAT_RRDY (1 << 3) /* Receive data ready */
+#define OMAP_I2C_STAT_ARDY (1 << 2) /* Register access ready */
+#define OMAP_I2C_STAT_NACK (1 << 1) /* No ack interrupt enable */
+#define OMAP_I2C_STAT_AL (1 << 0) /* Arbitration lost int ena */
+
+/* I2C Buffer Configuration Register (OMAP_I2C_BUF): */
+#define OMAP_I2C_BUF_RDMA_EN (1 << 15) /* RX DMA channel enable */
+#define OMAP_I2C_BUF_XDMA_EN (1 << 7) /* TX DMA channel enable */
+
+/* I2C Configuration Register (OMAP_I2C_CON): */
+#define OMAP_I2C_CON_EN (1 << 15) /* I2C module enable */
+#define OMAP_I2C_CON_BE (1 << 14) /* Big endian mode */
+#define OMAP_I2C_CON_STB (1 << 11) /* Start byte mode (master) */
+#define OMAP_I2C_CON_MST (1 << 10) /* Master/slave mode */
+#define OMAP_I2C_CON_TRX (1 << 9) /* TX/RX mode (master only) */
+#define OMAP_I2C_CON_XA (1 << 8) /* Expand address */
+#define OMAP_I2C_CON_RM (1 << 2) /* Repeat mode (master only) */
+#define OMAP_I2C_CON_STP (1 << 1) /* Stop cond (master only) */
+#define OMAP_I2C_CON_STT (1 << 0) /* Start condition (master) */
+
+/* I2C System Test Register (OMAP_I2C_SYSTEST): */
+#define OMAP_I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */
+#define OMAP_I2C_SYSTEST_FREE (1 << 14) /* Free running mode */
+#define OMAP_I2C_SYSTEST_TMODE_MASK (3 << 12) /* Test mode select */
+#define OMAP_I2C_SYSTEST_TMODE_SHIFT (12) /* Test mode select */
+#define OMAP_I2C_SYSTEST_SCL_I (1 << 3) /* SCL line sense in */
+#define OMAP_I2C_SYSTEST_SCL_O (1 << 2) /* SCL line drive out */
+#define OMAP_I2C_SYSTEST_SDA_I (1 << 1) /* SDA line sense in */
+#define OMAP_I2C_SYSTEST_SDA_O (1 << 0) /* SDA line drive out */
+
+/* I2C System Status register (OMAP_I2C_SYSS): */
+#define OMAP_I2C_SYSS_RDONE 1 /* Reset Done */
+
+/* I2C System Configuration Register (OMAP_I2C_SYSC): */
+#define OMAP_I2C_SYSC_SRST (1 << 1) /* Soft Reset */
+
+/* REVISIT: Use platform_data instead of module parameters */
+static int clock = 100; /* Default: Fast Mode = 400 KHz, Standard = 100 KHz */
+module_param(clock, int, 0);
+MODULE_PARM_DESC(clock, "Set I2C clock in kHz: 100 or 400 (Fast Mode)");
+
+static int own;
+module_param(own, int, 0);
+MODULE_PARM_DESC(own, "Address of OMAP I2C master (0 for default == 1)");
+
+struct omap_i2c_dev {
+ struct device *dev;
+ void __iomem *base; /* virtual */
+ int irq;
+ struct clk *iclk; /* Interface clock */
+ struct clk *fclk; /* Functional clock */
+ struct completion cmd_complete;
+ u16 cmd_err;
+ u8 *buf;
+ size_t buf_len;
+ struct i2c_adapter adapter;
+ unsigned rev1:1;
+ u8 own_address;
+};
+
+static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev,
+ int reg, u16 val)
+{
+ __raw_writew(val, i2c_dev->base + reg);
+}
+
+static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
+{
+ return __raw_readw(i2c_dev->base + reg);
+}
+
+static int omap_i2c_get_clocks(struct omap_i2c_dev *dev)
+{
+ if (cpu_is_omap24xx()) {
+ dev->iclk = clk_get(dev->dev, "i2c_ick");
+ if (IS_ERR(dev->iclk)) {
+ return -ENODEV;
+ }
+ dev->fclk = clk_get(dev->dev, "i2c_fck");
+ if (IS_ERR(dev->fclk)) {
+ clk_put(dev->fclk);
+ return -ENODEV;
+ }
+ }
+
+ if (cpu_class_is_omap1()) {
+ dev->fclk = clk_get(dev->dev, "i2c_fck");
+ if (IS_ERR(dev->fclk))
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void omap_i2c_put_clocks(struct omap_i2c_dev *dev)
+{
+ clk_put(dev->fclk);
+ dev->fclk = NULL;
+ if (dev->iclk != NULL) {
+ clk_put(dev->iclk);
+ dev->iclk = NULL;
+ }
+}
+
+static void omap_i2c_enable_clocks(struct omap_i2c_dev *dev)
+{
+ if (dev->iclk != NULL)
+ clk_enable(dev->iclk);
+ clk_enable(dev->fclk);
+}
+
+static void omap_i2c_disable_clocks(struct omap_i2c_dev *dev)
+{
+ if (dev->iclk != NULL)
+ clk_disable(dev->iclk);
+ clk_disable(dev->fclk);
+}
+
+static void omap_i2c_reset(struct omap_i2c_dev *dev)
+{
+ u16 psc;
+ unsigned long fclk_rate;
+
+ if (!dev->rev1) {
+ omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, OMAP_I2C_SYSC_SRST);
+ /* For some reason we need to set the EN bit before the
+ * reset done bit gets set. */
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
+ while (!(omap_i2c_read_reg(dev, OMAP_I2C_SYSS_REG) & 0x01));
+ }
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+
+ if (cpu_class_is_omap1()) {
+ struct clk *armxor_ck;
+ unsigned long armxor_rate;
+
+ armxor_ck = clk_get(NULL, "armxor_ck");
+ if (IS_ERR(armxor_ck)) {
+ printk(KERN_WARNING "i2c: Could not get armxor_ck\n");
+ armxor_rate = 12000000;
+ } else {
+ armxor_rate = clk_get_rate(armxor_ck);
+ clk_put(armxor_ck);
+ }
+
+ if (armxor_rate > 16000000)
+ psc = (armxor_rate + 8000000) / 12000000;
+ else
+ psc = 0;
+
+ fclk_rate = armxor_rate;
+ } else if (cpu_class_is_omap2()) {
+ fclk_rate = 12000000;
+ psc = 0;
+ }
+
+ /* Setup clock prescaler to obtain approx 12MHz I2C module clock: */
+ omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, psc);
+
+ /* Program desired operating rate */
+ fclk_rate /= (psc + 1) * 1000;
+ if (psc > 2)
+ psc = 2;
+
+ omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG,
+ fclk_rate / (clock * 2) - 7 + psc);
+ omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG,
+ fclk_rate / (clock * 2) - 7 + psc);
+
+ /* Set Own Address: */
+ omap_i2c_write_reg(dev, OMAP_I2C_OA_REG, dev->own_address);
+
+ /* Take the I2C module out of reset: */
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
+
+ /* Enable interrupts */
+ omap_i2c_write_reg(dev, OMAP_I2C_IE_REG,
+ (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
+ OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
+ OMAP_I2C_IE_AL));
+}
+
+/*
+ * Waiting on Bus Busy
+ */
+static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev)
+{
+ unsigned long timeout;
+
+ timeout = jiffies + OMAP_I2C_TIMEOUT;
+ while (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(dev->dev, "timeout waiting for bus ready\n");
+ return -ETIMEDOUT;
+ }
+ msleep(1);
+ }
+
+ return 0;
+}
+
+/*
+ * Low level master read/write transaction.
+ */
+static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
+ struct i2c_msg *msg, int stop)
+{
+ struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
+ int r;
+ u16 w;
+ u8 zero_byte = 0;
+
+ dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
+ msg->addr, msg->len, msg->flags, stop);
+
+ omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr);
+
+ /* Sigh, seems we can't do zero length transactions. Thus, we
+ * can't probe for devices w/o actually sending/receiving at least
+ * a single byte. So we'll set count to 1 for the zero length
+ * transaction case and hope we don't cause grief for some
+ * arbitrary device due to random byte write/read during
+ * probes.
+ */
+ /* REVISIT: Could the STB bit of I2C_CON be used with probing? */
+ if (msg->len == 0) {
+ dev->buf = &zero_byte;
+ dev->buf_len = 1;
+ } else {
+ dev->buf = msg->buf;
+ dev->buf_len = msg->len;
+ }
+ omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len);
+
+ init_completion(&dev->cmd_complete);
+ dev->cmd_err = 0;
+
+ w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT;
+ if (msg->flags & I2C_M_TEN)
+ w |= OMAP_I2C_CON_XA;
+ if (!(msg->flags & I2C_M_RD))
+ w |= OMAP_I2C_CON_TRX;
+ if (stop)
+ w |= OMAP_I2C_CON_STP;
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
+
+ r = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
+ OMAP_I2C_TIMEOUT);
+ dev->buf_len = 0;
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ dev_err(dev->dev, "controller timed out\n");
+ omap_i2c_reset(dev);
+ return -ETIMEDOUT;
+ }
+
+ if (likely(!dev->cmd_err))
+ return 0;
+
+ /* We have an error */
+ if (dev->cmd_err & OMAP_I2C_STAT_NACK) {
+ if (msg->flags & I2C_M_IGNORE_NAK)
+ return 0;
+ if (stop) {
+ u16 w;
+
+ w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
+ w |= OMAP_I2C_CON_STP;
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
+ }
+ return -EREMOTEIO;
+ }
+ if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR |
+ OMAP_I2C_STAT_XUDF))
+ omap_i2c_reset(dev);
+ return -EIO;
+}
+
+
+/*
+ * Prepare controller for a transaction and call omap_i2c_xfer_msg
+ * to do the work during IRQ processing.
+ */
+static int
+omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+ struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
+ int i;
+ int r = 0;
+
+ if (num < 1 || num > MAX_MESSAGES)
+ return -EINVAL;
+
+ /* Check for valid parameters in messages */
+ for (i = 0; i < num; i++)
+ if (msgs[i].buf == NULL)
+ return -EINVAL;
+
+ omap_i2c_enable_clocks(dev);
+
+ /* REVISIT: initialize and use adap->retries */
+ if ((r = omap_i2c_wait_for_bb(dev)) < 0)
+ goto out;
+
+ for (i = 0; i < num; i++) {
+ dev_dbg(dev->dev, "msg: %d, addr: 0x%04x, len: %d, flags: 0x%x\n",
+ i, msgs[i].addr, msgs[i].len, msgs[i].flags);
+ r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)));
+ if (r != 0)
+ break;
+ }
+
+ if (r == 0)
+ r = num;
+out:
+ omap_i2c_disable_clocks(dev);
+ return r;
+}
+
+static u32
+omap_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static inline void
+omap_i2c_complete_cmd(struct omap_i2c_dev *dev, u16 err)
+{
+ dev->cmd_err |= err;
+ complete(&dev->cmd_complete);
+}
+
+static inline void
+omap_i2c_ack_stat(struct omap_i2c_dev *dev, u16 stat)
+{
+ omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
+}
+
+#ifdef CONFIG_ARCH_OMAP15XX
+static irqreturn_t
+omap_i2c_rev1_isr(int this_irq, void *dev_id, struct pt_regs *regs)
+{
+ struct omap_i2c_dev *dev = dev_id;
+ u16 iv, w;
+
+ iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG);
+ switch (iv) {
+ case 0x00: /* None */
+ break;
+ case 0x01: /* Arbitration lost */
+ dev_err(dev->dev, "Arbitration lost\n");
+ omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_AL);
+ break;
+ case 0x02: /* No acknowledgement */
+ omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_NACK);
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_STP);
+ break;
+ case 0x03: /* Register access ready */
+ omap_i2c_complete_cmd(dev, 0);
+ break;
+ case 0x04: /* Receive data ready */
+ if (dev->buf_len) {
+ w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
+ *dev->buf++ = w;
+ dev->buf_len--;
+ if (dev->buf_len) {
+ *dev->buf++ = w >> 8;
+ dev->buf_len--;
+ }
+ } else
+ dev_err(dev->dev, "RRDY IRQ while no data requested\n");
+ break;
+ case 0x05: /* Transmit data ready */
+ if (dev->buf_len) {
+ w = *dev->buf++;
+ dev->buf_len--;
+ if (dev->buf_len) {
+ w |= *dev->buf++ << 8;
+ dev->buf_len--;
+ }
+ omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
+ } else
+ dev_err(dev->dev, "XRDY IRQ while no data to send\n");
+ break;
+ default:
+ return IRQ_NONE;
+ }
+
+ return IRQ_HANDLED;
+}
+#endif
+
+static irqreturn_t
+omap_i2c_isr(int this_irq, void *dev_id, struct pt_regs *regs)
+{
+ struct omap_i2c_dev *dev = dev_id;
+ u16 bits;
+ u16 stat, w;
+ int count = 0;
+
+ bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
+ while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) {
+ dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat);
+ if (count++ == 100) {
+ dev_warn(dev->dev, "Too much work in one IRQ\n");
+ break;
+ }
+
+ omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
+
+ if (stat & OMAP_I2C_STAT_ARDY) {
+ omap_i2c_complete_cmd(dev, 0);
+ continue;
+ }
+ if (stat & OMAP_I2C_STAT_RRDY) {
+ w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
+ if (dev->buf_len) {
+ *dev->buf++ = w;
+ dev->buf_len--;
+ if (dev->buf_len) {
+ *dev->buf++ = w >> 8;
+ dev->buf_len--;
+ }
+ } else
+ dev_err(dev->dev, "RRDY IRQ while no data requested\n");
+ omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RRDY);
+ continue;
+ }
+ if (stat & OMAP_I2C_STAT_XRDY) {
+ int bail_out = 0;
+
+ w = 0;
+ if (dev->buf_len) {
+ w = *dev->buf++;
+ dev->buf_len--;
+ if (dev->buf_len) {
+ w |= *dev->buf++ << 8;
+ dev->buf_len--;
+ }
+ } else
+ dev_err(dev->dev, "XRDY IRQ while no data to send\n");
+#if 0
+ if (!(stat & OMAP_I2C_STAT_BB)) {
+ dev_warn(dev->dev, "XRDY while bus not busy\n");
+ bail_out = 1;
+ }
+#endif
+ omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
+ omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY);
+ if (bail_out)
+ omap_i2c_complete_cmd(dev, 1 << 15);
+ continue;
+ }
+ if (stat & OMAP_I2C_STAT_ROVR) {
+ dev_err(dev->dev, "Receive overrun\n");
+ dev->cmd_err |= OMAP_I2C_STAT_ROVR;
+ }
+ if (stat & OMAP_I2C_STAT_XUDF) {
+ dev_err(dev->dev, "Transmit overflow\n");
+ dev->cmd_err |= OMAP_I2C_STAT_XUDF;
+ }
+ if (stat & OMAP_I2C_STAT_NACK) {
+ omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_NACK);
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_STP);
+ }
+ if (stat & OMAP_I2C_STAT_AL) {
+ dev_err(dev->dev, "Arbitration lost\n");
+ omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_AL);
+ }
+ }
+
+ return count ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static struct i2c_algorithm omap_i2c_algo = {
+ .master_xfer = omap_i2c_xfer,
+ .functionality = omap_i2c_func,
+};
+
+static int
+omap_i2c_probe(struct platform_device *pdev)
+{
+ struct omap_i2c_dev *dev;
+ struct i2c_adapter *adap;
+ struct resource *mem, *irq;
+ int r;
+
+ /* NOTE: driver uses the static register mapping */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "no mem resource?\n");
+ return -ENODEV;
+ }
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!irq) {
+ dev_err(&pdev->dev, "no irq resource?\n");
+ return -ENODEV;
+ }
+
+ r = (int) request_mem_region(mem->start, (mem->end - mem->start) + 1,
+ driver_name);
+ if (!r) {
+ dev_err(&pdev->dev, "I2C region already claimed\n");
+ return -EBUSY;
+ }
+
+ if (clock > 200)
+ clock = 400; /* Fast mode */
+ else
+ clock = 100; /* Standard mode */
+
+ dev = kzalloc(sizeof(struct omap_i2c_dev), GFP_KERNEL);
+ if (!dev) {
+ r = -ENOMEM;
+ goto do_release_region;
+ }
+
+ /* FIXME: Get own address from platform_data */
+ if (own >= 1 && own < 0x7f)
+ dev->own_address = own;
+ else
+ own = DEFAULT_OWN;
+
+ dev->dev = &pdev->dev;
+ dev->irq = irq->start;
+ dev->base = (void __iomem *) IO_ADDRESS(mem->start);
+ platform_set_drvdata(pdev, dev);
+
+ if ((r = omap_i2c_get_clocks(dev)) != 0)
+ goto do_free_mem;
+
+ omap_i2c_enable_clocks(dev);
+
+#ifdef CONFIG_ARCH_OMAP15XX
+ dev->rev1 = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) < 0x20;
+#endif
+
+ /* reset ASAP, clearing any IRQs */
+ omap_i2c_reset(dev);
+
+#ifdef CONFIG_ARCH_OMAP15XX
+ r = request_irq(dev->irq, dev->rev1 ? omap_i2c_rev1_isr : omap_i2c_isr,
+ 0, driver_name, dev);
+#else
+ r = request_irq(dev->irq, omap_i2c_isr, 0, driver_name, dev);
+#endif
+ if (r) {
+ dev_err(dev->dev, "failure requesting irq %i\n", dev->irq);
+ goto do_unuse_clocks;
+ }
+ r = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
+ dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n",
+ pdev->id - 1, r >> 4, r & 0xf, clock);
+
+ adap = &dev->adapter;
+ i2c_set_adapdata(adap, dev);
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_HWMON;
+ strncpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
+ adap->algo = &omap_i2c_algo;
+ adap->dev.parent = &pdev->dev;
+
+ /* i2c device drivers may be active on return from add_adapter() */
+ r = i2c_add_adapter(adap);
+ if (r) {
+ dev_err(dev->dev, "failure adding adapter\n");
+ goto do_free_irq;
+ }
+
+ omap_i2c_disable_clocks(dev);
+
+ return 0;
+
+do_free_irq:
+ free_irq(dev->irq, dev);
+do_unuse_clocks:
+ omap_i2c_disable_clocks(dev);
+ omap_i2c_put_clocks(dev);
+do_free_mem:
+ kfree(dev);
+do_release_region:
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+ release_mem_region(mem->start, (mem->end - mem->start) + 1);
+
+ return r;
+}
+
+static int
+omap_i2c_remove(struct platform_device *pdev)
+{
+ struct omap_i2c_dev *dev = platform_get_drvdata(pdev);
+ struct resource *mem;
+
+ free_irq(dev->irq, dev);
+ i2c_del_adapter(&dev->adapter);
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+ omap_i2c_put_clocks(dev);
+ kfree(dev);
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem->start, (mem->end - mem->start) + 1);
+ return 0;
+}
+
+static struct platform_driver omap_i2c_driver = {
+ .probe = omap_i2c_probe,
+ .remove = omap_i2c_remove,
+ .driver = {
+ .name = (char *)driver_name,
+ },
+};
+
+/* I2C may be needed to bring up other drivers */
+static int __init
+omap_i2c_init_driver(void)
+{
+ return platform_driver_register(&omap_i2c_driver);
+}
+subsys_initcall(omap_i2c_init_driver);
+
+static void __exit omap_i2c_exit_driver(void)
+{
+ platform_driver_unregister(&omap_i2c_driver);
+}
+module_exit(omap_i2c_exit_driver);
+
+MODULE_AUTHOR("MontaVista Software, Inc. (and others)");
+MODULE_DESCRIPTION("TI OMAP I2C bus adapter");
+MODULE_LICENSE("GPL");
This driver can also be built as a module. If so, the module
will be called tps65010.
+config SENSORS_TLV320AIC23
+ tristate "Texas Instruments TLV320AIC23 Codec"
+ depends on I2C && I2C_OMAP
+ help
+ If you say yes here you get support for the I2C control
+ interface for Texas Instruments TLV320AIC23 audio codec.
+
+config GPIOEXPANDER_OMAP
+ bool "GPIO Expander PCF8574PWR for OMAP"
+ depends on I2C && (ARCH_OMAP16XX || ARCH_OMAP24XX)
+ help
+ If you say yes here you get support for I/O expander calls
+ to configure IrDA, Camera and audio devices.
+
+config MENELAUS
+ bool "Menelaus PM chip"
+ depends on I2C=y && ARCH_OMAP24XX
+ help
+ Say yes here if you have Menelaus chip on your board
+
config SENSORS_M41T00
tristate "ST M41T00 RTC chip"
depends on I2C && PPC32
obj-$(CONFIG_SENSORS_RTC8564) += rtc8564.o
obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
obj-$(CONFIG_TPS65010) += tps65010.o
+obj-$(CONFIG_SENSORS_TLV320AIC23) += tlv320aic23.o
+obj-$(CONFIG_GPIOEXPANDER_OMAP) += gpio_expander_omap.o
+obj-$(CONFIG_MENELAUS) += menelaus.o
obj-$(CONFIG_RTC_X1205_I2C) += x1205.o
ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
--- /dev/null
+/*
+ * drivers/i2c/chips/gpio_expander_omap.c
+ *
+ * Copyright (C) 2004 Texas Instruments Inc
+ * Author:
+ *
+ * gpio expander is used to configure IrDA, camera and audio devices on omap 1710 processor.
+ *
+ * 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/types.h>
+#include <linux/i2c.h>
+#include <linux/errno.h>
+
+int read_gpio_expa(u8 * val, int addr);
+int write_gpio_expa(u8 val, int addr);
+
+int write_gpio_expa(u8 val, int addr)
+{
+ struct i2c_adapter *adap;
+ int err;
+ struct i2c_msg msg[1];
+ unsigned char data[1];
+
+ adap = i2c_get_adapter(0);
+ if (!adap)
+ return -ENODEV;
+ msg->addr = addr; /* I2C address of GPIO EXPA */
+ msg->flags = 0;
+ msg->len = 1;
+ msg->buf = data;
+ data[0] = val;
+ err = i2c_transfer(adap, msg, 1);
+ if (err >= 0)
+ return 0;
+ return err;
+}
+
+/* Read from I/O EXPANDER on the H3 board.
+ * The IO expanders need an independent I2C client driver.
+ */
+
+int read_gpio_expa(u8 * val, int addr)
+{
+ struct i2c_adapter *adap;
+ int err;
+ struct i2c_msg msg[1];
+ unsigned char data[1];
+
+ adap = i2c_get_adapter(0);
+ if (!adap)
+ return -ENODEV;
+ msg->addr = addr; /* I2C address of GPIO EXPA */
+ msg->flags = I2C_M_RD;
+ msg->len = 2;
+ msg->buf = data;
+ err = i2c_transfer(adap, msg, 1);
+ *val = data[0];
+
+ if (err >= 0)
+ return 0;
+ return err;
+}
+
+EXPORT_SYMBOL(read_gpio_expa);
+EXPORT_SYMBOL(write_gpio_expa);
+
#include <linux/workqueue.h>
#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/gpio.h>
#include <asm/arch/usb.h>
+#include <asm/arch/mux.h>
#ifndef DEBUG
#define DRIVER_VERSION "24 August 2004"
-#define DRIVER_NAME (isp1301_driver.name)
+#define DRIVER_NAME (isp1301_driver.driver.name)
MODULE_DESCRIPTION("ISP1301 USB OTG Transceiver Driver");
MODULE_LICENSE("GPL");
void (*i2c_release)(struct device *dev);
int irq;
+ int irq_type;
u32 last_otg_ctrl;
unsigned working:1;
/*-------------------------------------------------------------------------*/
-#ifdef CONFIG_MACH_OMAP_H2
+#if defined(CONFIG_MACH_OMAP_H2) || \
+ defined(CONFIG_MACH_OMAP_H3)
/* board-specific PM hooks */
-#include <asm/arch/gpio.h>
-#include <asm/arch/mux.h>
-#include <asm/mach-types.h>
-
#if defined(CONFIG_TPS65010) || defined(CONFIG_TPS65010_MODULE)
}
-/* products will deliver OTG messages with LEDs, GUI, etc */
-static inline void notresponding(struct isp1301 *isp)
+#else
+
+static void enable_vbus_draw(struct isp1301 *isp, unsigned mA)
{
- printk(KERN_NOTICE "OTG device not responding.\n");
+ pr_debug("%s UNIMPL\n", __FUNCTION__);
}
+static void enable_vbus_source(struct isp1301 *isp)
+{
+ pr_debug("%s UNIMPL\n", __FUNCTION__);
+}
#endif
/*-------------------------------------------------------------------------*/
+/* products will deliver OTG messages with LEDs, GUI, etc */
+static inline void notresponding(struct isp1301 *isp)
+{
+ printk(KERN_NOTICE "OTG device not responding.\n");
+}
+
+/*-------------------------------------------------------------------------*/
+
/* only two addresses possible */
#define ISP_BASE 0x2c
static unsigned short normal_i2c[] = {
static void update_otg1(struct isp1301 *isp, u8 int_src)
{
u32 otg_ctrl;
+ u8 int_id;
otg_ctrl = OTG_CTRL_REG
& OTG_CTRL_MASK
}
if (int_src & INTR_VBUS_VLD)
otg_ctrl |= OTG_VBUSVLD;
- if (int_src & INTR_ID_GND) { /* default-A */
+
+ int_id = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE);
+
+ if (int_id & INTR_ID_GND) { /* default-A */
if (isp->otg.state == OTG_STATE_B_IDLE
|| isp->otg.state == OTG_STATE_UNDEFINED) {
a_idle(isp, "init");
/* update the OTG controller state to match the isp1301; may
* trigger OPRT_CHG irqs for changes going to the isp1301.
*/
- update_otg1(isp, isp_stat);
+ update_otg1(isp, stat); // pass the actual interrupt latch status
update_otg2(isp, isp_bstat);
check_state(isp, __FUNCTION__);
#endif
if (machine_is_omap_h2())
omap_free_gpio(2);
+ if (machine_is_omap_h3())
+ omap_free_gpio(14);
+
isp->timer.data = 0;
set_bit(WORK_STOP, &isp->todo);
del_timer_sync(&isp->timer);
power_up(isp);
- if (machine_is_omap_h2())
+ if (machine_is_omap_h2() || machine_is_omap_h3())
isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
dev_info(&isp->client.dev, "A-Host sessions ok\n");
power_up(isp);
isp->otg.state = OTG_STATE_B_IDLE;
- if (machine_is_omap_h2())
+ if (machine_is_omap_h2() || machine_is_omap_h3())
isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
- INTR_SESS_VLD);
+ INTR_SESS_VLD | INTR_VBUS_VLD);
isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
- INTR_VBUS_VLD);
+ INTR_VBUS_VLD | INTR_SESS_VLD);
dev_info(&isp->client.dev, "B-Peripheral sessions ok\n");
dump_regs(isp, __FUNCTION__);
* So do this part as early as possible...
*/
switch (isp->otg.state) {
+ case OTG_STATE_B_PERIPHERAL:
+ isp->otg.state = OTG_STATE_B_WAIT_ACON;
+ isp1301_defer_work(isp, WORK_UPDATE_ISP);
+ break;
case OTG_STATE_B_HOST:
isp->otg.state = OTG_STATE_B_PERIPHERAL;
/* caller will suspend next */
isp->timer.data = (unsigned long) isp;
isp->irq = -1;
+ isp->irq_type = 0;
isp->client.addr = address;
i2c_set_clientdata(&isp->client, isp);
isp->client.adapter = bus;
}
#endif
- if (machine_is_omap_h2()) {
+ if (machine_is_omap_h2() || machine_is_omap_h3()) {
/* full speed signaling by default */
isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1,
MC1_SPEED_REG);
isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2,
MC2_SPD_SUSP_CTRL);
+ }
+ if (machine_is_omap_h2()) {
/* IRQ wired at M14 */
omap_cfg_reg(M14_1510_GPIO2);
isp->irq = OMAP_GPIO_IRQ(2);
omap_request_gpio(2);
omap_set_gpio_direction(2, 1);
- omap_set_gpio_edge_ctrl(2, OMAP_GPIO_FALLING_EDGE);
+ isp->irq_type = SA_TRIGGER_FALLING;
+ }
+
+ if (machine_is_omap_h3()) {
+ /* IRQ wired at N21 */
+ omap_cfg_reg(N21_1710_GPIO14);
+ isp->irq = OMAP_GPIO_IRQ(14);
+ omap_request_gpio(14);
+ omap_set_gpio_direction(14, 1);
+ isp->irq_type = SA_TRIGGER_FALLING;
}
status = request_irq(isp->irq, isp1301_irq,
- SA_SAMPLE_RANDOM, DRIVER_NAME, isp);
+ isp->irq_type, DRIVER_NAME, isp);
if (status < 0) {
dev_dbg(&i2c->dev, "can't get IRQ %d, err %d\n",
isp->irq, status);
--- /dev/null
+/*
+ * drivers/i2c/chips/menelaus.c
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * Some parts based tps65010.c:
+ * Copyright (C) 2004 Texas Instruments and
+ * Copyright (C) 2004-2005 David Brownell
+ *
+ * Some parts based on tlv320aic24.c:
+ * Copyright (C) by Kai Svahn <kai.svahn@nokia.com>
+ *
+ * Changes for interrupt handling and clean-up by
+ * Tony Lindgren <tony@atomide.com> and Imre Deak <imre.deak@nokia.com>
+ * 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/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/irq.h>
+
+#include <asm/arch/mux.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/menelaus.h>
+
+#define DRIVER_NAME "menelaus"
+
+#define pr_err(fmt, arg...) printk(KERN_ERR DRIVER_NAME ": ", ## arg);
+
+#define MENELAUS_I2C_ADDRESS 0x72
+
+#define MENELAUS_REV 0x01
+#define MENELAUS_VCORE_CTRL1 0x02
+#define MENELAUS_VCORE_CTRL2 0x03
+#define MENELAUS_VCORE_CTRL3 0x04
+#define MENELAUS_VCORE_CTRL4 0x05
+#define MENELAUS_VCORE_CTRL5 0x06
+#define MENELAUS_DCDC_CTRL1 0x07
+#define MENELAUS_DCDC_CTRL2 0x08
+#define MENELAUS_DCDC_CTRL3 0x09
+#define MENELAUS_LDO_CTRL1 0x0A
+#define MENELAUS_LDO_CTRL2 0x0B
+#define MENELAUS_LDO_CTRL3 0x0C
+#define MENELAUS_LDO_CTRL4 0x0D
+#define MENELAUS_LDO_CTRL5 0x0E
+#define MENELAUS_LDO_CTRL6 0x0F
+#define MENELAUS_LDO_CTRL7 0x10
+#define MENELAUS_LDO_CTRL8 0x11
+#define MENELAUS_SLEEP_CTRL1 0x12
+#define MENELAUS_SLEEP_CTRL2 0x13
+#define MENELAUS_DEVICE_OFF 0x14
+#define MENELAUS_OSC_CTRL 0x15
+#define MENELAUS_DETECT_CTRL 0x16
+#define MENELAUS_INT_MASK1 0x17
+#define MENELAUS_INT_MASK2 0x18
+#define MENELAUS_INT_STATUS1 0x19
+#define MENELAUS_INT_STATUS2 0x1A
+#define MENELAUS_INT_ACK1 0x1B
+#define MENELAUS_INT_ACK2 0x1C
+#define MENELAUS_GPIO_CTRL 0x1D
+#define MENELAUS_GPIO_IN 0x1E
+#define MENELAUS_GPIO_OUT 0x1F
+#define MENELAUS_BBSMS 0x20
+#define MENELAUS_RTC_CTRL 0x21
+#define MENELAUS_RTC_UPDATE 0x22
+#define MENELAUS_RTC_SEC 0x23
+#define MENELAUS_RTC_MIN 0x24
+#define MENELAUS_RTC_HR 0x25
+#define MENELAUS_RTC_DAY 0x26
+#define MENELAUS_RTC_MON 0x27
+#define MENELAUS_RTC_YR 0x28
+#define MENELAUS_RTC_WKDAY 0x29
+#define MENELAUS_RTC_AL_SEC 0x2A
+#define MENELAUS_RTC_AL_MIN 0x2B
+#define MENELAUS_RTC_AL_HR 0x2C
+#define MENELAUS_RTC_AL_DAY 0x2D
+#define MENELAUS_RTC_AL_MON 0x2E
+#define MENELAUS_RTC_AL_YR 0x2F
+#define MENELAUS_RTC_COMP_MSB 0x30
+#define MENELAUS_RTC_COMP_LSB 0x31
+#define MENELAUS_S1_PULL_EN 0x32
+#define MENELAUS_S1_PULL_DIR 0x33
+#define MENELAUS_S2_PULL_EN 0x34
+#define MENELAUS_S2_PULL_DIR 0x35
+#define MENELAUS_MCT_CTRL1 0x36
+#define MENELAUS_MCT_CTRL2 0x37
+#define MENELAUS_MCT_CTRL3 0x38
+#define MENELAUS_MCT_PIN_ST 0x39
+#define MENELAUS_DEBOUNCE1 0x3A
+
+#define IH_MENELAUS_IRQS 12
+#define MENELAUS_MMC_S1CD_IRQ 0 /* MMC slot 1 card change */
+#define MENELAUS_MMC_S2CD_IRQ 1 /* MMC slot 2 card change */
+#define MENELAUS_MMC_S1D1_IRQ 2 /* MMC DAT1 low in slot 1 */
+#define MENELAUS_MMC_S2D1_IRQ 3 /* MMC DAT1 low in slot 2 */
+#define MENELAUS_LOWBAT_IRQ 4 /* Low battery */
+#define MENELAUS_HOTDIE_IRQ 5 /* Hot die detect */
+#define MENELAUS_UVLO_IRQ 6 /* UVLO detect */
+#define MENELAUS_TSHUT_IRQ 7 /* Thermal shutdown */
+#define MENELAUS_RTCTMR_IRQ 8 /* RTC timer */
+#define MENELAUS_RTCALM_IRQ 9 /* RTC alarm */
+#define MENELAUS_RTCERR_IRQ 10 /* RTC error */
+#define MENELAUS_PSHBTN_IRQ 11 /* Push button */
+#define MENELAUS_RESERVED12_IRQ 12 /* Reserved */
+#define MENELAUS_RESERVED13_IRQ 13 /* Reserved */
+#define MENELAUS_RESERVED14_IRQ 14 /* Reserved */
+#define MENELAUS_RESERVED15_IRQ 15 /* Reserved */
+
+static void menelaus_work(void * _menelaus);
+
+/* Initialized by menelaus_init */
+static unsigned short normal_i2c[] = { MENELAUS_I2C_ADDRESS, I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD;
+
+struct menelaus_chip {
+ unsigned long initialized;
+ struct semaphore lock;
+ struct i2c_client client;
+ struct work_struct work;
+ int irq;
+ void *handlers[16];
+ void (*mmc_callback)(unsigned long data, u8 mask);
+ unsigned long mmc_callback_data;
+};
+
+static struct menelaus_chip menelaus;
+
+static void menelaus_write(u8 value, u8 reg)
+{
+ if (i2c_smbus_write_byte_data(&menelaus.client, reg, value) < 0)
+ pr_err("write error");
+}
+
+static u8 menelaus_read(u8 reg)
+{
+ int val = i2c_smbus_read_byte_data(&menelaus.client, reg);
+
+ if (val < 0) {
+ pr_err("read error");
+ return 0;
+ }
+
+ return val;
+}
+
+static void menelaus_enable_irq(int irq)
+{
+ if (irq > 7)
+ menelaus_write(menelaus_read(MENELAUS_INT_MASK2) &
+ ~(1 << (irq - 8)), MENELAUS_INT_MASK2);
+ else
+ menelaus_write(menelaus_read(MENELAUS_INT_MASK1) &
+ ~(1 << irq), MENELAUS_INT_MASK1);
+}
+
+static void menelaus_disable_irq(int irq)
+{
+ if (irq > 7)
+ menelaus_write(menelaus_read(MENELAUS_INT_MASK2)
+ | (1 << (irq - 8)), MENELAUS_INT_MASK2);
+ else
+ menelaus_write(menelaus_read(MENELAUS_INT_MASK1)
+ | (1 << irq), MENELAUS_INT_MASK1);
+}
+
+static void menelaus_ack_irq(int irq)
+{
+ if (irq > 7)
+ menelaus_write(1 << (irq - 8), MENELAUS_INT_ACK2);
+ else
+ menelaus_write(1 << irq, MENELAUS_INT_ACK1);
+}
+
+/* Adds a handler for an interrupt. Does not run in interrupt context */
+static int menelaus_add_irq_work(int irq, void * handler)
+{
+ down(&menelaus.lock);
+ menelaus.handlers[irq] = handler;
+ menelaus_enable_irq(irq);
+ up(&menelaus.lock);
+
+ return 0;
+}
+
+/* Removes handler for an interrupt */
+static void menelaus_remove_irq_work(int irq)
+{
+ down(&menelaus.lock);
+ menelaus_disable_irq(irq);
+ menelaus.handlers[irq] = NULL;
+ up(&menelaus.lock);
+}
+
+/*-----------------------------------------------------------------------*/
+
+/*
+ * Toggles the MMC slots between open-drain and push-pull mode.
+ * We always set both slots the same way.
+ */
+void menelaus_mmc_opendrain(int enable)
+{
+ unsigned char reg = menelaus_read(MENELAUS_MCT_CTRL1);
+
+ if (enable)
+ reg |= (0x3 << 2);
+ else
+ reg &= ~(0x3 << 2);
+
+ menelaus_write(reg, MENELAUS_MCT_CTRL1);
+}
+EXPORT_SYMBOL(menelaus_mmc_opendrain);
+
+/*
+ * Gets scheduled when a card detect interrupt happens. Note that in some cases
+ * this line is wired to card cover switch rather than the card detect switch
+ * in each slot. In this case the cards are not seen by menelaus.
+ * FIXME: Add handling for D1 too
+ */
+static int menelaus_mmc_cd_work(struct menelaus_chip *menelaus)
+{
+ unsigned char reg;
+ unsigned char card_mask = 0;
+
+ reg = menelaus_read(MENELAUS_MCT_PIN_ST);
+
+ if (!(reg & 0x1))
+ card_mask |= (1 << 0);
+
+ if (!(reg & 0x2))
+ card_mask |= (1 << 1);
+
+ if (menelaus->mmc_callback)
+ menelaus->mmc_callback(menelaus->mmc_callback_data, card_mask);
+
+ return 0;
+}
+
+/* Initializes MMC slots */
+void menelaus_mmc_register(void (*callback)(unsigned long data, u8 card_mask), unsigned long data)
+{
+ int reg;
+
+ /* DCDC3 to 3V */
+ reg = menelaus_read(MENELAUS_DCDC_CTRL1);
+ reg |= 0x6 << 4;
+ menelaus_write(reg, MENELAUS_DCDC_CTRL1);
+
+ reg = menelaus_read(MENELAUS_DCDC_CTRL3);
+ reg |= 0x6;
+ menelaus_write(reg, MENELAUS_DCDC_CTRL3);
+
+ /* Enable both slots, do not set auto shutdown */
+ reg = menelaus_read(MENELAUS_MCT_CTRL3);
+ reg |= 0x3;
+ menelaus_write(reg, MENELAUS_MCT_CTRL3);
+
+ /* Enable card detect for both slots, slot 2 powered from DCDC3 */
+ reg = menelaus_read(MENELAUS_MCT_CTRL2);
+ reg |= 0xf0;
+ menelaus_write(reg, MENELAUS_MCT_CTRL2);
+
+ /* Set both slots in open-drain mode, card detect normally closed */
+ reg = menelaus_read(MENELAUS_MCT_CTRL1);
+ reg |= 0xfc;
+ menelaus_write(reg, MENELAUS_MCT_CTRL1);
+
+ /* Set MMC voltage */
+ reg = menelaus_read(MENELAUS_LDO_CTRL7);
+ reg |= 0x03;
+ menelaus_write(reg, MENELAUS_LDO_CTRL7);
+
+ menelaus.mmc_callback_data = data;
+ menelaus.mmc_callback = callback;
+
+ menelaus_add_irq_work(MENELAUS_MMC_S1CD_IRQ, menelaus_mmc_cd_work);
+ menelaus_add_irq_work(MENELAUS_MMC_S2CD_IRQ, menelaus_mmc_cd_work);
+ menelaus_add_irq_work(MENELAUS_MMC_S1D1_IRQ, menelaus_mmc_cd_work);
+ menelaus_add_irq_work(MENELAUS_MMC_S2D1_IRQ, menelaus_mmc_cd_work);
+}
+EXPORT_SYMBOL(menelaus_mmc_register);
+
+void menelaus_mmc_remove(void)
+{
+ menelaus_remove_irq_work(MENELAUS_MMC_S1CD_IRQ);
+ menelaus_remove_irq_work(MENELAUS_MMC_S2CD_IRQ);
+ menelaus_remove_irq_work(MENELAUS_MMC_S1D1_IRQ);
+ menelaus_remove_irq_work(MENELAUS_MMC_S2D1_IRQ);
+
+ menelaus.mmc_callback = NULL;
+ menelaus.mmc_callback_data = 0;
+
+ /* FIXME: Shutdown MMC components of Menelaus */
+}
+EXPORT_SYMBOL(menelaus_mmc_remove);
+
+/*-----------------------------------------------------------------------*/
+
+/* Handles Menelaus interrupts. Does not run in interrupt context */
+static void menelaus_work(void * _menelaus)
+{
+ struct menelaus_chip *menelaus = _menelaus;
+ int (*handler)(struct menelaus_chip *menelaus);
+
+ while (1) {
+ int i;
+ unsigned char isr;
+
+ isr = menelaus_read(MENELAUS_INT_STATUS1) |
+ (menelaus_read(MENELAUS_INT_STATUS2) << 8);
+
+ if (!isr)
+ break;
+
+ for (i = 0; i < IH_MENELAUS_IRQS; i++) {
+ if (isr & (1 << i)) {
+ down(&menelaus->lock);
+ menelaus_disable_irq(i);
+ menelaus_ack_irq(i);
+ if (menelaus->handlers[i]) {
+ handler = menelaus->handlers[i];
+ handler(menelaus);
+ }
+ menelaus_enable_irq(i);
+ up(&menelaus->lock);
+ }
+ }
+ }
+ enable_irq(menelaus->irq);
+}
+
+/*
+ * We cannot use I2C in interrupt context, so we just schedule work.
+ */
+static irqreturn_t menelaus_irq(int irq, void *_menelaus, struct pt_regs *regs)
+{
+ struct menelaus_chip *menelaus = _menelaus;
+
+ disable_irq_nosync(irq);
+ (void)schedule_work(&menelaus->work);
+
+ return IRQ_HANDLED;
+}
+
+static struct i2c_driver menelaus_i2c_driver;
+
+static int menelaus_probe(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *c;
+ int rev = 0;
+ int err = 0, i;
+
+ if (test_and_set_bit(0, &menelaus.initialized))
+ return -EBUSY;
+
+ c = &menelaus.client;
+ strncpy(c->name, DRIVER_NAME, sizeof(c->name));
+ c->addr = address;
+ c->adapter = adapter;
+ c->driver = &menelaus_i2c_driver;
+ c->flags = 0;
+
+ if ((err = i2c_attach_client(c)) < 0) {
+ pr_err("couldn't attach\n");
+ goto fail1;
+ }
+
+ /* If a true probe check the device */
+ if (kind < 0 && (rev = menelaus_read(MENELAUS_REV)) < 0) {
+ pr_err("device not found");
+ err = -ENODEV;
+ goto fail2;
+ }
+
+ /* Most likely Menelaus interrupt is at SYS_NIRQ */
+ omap_cfg_reg(W19_24XX_SYS_NIRQ);
+ menelaus.irq = INT_24XX_SYS_NIRQ;
+
+ /* Disable all menelaus interrupts */
+ for (i = 0; i < 16; i++) {
+ menelaus_ack_irq(i);
+ menelaus_disable_irq(i);
+ }
+
+ err = request_irq(menelaus.irq, menelaus_irq, SA_INTERRUPT,
+ DRIVER_NAME, &menelaus);
+ if (err)
+ printk(KERN_ERR "Could not get Menelaus IRQ\n");
+
+ init_MUTEX(&menelaus.lock);
+ INIT_WORK(&menelaus.work, menelaus_work, &menelaus);
+
+ if (kind < 0)
+ pr_info("Menelaus rev %d.%d\n", rev >> 4, rev & 0x0f);
+
+ return 0;
+
+fail2:
+ i2c_detach_client(c);
+fail1:
+ clear_bit(0, &menelaus.initialized);
+ return err;
+}
+
+static int menelaus_remove(struct i2c_client *client)
+{
+ int err;
+
+ free_irq(menelaus.irq, &menelaus);
+
+ if ((err = i2c_detach_client(client))) {
+ pr_err("client deregistration failed\n");
+ return err;
+ }
+
+ clear_bit(0, &menelaus.initialized);
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------------*/
+
+static int menelaus_scan_bus(struct i2c_adapter *bus)
+{
+ if (!i2c_check_functionality(bus, I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_WRITE_BYTE)) {
+ pr_err("invalid i2c bus functionality\n");
+ return -EINVAL;
+ }
+
+ return i2c_probe(bus, &addr_data, menelaus_probe);
+}
+
+static struct i2c_driver menelaus_i2c_driver = {
+ .driver {
+ .name = DRIVER_NAME,
+ },
+ .id = I2C_DRIVERID_MISC, /*FIXME:accroding to i2c-ids.h */
+ .class = I2C_CLASS_HWMON,
+ .attach_adapter = menelaus_scan_bus,
+ .detach_client = menelaus_remove,
+};
+
+static int __init menelaus_init(void)
+{
+ int res;
+
+ if ((res = i2c_add_driver(&menelaus_i2c_driver)) < 0) {
+ pr_err("driver registration failed\n");
+ return res;
+ }
+
+ return 0;
+}
+
+static void __exit menelaus_exit(void)
+{
+ if (i2c_del_driver(&menelaus_i2c_driver) < 0)
+ pr_err("driver remove failed\n");
+
+ /* FIXME: Shutdown menelaus parts that can be shut down */
+}
+
+MODULE_AUTHOR("Texas Instruments, Inc.");
+MODULE_DESCRIPTION("I2C interface for Menelaus.");
+MODULE_LICENSE("GPL");
+
+module_init(menelaus_init);
+module_exit(menelaus_exit);
--- /dev/null
+/*
+ * Texas Instrumens TLV320AIC23 audio codec's i2c interface.
+ *
+ * Copyright (c) by Kai Svahn <kai.svahn@nokia.com>
+ * Copyright (c) by Jussi Laako <jussi.laako@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/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <asm/io.h>
+#include <asm/arch/aic23.h>
+#include <asm/arch/mcbsp.h>
+
+#define TLV320AIC23_VERSION "1.8"
+#define TLV320AIC23_DATE "10-Feb-2006"
+#define MAX_VOL 100
+#define MIN_VOL 0
+#define MAX_GAIN 100
+#define MIN_GAIN 0
+#define OUTPUT_VOLUME_MIN LHV_MIN
+#define OUTPUT_VOLUME_MAX LHV_MAX
+#define OUTPUT_VOLUME_RANGE (OUTPUT_VOLUME_MAX - OUTPUT_VOLUME_MIN)
+#define INPUT_VOLUME_MIN LIV_MIN
+#define INPUT_VOLUME_MAX LIV_MAX
+#define INPUT_VOLUME_RANGE (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
+
+/* I2C Addresses to scan */
+static unsigned short normal_i2c[] = { TLV320AIC23ID1, TLV320AIC23ID2, \
+ I2C_CLIENT_END };
+/*static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };*/
+
+/* This makes all addr_data:s */
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver tlv320aic23_driver;
+static struct i2c_client *new_client;
+static int selftest;
+
+static struct tlv320aic23_info {
+ u16 volume_reg_left;
+ u16 volume_reg_right;
+ u16 input_gain_reg_left;
+ u16 input_gain_reg_right;
+ u16 power; /* For POWER_DOWN_CONTROL_ADDR */
+ u16 mask; /* For ANALOG_AUDIO_CONTROL_ADDR */
+ int mic_loopback;
+ int mic_enable;
+ int sta;
+ int power_down;
+ int initialization;
+} tlv320aic23_info_l;
+
+static int _tlv320aic23_write_value(struct i2c_client *client, u8 reg, u16 value)
+{
+ u8 val, wreg;
+
+ /* TLV320AIC23 has 7 bit address and 9 bits of data
+ * so we need to switch one data bit into reg and rest
+ * of data into val
+ */
+
+ wreg = (reg << 1);
+ val = (0x01 & (value >> 8));
+ wreg = (wreg | val);
+ val = (0x00ff & value);
+
+ return i2c_smbus_write_byte_data(client, wreg, val);
+}
+
+int tlv320aic23_write_value(u8 reg, u16 value)
+{
+ static struct i2c_client *client;
+ client = new_client;
+ _tlv320aic23_write_value(client, reg, value);
+
+ return 0;
+}
+
+static int tlv320aic23_detect_client(struct i2c_adapter *adapter, int address,
+ int kind)
+{
+ int err = 0;
+ const char *client_name = "TLV320AIC23 Audio Codec";
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_WRITE_BYTE)) {
+ printk(KERN_WARNING "%s functinality check failed\n",
+ client_name);
+ return err;
+ }
+
+ if (!(new_client = kmalloc(sizeof(struct i2c_client),
+ GFP_KERNEL))) {
+ err = -ENOMEM;
+ printk(KERN_WARNING "Couldn't allocate memory for %s\n",
+ client_name);
+ return err;
+ }
+
+ memset(new_client, 0x00, sizeof(struct i2c_client));
+ new_client->addr = address;
+ new_client->adapter = adapter;
+ new_client->driver = &tlv320aic23_driver;
+ new_client->flags = 0;
+ strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
+
+ if ((err = i2c_attach_client(new_client))) {
+ printk(KERN_WARNING "Couldn't attach %s\n", client_name);
+ kfree(new_client);
+ return err;
+ }
+ return 0;
+}
+
+static int tlv320aic23_detach_client(struct i2c_client *client)
+{
+ int err;
+
+ if ((err = i2c_detach_client(client))) {
+ printk("tlv320aic23.o: Client deregistration failed, \
+ client not detached.\n");
+ return err;
+ }
+ kfree(client);
+ return 0;
+}
+
+static int tlv320aic23_attach_adapter(struct i2c_adapter *adapter)
+{
+ int res;
+
+ res = i2c_probe(adapter, &addr_data, &tlv320aic23_detect_client);
+ return res;
+}
+
+static struct i2c_driver tlv320aic23_driver = {
+ .driver {
+ .name = "OMAP+TLV320AIC23 codec",
+ /*.flags = I2C_DF_NOTIFY,*/
+ },
+ .id = I2C_DRIVERID_MISC, /* Experimental ID */
+ .attach_adapter = tlv320aic23_attach_adapter,
+ .detach_client = tlv320aic23_detach_client,
+};
+
+/*
+ * Configures the McBSP3 which is used to send clock to the AIC23 codec.
+ * The input clock rate from DSP is 12MHz.
+ * The DSP clock must be on before this is called.
+ */
+static int omap_mcbsp3_tlv320aic23_clock_init(void)
+{
+ u16 w;
+
+ /* enable 12MHz clock to mcbsp 1 & 3 */
+ __raw_writew(__raw_readw(DSP_IDLECT2) | (1<<1), DSP_IDLECT2);
+ __raw_writew(__raw_readw(DSP_RSTCT2) | 1 | 1<<1, DSP_RSTCT2);
+
+ /* disable sample rate generator */
+ OMAP_MCBSP_WRITE(OMAP1610_MCBSP3_BASE, SPCR1, 0x0000);
+ OMAP_MCBSP_WRITE(OMAP1610_MCBSP3_BASE, SPCR2, 0x0000);
+
+ /* pin control register */
+ OMAP_MCBSP_WRITE(OMAP1610_MCBSP3_BASE, PCR0,(CLKXM | CLKXP | CLKRP));
+
+ /* configure srg to send 12MHz pulse from dsp peripheral clock */
+ OMAP_MCBSP_WRITE(OMAP1610_MCBSP3_BASE, SRGR1, 0x0000);
+ OMAP_MCBSP_WRITE(OMAP1610_MCBSP3_BASE, SRGR2, CLKSM);
+
+ /* enable sample rate generator */
+ w = OMAP_MCBSP_READ(OMAP1610_MCBSP3_BASE, SPCR2);
+ OMAP_MCBSP_WRITE(OMAP1610_MCBSP3_BASE, SPCR2, (w | FREE | GRST));
+ printk("Clock enabled to MCBSP1 & 3 \n");
+
+ return 0;
+}
+
+static void update_volume_left(int volume)
+{
+ u16 val = 0;
+ val = ((volume * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MIN;
+ tlv320aic23_write_value(LEFT_CHANNEL_VOLUME_ADDR, val);
+ tlv320aic23_info_l.volume_reg_left = volume;
+}
+
+static void update_volume_right(int volume)
+{
+ u16 val = 0;
+ val = ((volume * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MIN;
+ tlv320aic23_write_value(RIGHT_CHANNEL_VOLUME_ADDR, val);
+ tlv320aic23_info_l.volume_reg_right = volume;
+}
+
+static void set_mic(int mic_en)
+{
+ u16 dg_ctrl;
+
+ if (mic_en) {
+ tlv320aic23_info_l.power = OSC_OFF | LINE_OFF;
+ dg_ctrl = ADCHP_ON;
+ tlv320aic23_info_l.mask &= ~MICM_MUTED;
+ tlv320aic23_info_l.mask |= MICB_20DB; /* STE_ENABLED */
+ } else {
+ tlv320aic23_info_l.power =
+ OSC_OFF | ADC_OFF | MIC_OFF | LINE_OFF;
+ dg_ctrl = 0x00;
+ tlv320aic23_info_l.mask =
+ DAC_SELECTED | INSEL_MIC | MICM_MUTED;
+ }
+ tlv320aic23_write_value(POWER_DOWN_CONTROL_ADDR,
+ tlv320aic23_info_l.power);
+ tlv320aic23_write_value(DIGITAL_AUDIO_CONTROL_ADDR, dg_ctrl);
+ tlv320aic23_write_value(ANALOG_AUDIO_CONTROL_ADDR,
+ tlv320aic23_info_l.mask);
+ tlv320aic23_info_l.mic_enable = mic_en;
+
+ printk(KERN_INFO "tlv320aic23 mic state: %i\n", mic_en);
+}
+
+static void tlv320aic23_init_power(void)
+{
+ tlv320aic23_write_value(RESET_CONTROL_ADDR, 0x00);
+
+ if (tlv320aic23_info_l.initialization == 0) {
+ tlv320aic23_write_value(LEFT_CHANNEL_VOLUME_ADDR, LHV_MIN);
+ tlv320aic23_write_value(RIGHT_CHANNEL_VOLUME_ADDR, LHV_MIN);
+ }
+ else {
+ update_volume_left(tlv320aic23_info_l.volume_reg_left);
+ update_volume_right(tlv320aic23_info_l.volume_reg_right);
+ }
+
+ tlv320aic23_info_l.mask = DAC_SELECTED | INSEL_MIC | MICM_MUTED;
+ tlv320aic23_write_value(ANALOG_AUDIO_CONTROL_ADDR,
+ tlv320aic23_info_l.mask);
+ tlv320aic23_write_value(DIGITAL_AUDIO_CONTROL_ADDR, 0x00);
+ tlv320aic23_write_value(DIGITAL_AUDIO_FORMAT_ADDR, LRP_ON | FOR_DSP);
+ tlv320aic23_write_value(SAMPLE_RATE_CONTROL_ADDR, USB_CLK_ON);
+ tlv320aic23_write_value(DIGITAL_INTERFACE_ACT_ADDR, ACT_ON);
+ tlv320aic23_info_l.power = OSC_OFF | ADC_OFF | MIC_OFF | LINE_OFF;
+ tlv320aic23_write_value(POWER_DOWN_CONTROL_ADDR,
+ tlv320aic23_info_l.power);
+
+ /* enable mic input */
+ if (tlv320aic23_info_l.mic_enable)
+ set_mic(tlv320aic23_info_l.mic_enable);
+
+ printk(KERN_INFO "tlv320aic23_init_power() done\n");
+}
+
+void tlv320aic23_power_down(void)
+{
+ printk("tlv320aic23 powering down\n");
+ tlv320aic23_write_value(POWER_DOWN_CONTROL_ADDR, 0xff);
+ tlv320aic23_info_l.power_down = 1;
+}
+
+void tlv320aic23_power_up(void)
+{
+ printk("tlv320aic23 powering up\n");
+ tlv320aic23_init_power();
+ tlv320aic23_info_l.power_down = 0;
+}
+
+/*----------------------------------------------------------------------*/
+/* sysfs initializations */
+/*----------------------------------------------------------------------*/
+
+static ssize_t store_volume_left(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ signed volume;
+
+ sscanf(buf, "%i", &volume);
+
+ if (volume < MIN_VOL) {
+ tlv320aic23_power_down();
+ return count;
+ } else if (volume > MIN_VOL && tlv320aic23_info_l.power_down) {
+ tlv320aic23_info_l.volume_reg_left = volume;
+ tlv320aic23_power_up();
+ return count;
+ }
+ if (volume > MAX_VOL)
+ volume = MAX_VOL;
+
+ update_volume_left(volume);
+ return count;
+}
+
+static ssize_t show_volume_left(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%u\n", tlv320aic23_info_l.volume_reg_left);
+}
+
+static DEVICE_ATTR(volume_left, S_IRUGO | S_IWUGO,
+ show_volume_left, store_volume_left);
+
+static ssize_t store_volume_right(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ signed volume;
+
+ sscanf(buf, "%i", &volume);
+ if (volume < MIN_VOL) {
+ tlv320aic23_power_down();
+ return count;
+ } else if (volume > MIN_VOL && tlv320aic23_info_l.power_down) {
+ tlv320aic23_info_l.volume_reg_right = volume;
+ tlv320aic23_power_up();
+ return count;
+ }
+ if (volume > MAX_VOL)
+ volume = MAX_VOL;
+
+ update_volume_right(volume);
+ return count;
+}
+
+static ssize_t show_volume_right(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%u\n", tlv320aic23_info_l.volume_reg_right);
+}
+
+static DEVICE_ATTR(volume_right, S_IRUGO | S_IWUGO,
+ show_volume_right, store_volume_right);
+
+static ssize_t store_gain_left(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ u16 val = 0;
+ unsigned gain;
+
+ sscanf(buf, "%u", &gain);
+ if (gain > MAX_VOL)
+ gain = MAX_VOL;
+
+ val = ((gain * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
+ tlv320aic23_write_value(LEFT_LINE_VOLUME_ADDR, val);
+ tlv320aic23_info_l.input_gain_reg_left = gain;
+
+ return count;
+}
+
+static ssize_t show_gain_left(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%u\n", tlv320aic23_info_l.input_gain_reg_left);
+}
+
+static DEVICE_ATTR(gain_left, S_IRUGO | S_IWUSR, show_gain_left,
+ store_gain_left);
+
+static ssize_t store_gain_right(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ u16 val = 0;
+ unsigned gain;
+
+ sscanf(buf, "%u", &gain);
+ if (gain > MAX_VOL)
+ gain = MAX_VOL;
+
+ val = ((gain * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
+ tlv320aic23_write_value(RIGHT_LINE_VOLUME_ADDR, val);
+ tlv320aic23_info_l.input_gain_reg_right = gain;
+
+ return count;
+}
+
+static ssize_t show_gain_right(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%u\n", tlv320aic23_info_l.input_gain_reg_right);
+}
+
+static DEVICE_ATTR(gain_right, S_IRUGO | S_IWUSR, show_gain_right,
+ store_gain_right);
+
+static ssize_t store_mic_loopback(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int mic;
+
+ sscanf(buf, "%i", &mic);
+ if (mic > 0) {
+ tlv320aic23_write_value(POWER_DOWN_CONTROL_ADDR, \
+ OSC_OFF | ADC_OFF | LINE_OFF);
+ tlv320aic23_info_l.mask = STE_ENABLED | DAC_SELECTED \
+ | INSEL_MIC | MICB_20DB;
+ tlv320aic23_write_value(ANALOG_AUDIO_CONTROL_ADDR,
+ tlv320aic23_info_l.mask);
+ mic = 1;
+ }
+ else {
+ tlv320aic23_write_value(POWER_DOWN_CONTROL_ADDR, \
+ OSC_OFF | ADC_OFF | MIC_OFF | LINE_OFF);
+ mic = 0;
+ }
+ tlv320aic23_info_l.mic_loopback = mic;
+
+ return count;
+}
+
+static ssize_t show_mic_loopback(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%i\n", tlv320aic23_info_l.mic_loopback);
+}
+
+static DEVICE_ATTR(mic_loopback, S_IRUGO | S_IWUSR,
+ show_mic_loopback, store_mic_loopback);
+
+static ssize_t store_st_attenuation(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned sta;
+ u16 tmp;
+
+ sscanf(buf, "%u", &sta);
+ if (sta > 3)
+ sta = 3;
+
+ tmp = tlv320aic23_info_l.mask;
+ tmp &= 0x3f;
+
+ tlv320aic23_info_l.mask = tmp | STA_REG(sta);
+ tlv320aic23_write_value(ANALOG_AUDIO_CONTROL_ADDR,
+ tlv320aic23_info_l.mask);
+ tlv320aic23_info_l.sta = sta;
+
+ return count;
+}
+
+static ssize_t show_st_attenuation(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%i\n", tlv320aic23_info_l.sta);
+}
+
+static DEVICE_ATTR(st_attenuation, S_IRUGO | S_IWUSR,
+ show_st_attenuation, store_st_attenuation);
+
+static ssize_t store_mic_enable(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int mic;
+
+ sscanf(buf, "%i", &mic);
+ set_mic(mic);
+
+ return count;
+}
+
+static ssize_t show_mic_enable(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%i\n", tlv320aic23_info_l.mic_enable);
+}
+
+static DEVICE_ATTR(mic_enable, S_IRUGO | S_IWUSR,
+ show_mic_enable, store_mic_enable);
+
+static ssize_t show_audio_selftest(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%i\n", selftest);
+}
+
+static DEVICE_ATTR(audio_selftest, S_IRUGO | S_IWUSR,
+ show_audio_selftest, NULL);
+
+static int audio_i2c_probe(struct platform_device *dev)
+{
+ int r;
+
+ if ((r = device_create_file(&dev->dev, &dev_attr_volume_left)) != 0)
+ return r;
+ else if ((r = device_create_file(&dev->dev,
+ &dev_attr_volume_right)) != 0)
+ goto err_volume_left;
+ else if ((r = device_create_file(&dev->dev,
+ &dev_attr_gain_right)) != 0)
+ goto err_volume_right;
+ else if ((r = device_create_file(&dev->dev,
+ &dev_attr_gain_left)) != 0)
+ goto err_gain_right;
+ else if ((r = device_create_file(&dev->dev,
+ &dev_attr_mic_loopback)) != 0)
+ goto err_gain_left;
+ else if ((r = device_create_file(&dev->dev,
+ &dev_attr_mic_enable)) != 0)
+ goto err_mic_loopback;
+ else if ((r = device_create_file(&dev->dev,
+ &dev_attr_st_attenuation)) != 0)
+ goto err_mic_enable;
+ else if ((r = device_create_file(&dev->dev,
+ &dev_attr_audio_selftest)) != 0)
+ goto err_st_attenuation;
+ else
+ return r;
+
+err_st_attenuation:
+ device_remove_file(&dev->dev, &dev_attr_st_attenuation);
+err_mic_enable:
+ device_remove_file(&dev->dev, &dev_attr_mic_enable);
+err_mic_loopback:
+ device_remove_file(&dev->dev, &dev_attr_mic_loopback);
+err_gain_left:
+ device_remove_file(&dev->dev, &dev_attr_gain_left);
+err_gain_right:
+ device_remove_file(&dev->dev, &dev_attr_gain_right);
+err_volume_right:
+ device_remove_file(&dev->dev, &dev_attr_volume_right);
+err_volume_left:
+ device_remove_file(&dev->dev, &dev_attr_volume_left);
+
+ return r;
+}
+
+static int audio_i2c_remove(struct platform_device *dev)
+{
+ device_remove_file(&dev->dev, &dev_attr_st_attenuation);
+ device_remove_file(&dev->dev, &dev_attr_mic_enable);
+ device_remove_file(&dev->dev, &dev_attr_mic_loopback);
+ device_remove_file(&dev->dev, &dev_attr_gain_left);
+ device_remove_file(&dev->dev, &dev_attr_gain_right);
+ device_remove_file(&dev->dev, &dev_attr_volume_right);
+ device_remove_file(&dev->dev, &dev_attr_volume_left);
+
+ return 0;
+}
+
+/*----------------------------------------------------------------*/
+/* PM functions */
+/*----------------------------------------------------------------*/
+
+static void audio_i2c_shutdown(struct platform_device *dev)
+{
+ /* Let's mute the codec before powering off to prevent
+ * glitch in the sound
+ */
+ tlv320aic23_write_value(LEFT_CHANNEL_VOLUME_ADDR, LHV_MIN);
+ tlv320aic23_write_value(RIGHT_CHANNEL_VOLUME_ADDR, LHV_MIN);
+ tlv320aic23_power_down();
+}
+
+static int audio_i2c_suspend(struct platform_device *dev, pm_message_t state)
+{
+ /* Let's mute the codec before powering off to prevent
+ * glitch in the sound
+ */
+ tlv320aic23_write_value(LEFT_CHANNEL_VOLUME_ADDR, LHV_MIN);
+ tlv320aic23_write_value(RIGHT_CHANNEL_VOLUME_ADDR, LHV_MIN);
+ tlv320aic23_power_down();
+
+ return 0;
+}
+
+static int audio_i2c_resume(struct platform_device *dev)
+{
+ tlv320aic23_power_up();
+
+ return 0;
+}
+
+static struct platform_driver audio_i2c_driver = {
+ .driver {
+ .owner = THIS_MODULE,
+ .name = "audio-i2c",
+ },
+ .shutdown = audio_i2c_shutdown,
+ .probe = audio_i2c_probe,
+ .remove = audio_i2c_remove,
+ .suspend = audio_i2c_suspend,
+ .resume = audio_i2c_resume,
+};
+
+static struct platform_device audio_i2c_device = {
+ .name = "audio-i2c",
+ .id = -1,
+};
+
+/*----------------------------------------------------------------*/
+
+static int __init tlv320aic23_init(void)
+{
+ selftest = 0;
+ tlv320aic23_info_l.initialization = 0;
+
+ if (i2c_add_driver(&tlv320aic23_driver)) {
+ printk("tlv320aic23 i2c: Driver registration failed, \
+ module not inserted.\n");
+ selftest= -ENODEV;
+ return selftest;
+ }
+
+ if (platform_driver_register(&audio_i2c_driver)) {
+ printk(KERN_WARNING "Failed to register audio i2c driver\n");
+ selftest = -ENODEV;
+ return selftest;
+ }
+
+ if (platform_device_register(&audio_i2c_device)) {
+ printk(KERN_WARNING "Failed to register audio i2c device\n");
+ platform_driver_unregister(&audio_i2c_driver);
+ selftest = -ENODEV;
+ return selftest;
+ }
+ omap_mcbsp3_tlv320aic23_clock_init();
+ tlv320aic23_power_up();
+ tlv320aic23_info_l.initialization = 1;
+ printk("TLV320AIC23 I2C version %s (%s)\n",
+ TLV320AIC23_VERSION, TLV320AIC23_DATE);
+
+ return selftest;
+}
+
+static void __exit tlv320aic23_exit(void)
+{
+ int res;
+
+ tlv320aic23_power_down();
+ if ((res = i2c_del_driver(&tlv320aic23_driver)))
+ printk("tlv320aic23 i2c: Driver remove failed, module not removed.\n");
+
+ platform_device_unregister(&audio_i2c_device);
+ platform_driver_unregister(&audio_i2c_driver);
+}
+
+MODULE_AUTHOR("Kai Svahn <kai.svahn@nokia.com>");
+MODULE_DESCRIPTION("I2C interface for TLV320AIC23 codec.");
+MODULE_LICENSE("GPL");
+
+module_init(tlv320aic23_init)
+module_exit(tlv320aic23_exit)
+
+EXPORT_SYMBOL(tlv320aic23_write_value);
+EXPORT_SYMBOL(tlv320aic23_power_up);
+EXPORT_SYMBOL(tlv320aic23_power_down);
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#undef DEBUG
#include <linux/config.h>
#include <linux/kernel.h>
/*-------------------------------------------------------------------------*/
#define DRIVER_VERSION "2 May 2005"
-#define DRIVER_NAME (tps65010_driver.name)
+#define DRIVER_NAME (tps65010_driver.driver.name)
MODULE_DESCRIPTION("TPS6501x Power Management Driver");
MODULE_LICENSE("GPL");
-static unsigned short normal_i2c[] = { 0x48, /* 0x49, */ I2C_CLIENT_END };
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
+/* only two addresses possible */
+#define TPS_BASE 0x48
+static unsigned short normal_i2c[] = {
+ TPS_BASE,
+ I2C_CLIENT_END };
I2C_CLIENT_INSMOD;
struct i2c_client client;
struct semaphore lock;
int irq;
+ int irq_type;
struct work_struct work;
struct dentry *file;
unsigned charging:1;
u8 chgstatus, regstatus, chgconf;
u8 nmask1, nmask2;
- /* not currently tracking GPIO state */
+ /* plus four GPIOs, probably used to switch power */
};
#define POWER_POLL_DELAY msecs_to_jiffies(800)
(regstatus & TPS_REG_COVER) ? " uncover" : "",
(regstatus & TPS_REG_UVLO) ? " UVLO" : "",
(regstatus & TPS_REG_NO_CHG) ? " NO_CHG" : "",
- (regstatus & TPS_REG_PG_LD02) ? " ld02_bad" : "",
+ (regstatus & TPS_REG_PG_LD02) ? " ld01_bad" : "",
(regstatus & TPS_REG_PG_LD01) ? " ld01_bad" : "",
(regstatus & TPS_REG_PG_MAIN) ? " main_bad" : "",
(regstatus & TPS_REG_PG_CORE) ? " core_bad" : "");
static void dbg_chgconf(int por, char *buf, size_t len, u8 chgconfig)
{
- const char *hibit;
+ char *hibit;
if (por)
hibit = (chgconfig & TPS_CHARGE_POR)
seq_printf(s, "defgpio %02x mask3 %02x\n", value, v2);
for (i = 0; i < 4; i++) {
- if (value & (1 << (4 + i)))
+ if (value & (1 << (4 +i)))
seq_printf(s, " gpio%d-out %s\n", i + 1,
(value & (1 << i)) ? "low" : "hi ");
else
debugfs_remove(tps->file);
if (i2c_detach_client(client) == 0)
kfree(tps);
- the_tps = NULL;
+ the_tps = 0;
return 0;
}
{
struct tps65010 *tps;
int status;
- unsigned long irqflags;
if (the_tps) {
dev_dbg(&bus->dev, "only one %s for now\n", DRIVER_NAME);
INIT_WORK(&tps->work, tps65010_work, tps);
tps->irq = -1;
tps->client.addr = address;
+ i2c_set_clientdata(&tps->client, tps);
tps->client.adapter = bus;
tps->client.driver = &tps65010_driver;
strlcpy(tps->client.name, DRIVER_NAME, I2C_NAME_SIZE);
if (status < 0) {
dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n",
DRIVER_NAME, address, status);
- goto fail1;
+fail1:
+ kfree(tps);
+ return 0;
}
+ tps->irq_type = 0;
+
#ifdef CONFIG_ARM
- irqflags = SA_SAMPLE_RANDOM | SA_TRIGGER_LOW;
if (machine_is_omap_h2()) {
tps->model = TPS65010;
omap_cfg_reg(W4_GPIO58);
tps->irq = OMAP_GPIO_IRQ(58);
omap_request_gpio(58);
omap_set_gpio_direction(58, 1);
- irqflags |= SA_TRIGGER_FALLING;
+ tps->irq_type = SA_TRIGGER_FALLING;
}
if (machine_is_omap_osk()) {
tps->model = TPS65010;
tps->irq = OMAP_GPIO_IRQ(OMAP_MPUIO(1));
omap_request_gpio(OMAP_MPUIO(1));
omap_set_gpio_direction(OMAP_MPUIO(1), 1);
- irqflags |= SA_TRIGGER_FALLING;
+ tps->irq_type = SA_TRIGGER_FALLING;
}
if (machine_is_omap_h3()) {
tps->model = TPS65013;
// FIXME set up this board's IRQ ...
}
-#else
- irqflags = SA_SAMPLE_RANDOM;
#endif
if (tps->irq > 0) {
status = request_irq(tps->irq, tps65010_irq,
- irqflags, DRIVER_NAME, tps);
+ tps->irq_type, DRIVER_NAME, tps);
if (status < 0) {
dev_dbg(&tps->client.dev, "can't get IRQ %d, err %d\n",
tps->irq, status);
tps->file = debugfs_create_file(DRIVER_NAME, S_IRUGO, NULL,
tps, DEBUG_FOPS);
return 0;
-fail1:
- kfree(tps);
- return 0;
}
static int __init tps65010_scan_bus(struct i2c_adapter *bus)
static struct i2c_driver tps65010_driver = {
.driver = {
- .name = "tps65010",
+ .name = "tps65010",
},
+ .id = 888, /* FIXME assign "official" value */
.attach_adapter = tps65010_scan_bus,
.detach_client = __exit_p(tps65010_detach_client),
};
return -ENODEV;
if ((gpio < GPIO1) || (gpio > GPIO4))
return -EINVAL;
-
+
down(&the_tps->lock);
defgpio = i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO);
/* Configure GPIO for output */
defgpio |= 1 << (gpio + 3);
-
+
/* Writing 1 forces a logic 0 on that GPIO and vice versa */
switch (value) {
case LOW:
defgpio &= ~(1 << (gpio - 1)); /* set GPIO high by writing 0 */
break;
}
-
+
status = i2c_smbus_write_byte_data(&the_tps->client,
TPS_DEFGPIO, defgpio);
pr_debug("%s: gpio%dout = %s, defgpio 0x%02x\n", DRIVER_NAME,
gpio, value ? "high" : "low",
i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO));
-
+
up(&the_tps->lock);
return status;
}
if (!the_tps)
return -ENODEV;
- if (led == LED1)
+ if(led == LED1)
offs = 0;
else {
offs = 2;
down(&the_tps->lock);
- pr_debug("%s: led%i_on 0x%02x\n", DRIVER_NAME, led,
- i2c_smbus_read_byte_data(&the_tps->client,
- TPS_LED1_ON + offs));
-
- pr_debug("%s: led%i_per 0x%02x\n", DRIVER_NAME, led,
- i2c_smbus_read_byte_data(&the_tps->client,
- TPS_LED1_PER + offs));
+ dev_dbg (&the_tps->client.dev, "led%i_on 0x%02x\n", led,
+ i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_ON + offs));
+ dev_dbg (&the_tps->client.dev, "led%i_per 0x%02x\n", led,
+ i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_PER + offs));
+
switch (mode) {
case OFF:
led_on = 1 << 7;
led_per = 0x08 | (1 << 7);
break;
default:
- printk(KERN_ERR "%s: Wrong mode parameter for set_led()\n",
+ printk(KERN_ERR "%s: Wrong mode parameter for tps65010_set_led()\n",
DRIVER_NAME);
up(&the_tps->lock);
return -EINVAL;
TPS_LED1_ON + offs, led_on);
if (status != 0) {
- printk(KERN_ERR "%s: Failed to write led%i_on register\n",
+ printk(KERN_ERR "%s: Failed to write led%i_on register\n",
DRIVER_NAME, led);
up(&the_tps->lock);
return status;
- }
+ }
- pr_debug("%s: led%i_on 0x%02x\n", DRIVER_NAME, led,
+ dev_dbg (&the_tps->client.dev, "led%i_on 0x%02x\n", led,
i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_ON + offs));
status = i2c_smbus_write_byte_data(&the_tps->client,
TPS_LED1_PER + offs, led_per);
if (status != 0) {
- printk(KERN_ERR "%s: Failed to write led%i_per register\n",
+ printk(KERN_ERR "%s: Failed to write led%i_per register\n",
DRIVER_NAME, led);
up(&the_tps->lock);
return status;
}
- pr_debug("%s: led%i_per 0x%02x\n", DRIVER_NAME, led,
- i2c_smbus_read_byte_data(&the_tps->client,
- TPS_LED1_PER + offs));
+ dev_dbg (&the_tps->client.dev, "led%i_per 0x%02x\n", led,
+ i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_PER + offs));
up(&the_tps->lock);
i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1));
vdcdc1 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1);
-
+
switch (mode) {
case OFF:
vdcdc1 &= ~TPS_ENABLE_LP; /* disable ENABLE_LP bit */
TPS_VDCDC1, vdcdc1);
if (status != 0)
- printk(KERN_ERR "%s: Failed to write vdcdc1 register\n",
- DRIVER_NAME);
+ printk(KERN_ERR "%s: Failed to write vdcdc1 register\n",
+ DRIVER_NAME);
else
pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME,
i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1));
down(&the_tps->lock);
- pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME,
- i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1));
+ pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME,
+ i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1));
status = i2c_smbus_write_byte_data(&the_tps->client,
TPS_VREGS1, value);
if (status != 0)
- printk(KERN_ERR "%s: Failed to write vregs1 register\n",
- DRIVER_NAME);
+ printk(KERN_ERR "%s: Failed to write vregs1 register\n",
+ DRIVER_NAME);
else
pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME,
i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1));
msleep(10);
}
-#ifdef CONFIG_ARM
+#if defined(CONFIG_ARM)
if (machine_is_omap_osk()) {
// FIXME: More should be placed in the initialization code
} else if (machine_is_omap_h3()) {
/* gpio4 for SD, gpio3 for VDD_DSP */
#ifdef CONFIG_PM
- /* Enable LOW_PWR */
- tps65013_set_low_pwr(ON);
+ /* FIXME: Enable LOW_PWR hangs H3 */
+ //tps65013_set_low_pwr(ON);
#endif
}
#endif
This driver implements support for HIL-keyboards attached
to your machine, so normally you should say Y here.
+
+config KEYBOARD_OMAP
+ tristate "TI OMAP keypad support"
+ depends on (ARCH_OMAP1 || ARCH_OMAP2)
+ help
+ Say Y here if you want to use the OMAP keypad.
+
+ 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.
+
endif
obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
-
+obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
+obj-$(CONFIG_OMAP_PS2) += innovator_ps2.o
--- /dev/null
+/*
+ * 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 u8 block[JUNO_BLOCK_SIZE];
+
+static void do_hid_tasklet(unsigned long);
+DECLARE_TASKLET(hid_tasklet, do_hid_tasklet, 0);
+static struct innovator_hid_dev *hid;
+static spinlock_t innovator_fpga_hid_lock = SPIN_LOCK_UNLOCKED;
+static atomic_t innovator_fpga_hid_busy = ATOMIC_INIT(0);
+
+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
+innovator_fpga_hid_clear_bits(u8 x)
+{
+ innovator_fpga_hid_frob(x, 0);
+}
+
+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;
+}
+
+static int
+verify_init(u8 * p)
+{
+ return (((simple_t *)p)->cmd_code == 0x01) ? 0 : -1;
+}
+
+
+/*
+ * 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;
+
+ 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;
+
+ 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,
+ SA_INTERRUPT, 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;
+
+ /*
+ * 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;
+
+ /*
+ * 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.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.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+ init_input_dev(&hid->keyboard);
+ 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");
--- /dev/null
+/*
+ * linux/drivers/char/omap-keypad.c
+ *
+ * OMAP Keypad Driver
+ *
+ * Copyright (C) 2003 Nokia Corporation
+ * Written by Timo Teräs <ext-timo.teras@nokia.com>
+ *
+ * Added support for H2 & H3 Keypad
+ * Copyright (C) 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 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/init.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/keypad.h>
+#include <asm/arch/menelaus.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/mach-types.h>
+#include <asm/arch/mux.h>
+
+#undef NEW_BOARD_LEARNING_MODE
+
+static void omap_kp_tasklet(unsigned long);
+static void omap_kp_timer(unsigned long);
+
+static unsigned char keypad_state[8];
+static DECLARE_MUTEX(kp_enable_mutex);
+static int kp_enable = 1;
+static int kp_cur_group = -1;
+
+struct omap_kp {
+ struct input_dev *input;
+ struct timer_list timer;
+ unsigned int irq;
+ unsigned int rows;
+ unsigned int cols;
+};
+
+DECLARE_TASKLET_DISABLED(kp_tasklet, omap_kp_tasklet, 0);
+
+static int *keymap;
+static unsigned int *row_gpios;
+static unsigned int *col_gpios;
+
+#ifdef CONFIG_ARCH_OMAP2
+static void set_col_gpio_val(struct omap_kp *omap_kp, u8 value)
+{
+ int col;
+ for (col = 0; col < omap_kp->cols; col++) {
+ if (value & (1 << col))
+ omap_set_gpio_dataout(col_gpios[col], 1);
+ else
+ omap_set_gpio_dataout(col_gpios[col], 0);
+ }
+}
+
+static u8 get_row_gpio_val(struct omap_kp *omap_kp)
+{
+ int row;
+ u8 value = 0;
+
+ for (row = 0; row < omap_kp->rows; row++) {
+ if (omap_get_gpio_datain(row_gpios[row]))
+ value |= (1 << row);
+ }
+ return value;
+}
+#else
+#define set_col_gpio_val(x, y) do {} while (0)
+#define get_row_gpio_val(x) 0
+#endif
+
+static irqreturn_t omap_kp_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ struct omap_kp *omap_kp = dev_id;
+
+ /* disable keyboard interrupt and schedule for handling */
+ if (cpu_is_omap24xx()) {
+ int i;
+ for (i = 0; i < omap_kp->rows; i++)
+ disable_irq(OMAP_GPIO_IRQ(row_gpios[i]));
+ } else {
+ /* disable keyboard interrupt and schedule for handling */
+ omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+ }
+
+ tasklet_schedule(&kp_tasklet);
+
+ return IRQ_HANDLED;
+}
+
+static void omap_kp_timer(unsigned long data)
+{
+ tasklet_schedule(&kp_tasklet);
+}
+
+static void omap_kp_scan_keypad(struct omap_kp *omap_kp, unsigned char *state)
+{
+ int col = 0;
+
+ /* read the keypad status */
+ if (cpu_is_omap24xx()) {
+ int i;
+ for (i = 0; i < omap_kp->rows; i++)
+ disable_irq(OMAP_GPIO_IRQ(row_gpios[i]));
+ } else {
+ /* disable keyboard interrupt and schedule for handling */
+ omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+ }
+ if (!cpu_is_omap24xx()) {
+ /* read the keypad status */
+ omap_writew(0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_KBC);
+ for (col = 0; col < omap_kp->cols; col++) {
+ omap_writew(~(1 << col) & 0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_KBC);
+
+ if (machine_is_omap_osk() || machine_is_omap_h2() || machine_is_omap_h3()) {
+ udelay(9);
+ } else {
+ udelay(4);
+ }
+ state[col] = ~omap_readw(OMAP_MPUIO_BASE + OMAP_MPUIO_KBR_LATCH) & 0xff;
+ }
+ omap_writew(0x00, OMAP_MPUIO_BASE + OMAP_MPUIO_KBC);
+ udelay(2);
+ } else {
+ /* read the keypad status */
+ for (col = 0; col < omap_kp->cols; col++) {
+ set_col_gpio_val(omap_kp, ~(1 << col));
+ state[col] = ~(get_row_gpio_val(omap_kp)) & 0x3f;
+ }
+ set_col_gpio_val(omap_kp, 0);
+ }
+}
+
+static inline int omap_kp_find_key(int col, int row)
+{
+ int i, key;
+
+ key = KEY(col, row, 0);
+ for (i = 0; keymap[i] != 0; i++)
+ if ((keymap[i] & 0xff000000) == key)
+ return keymap[i] & 0x00ffffff;
+ return -1;
+}
+
+static void omap_kp_tasklet(unsigned long data)
+{
+ struct omap_kp *omap_kp_data = (struct omap_kp *) data;
+ unsigned char new_state[8], changed, key_down = 0;
+ int col, row;
+ int spurious = 0;
+
+ /* check for any changes */
+ omap_kp_scan_keypad(omap_kp_data, new_state);
+
+ /* check for changes and print those */
+ for (col = 0; col < omap_kp_data->cols; col++) {
+ changed = new_state[col] ^ keypad_state[col];
+ key_down |= new_state[col];
+ if (changed == 0)
+ continue;
+
+ for (row = 0; row < omap_kp_data->rows; row++) {
+ int key;
+ if (!(changed & (1 << row)))
+ continue;
+#ifdef NEW_BOARD_LEARNING_MODE
+ printk(KERN_INFO "omap-keypad: key %d-%d %s\n", col, row, (new_state[col] & (1 << row)) ? "pressed" : "released");
+#else
+ key = omap_kp_find_key(col, row);
+ if (key < 0) {
+ printk(KERN_WARNING "omap-keypad: Spurious key event %d-%d\n",
+ col, row);
+ /* We scan again after a couple of seconds */
+ spurious = 1;
+ continue;
+ }
+
+ if (!(kp_cur_group == (key & GROUP_MASK) ||
+ kp_cur_group == -1))
+ continue;
+
+ kp_cur_group = key & GROUP_MASK;
+ input_report_key(omap_kp_data->input, key & ~GROUP_MASK,
+ !!(new_state[col] & (1 << row)));
+#endif
+ }
+ }
+ memcpy(keypad_state, new_state, sizeof(keypad_state));
+
+ if (key_down) {
+ int delay = HZ / 20;
+ /* some key is pressed - keep irq disabled and use timer
+ * to poll the keypad */
+ if (spurious)
+ delay = 2 * HZ;
+ mod_timer(&omap_kp_data->timer, jiffies + delay);
+ } else {
+ /* enable interrupts */
+ if (cpu_is_omap24xx()) {
+ int i;
+ for (i = 0; i < omap_kp_data->rows; i++)
+ enable_irq(OMAP_GPIO_IRQ(row_gpios[i]));
+ } else {
+ omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+ kp_cur_group = -1;
+ }
+ }
+}
+
+static ssize_t omap_kp_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%u\n", kp_enable);
+}
+
+static ssize_t omap_kp_enable_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int state;
+
+ if (sscanf(buf, "%u", &state) != 1)
+ return -EINVAL;
+
+ if ((state != 1) && (state != 0))
+ return -EINVAL;
+
+ down(&kp_enable_mutex);
+ if (state != kp_enable) {
+ if (state)
+ enable_irq(INT_KEYBOARD);
+ else
+ disable_irq(INT_KEYBOARD);
+ kp_enable = state;
+ }
+ up(&kp_enable_mutex);
+
+ return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, omap_kp_enable_show, omap_kp_enable_store);
+
+#ifdef CONFIG_PM
+static int omap_kp_suspend(struct platform_device *dev, pm_message_t state)
+{
+ /* Nothing yet */
+
+ return 0;
+}
+
+static int omap_kp_resume(struct platform_device *dev)
+{
+ /* Nothing yet */
+
+ return 0;
+}
+#else
+#define omap_kp_suspend NULL
+#define omap_kp_resume NULL
+#endif
+
+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;
+
+ if (!pdata->rows || !pdata->cols || !pdata->keymap) {
+ printk(KERN_ERR "No rows, cols or keymap from pdata\n");
+ return -EINVAL;
+ }
+
+ omap_kp = kzalloc(sizeof(struct omap_kp), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!omap_kp || !input_dev) {
+ kfree(omap_kp);
+ input_free_device(input_dev);
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, omap_kp);
+
+ omap_kp->input = input_dev;
+
+ /* Disable the interrupt for the MPUIO keyboard */
+ if (!cpu_is_omap24xx())
+ omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+
+ keymap = pdata->keymap;
+
+ if (pdata->rep)
+ set_bit(EV_REP, input_dev->evbit);
+
+ if (pdata->row_gpios && pdata->col_gpios) {
+ row_gpios = pdata->row_gpios;
+ col_gpios = pdata->col_gpios;
+ }
+
+ omap_kp->rows = pdata->rows;
+ omap_kp->cols = pdata->cols;
+
+ if (cpu_is_omap24xx()) {
+ /* Cols: outputs */
+ for (i = 0; i < omap_kp->cols; i++) {
+ if (omap_request_gpio(col_gpios[i]) < 0) {
+ printk(KERN_ERR "Failed to request"
+ "GPIO%d for keypad\n",
+ col_gpios[i]);
+ return -EINVAL;
+ }
+ omap_set_gpio_direction(col_gpios[i], 0);
+ }
+ /* Rows: inputs */
+ for (i = 0; i < omap_kp->rows; i++) {
+ if (omap_request_gpio(row_gpios[i]) < 0) {
+ printk(KERN_ERR "Failed to request"
+ "GPIO%d for keypad\n",
+ row_gpios[i]);
+ return -EINVAL;
+ }
+ omap_set_gpio_direction(row_gpios[i], 1);
+ }
+ }
+
+ init_timer(&omap_kp->timer);
+ omap_kp->timer.function = omap_kp_timer;
+ omap_kp->timer.data = (unsigned long) omap_kp;
+
+ /* get the irq and init timer*/
+ tasklet_enable(&kp_tasklet);
+ kp_tasklet.data = (unsigned long) omap_kp;
+
+ omap_kp->irq = platform_get_irq(pdev, 0);
+ if (omap_kp->irq) {
+ if (request_irq(omap_kp->irq, omap_kp_interrupt, 0,
+ "omap-keypad", omap_kp) < 0)
+ return -EINVAL;
+ }
+
+ device_create_file(&pdev->dev, &dev_attr_enable);
+
+ /* setup input device */
+ set_bit(EV_KEY, input_dev->evbit);
+ for (i = 0; keymap[i] != 0; i++)
+ set_bit(keymap[i] & KEY_MAX, input_dev->keybit);
+ input_dev->name = "omap-keypad";
+ input_dev->cdev.dev = &pdev->dev;
+ input_dev->private = omap_kp;
+ input_register_device(omap_kp->input);
+
+ if (machine_is_omap_h2() || machine_is_omap_h3() ||
+ machine_is_omap_perseus2()) {
+ omap_writew(0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_DEBOUNCING);
+ }
+ /* scan current status and enable interrupt */
+ omap_kp_scan_keypad(omap_kp, keypad_state);
+ if (!cpu_is_omap24xx()) {
+ omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+ } else {
+ for (i = 0; i < omap_kp->rows; i++) {
+ if (request_irq(OMAP_GPIO_IRQ(row_gpios[i]), omap_kp_interrupt,
+ SA_TRIGGER_FALLING, "omap-keypad", omap_kp) < 0)
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int omap_kp_remove(struct platform_device *pdev)
+{
+ struct omap_kp *omap_kp = platform_get_drvdata(pdev);
+
+ /* disable keypad interrupt handling */
+ tasklet_disable(&kp_tasklet);
+ if (cpu_is_omap24xx()) {
+ int i;
+ for (i = 0; i < omap_kp->cols; i++)
+ omap_free_gpio(col_gpios[i]);
+ for (i = 0; i < omap_kp->rows; i++) {
+ omap_free_gpio(row_gpios[i]);
+ free_irq(OMAP_GPIO_IRQ(row_gpios[i]), 0);
+ }
+ } else {
+ omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+ free_irq(omap_kp->irq, 0);
+ }
+
+ del_timer_sync(&omap_kp->timer);
+
+ /* unregister everything */
+ input_unregister_device(omap_kp->input);
+
+ kfree(omap_kp);
+
+ return 0;
+}
+
+static struct platform_driver omap_kp_driver = {
+ .probe = omap_kp_probe,
+ .remove = omap_kp_remove,
+ .suspend = omap_kp_suspend,
+ .resume = omap_kp_resume,
+ .driver = {
+ .name = "omap-keypad",
+ },
+};
+
+static int __devinit omap_kp_init(void)
+{
+ printk(KERN_INFO "OMAP Keypad Driver\n");
+ return platform_driver_register(&omap_kp_driver);
+}
+
+static void __exit omap_kp_exit(void)
+{
+ platform_driver_unregister(&omap_kp_driver);
+}
+
+module_init(omap_kp_init);
+module_exit(omap_kp_exit);
+
+MODULE_AUTHOR("Timo Teräs");
+MODULE_DESCRIPTION("OMAP Keypad Driver");
+MODULE_LICENSE("GPL");
module will be called hp680_ts_input.
endif
+config TOUCHSCREEN_OMAP
+ tristate "OMAP touchscreen input driver"
+ depends on INPUT && INPUT_TOUCHSCREEN && ARCH_OMAP
+ select OMAP_TSC2101
+ help
+ Say Y here if you have an OMAP based board with touchscreen
+ attached to it, e.g. OMAP Innovator, OSK, H2 or H3
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called omap_ts.
+
+
+
#
-# Makefile for the mouse drivers.
+# Makefile for the touchscreen input drivers.
#
# Each configuration option enables a list of files.
obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o
obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o
+obj-$(CONFIG_TOUCHSCREEN_OMAP) += omap/
u16 vref_delay_usecs;
u16 x_plate_ohms;
- u8 read_x, read_y, read_z1, read_z2;
+ u8 read_x, read_y, read_z1, read_z2, pwrdown;
+ u16 dummy; /* for the pwrdown read */
struct ts_event tc;
- struct spi_transfer xfer[8];
- struct spi_message msg;
+ struct spi_transfer xfer[10];
+ struct spi_message msg[5];
+ int msg_idx;
+ int read_cnt;
+ int last_read;
+
+ u16 debounce_max;
+ u16 debounce_tol;
spinlock_t lock;
struct timer_list timer; /* P: lock */
#define READ_Y (READ_12BIT_DFR(y) | ADS_PD10_ADC_ON)
#define READ_Z1 (READ_12BIT_DFR(z1) | ADS_PD10_ADC_ON)
#define READ_Z2 (READ_12BIT_DFR(z2) | ADS_PD10_ADC_ON)
-#define READ_X (READ_12BIT_DFR(x) | ADS_PD10_PDOWN) /* LAST */
+
+#define READ_X (READ_12BIT_DFR(x) | ADS_PD10_ADC_ON)
+#define PWRDOWN (READ_12BIT_DFR(y) | ADS_PD10_PDOWN) /* LAST */
/* single-ended samples need to first power up reference voltage;
* we leave both ADC and VREF powered
if (!req)
return -ENOMEM;
- INIT_LIST_HEAD(&req->msg.transfers);
+ spi_message_init(&req->msg);
/* activate reference, so it has time to settle; */
req->ref_on = REF_ON;
SHOW(vaux)
SHOW(vbatt)
+static int is_pen_down(struct device *dev)
+{
+ struct ads7846 *ts = dev_get_drvdata(dev);
+
+ return ts->pendown;
+}
+
+static ssize_t ads7846_pen_down_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%u\n", is_pen_down(dev));
+}
+
+static DEVICE_ATTR(pen_down, S_IRUGO, ads7846_pen_down_show, NULL);
+
/*--------------------------------------------------------------------------*/
/*
/* adjust: 12 bit samples (left aligned), built from
* two 8 bit values writen msb-first.
*/
- x = be16_to_cpu(ts->tc.x) >> 4;
- y = be16_to_cpu(ts->tc.y) >> 4;
- z1 = be16_to_cpu(ts->tc.z1) >> 4;
- z2 = be16_to_cpu(ts->tc.z2) >> 4;
+ x = ts->tc.x >> 3;
+ y = ts->tc.y >> 3;
+ z1 = ts->tc.z1 >> 3;
+ z2 = ts->tc.z2 >> 3;
/* range filtering */
if (x == MAX_12BIT)
spin_unlock_irqrestore(&ts->lock, flags);
}
+static void ads7846_debounce(void *ads)
+{
+ struct ads7846 *ts = ads;
+ struct spi_message *m;
+ struct spi_transfer *t;
+ u16 val;
+ int status;
+
+ m = &ts->msg[ts->msg_idx];
+ t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
+ val = (*(u16 *)t->rx_buf) >> 3;
+
+ if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol &&
+ ts->read_cnt < ts->debounce_max)) {
+ /* Repeat it, if this was the first read or the read wasn't
+ * consistent enough */
+ ts->read_cnt++;
+ ts->last_read = val;
+ } else {
+ /* Go for the next read */
+ ts->msg_idx++;
+ ts->read_cnt = 0;
+ m++;
+ }
+ status = spi_async(ts->spi, m);
+ if (status)
+ dev_err(&ts->spi->dev, "spi_async --> %d\n",
+ status);
+}
+
static void ads7846_timer(unsigned long handle)
{
struct ads7846 *ts = (void *)handle;
int status = 0;
- unsigned long flags;
+
+ ts->msg_idx = 0;
+ status = spi_async(ts->spi, &ts->msg[0]);
+ if (status)
+ dev_err(&ts->spi->dev, "spi_async --> %d\n", status);
+}
+
+static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs)
+{
+ struct ads7846 *ts = handle;
+ unsigned long flags;
+ int r = IRQ_HANDLED;
spin_lock_irqsave(&ts->lock, flags);
- if (!ts->pending) {
- ts->pending = 1;
+ if (ts->irq_disabled)
+ r = IRQ_HANDLED;
+ else {
if (!ts->irq_disabled) {
ts->irq_disabled = 1;
+ /* The following has at the moment no effect whatsoever
+ * on OMAP, that's why we maintain the disabled
+ * state ourselves */
disable_irq(ts->spi->irq);
}
- status = spi_async(ts->spi, &ts->msg);
- if (status)
- dev_err(&ts->spi->dev, "spi_async --> %d\n",
- status);
+ if (!ts->pending) {
+ ts->pending = 1;
+ mod_timer(&ts->timer, jiffies);
+ }
}
spin_unlock_irqrestore(&ts->lock, flags);
-}
-
-static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs)
-{
- ads7846_timer((unsigned long) handle);
- return IRQ_HANDLED;
+ return r;
}
/*--------------------------------------------------------------------------*/
while (ts->pendown || ts->pending) {
spin_unlock_irqrestore(&ts->lock, flags);
- udelay(10);
+ msleep(1);
spin_lock_irqsave(&ts->lock, flags);
}
}
struct ads7846 *ts;
struct input_dev *input_dev;
struct ads7846_platform_data *pdata = spi->dev.platform_data;
+ struct spi_message *m;
struct spi_transfer *x;
int err;
ts->model = pdata->model ? : 7846;
ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
+ ts->debounce_max = pdata->debounce_max ? : 1;
+ ts->debounce_tol = pdata->debounce_tol ? : 10;
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id);
/* set up the transfers to read touchscreen state; this assumes we
* use formula #2 for pressure, not #3.
*/
- INIT_LIST_HEAD(&ts->msg.transfers);
+ m = &ts->msg[0];
x = ts->xfer;
+ spi_message_init(m);
+
/* y- still on; turn on only y+ (and ADC) */
ts->read_y = READ_Y;
x->tx_buf = &ts->read_y;
x->len = 1;
- spi_message_add_tail(x, &ts->msg);
+ spi_message_add_tail(x, m);
x++;
x->rx_buf = &ts->tc.y;
x->len = 2;
- spi_message_add_tail(x, &ts->msg);
+ spi_message_add_tail(x, m);
+
+ m->complete = ads7846_debounce;
+ m->context = ts;
+
+ m++;
+ spi_message_init(m);
+
+ /* turn y- off, x+ on, then leave in lowpower */
+ x++;
+ ts->read_x = READ_X;
+ x->tx_buf = &ts->read_x;
+ x->len = 1;
+ spi_message_add_tail(x, m);
+
+ x++;
+ x->rx_buf = &ts->tc.x;
+ x->len = 2;
+ spi_message_add_tail(x, m);
+
+ m->complete = ads7846_debounce;
+ m->context = ts;
/* turn y+ off, x- on; we'll use formula #2 */
if (ts->model == 7846) {
+ m++;
+ spi_message_init(m);
+
x++;
ts->read_z1 = READ_Z1;
x->tx_buf = &ts->read_z1;
x->len = 1;
- spi_message_add_tail(x, &ts->msg);
+ spi_message_add_tail(x, m);
x++;
x->rx_buf = &ts->tc.z1;
x->len = 2;
- spi_message_add_tail(x, &ts->msg);
+ spi_message_add_tail(x, m);
+
+ m->complete = ads7846_debounce;
+ m->context = ts;
+
+ m++;
+ spi_message_init(m);
x++;
ts->read_z2 = READ_Z2;
x->tx_buf = &ts->read_z2;
x->len = 1;
- spi_message_add_tail(x, &ts->msg);
+ spi_message_add_tail(x, m);
x++;
x->rx_buf = &ts->tc.z2;
x->len = 2;
- spi_message_add_tail(x, &ts->msg);
+ spi_message_add_tail(x, m);
+
+ m->complete = ads7846_debounce;
+ m->context = ts;
}
- /* turn y- off, x+ on, then leave in lowpower */
+ /* power down */
+ m++;
+ spi_message_init(m);
+
x++;
- ts->read_x = READ_X;
- x->tx_buf = &ts->read_x;
+ ts->pwrdown = PWRDOWN;
+ x->tx_buf = &ts->pwrdown;
x->len = 1;
- spi_message_add_tail(x, &ts->msg);
+ spi_message_add_tail(x, m);
x++;
- x->rx_buf = &ts->tc.x;
+ x->rx_buf = &ts->dummy;
x->len = 2;
CS_CHANGE(*x);
- spi_message_add_tail(x, &ts->msg);
+ spi_message_add_tail(x, m);
- ts->msg.complete = ads7846_rx;
- ts->msg.context = ts;
+ m->complete = ads7846_rx;
+ m->context = ts;
if (request_irq(spi->irq, ads7846_irq,
SA_SAMPLE_RANDOM | SA_TRIGGER_FALLING,
device_create_file(&spi->dev, &dev_attr_vbatt);
device_create_file(&spi->dev, &dev_attr_vaux);
+ device_create_file(&spi->dev, &dev_attr_pen_down);
+
err = input_register_device(input_dev);
if (err)
goto err_free_irq;
if (ts->irq_disabled)
enable_irq(ts->spi->irq);
+ device_remove_file(&spi->dev, &dev_attr_pen_down);
+
if (ts->model == 7846) {
device_remove_file(&spi->dev, &dev_attr_temp0);
device_remove_file(&spi->dev, &dev_attr_temp1);
--- /dev/null
+#
+# 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
+objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_INNOVATOR) += ts_inn1510.o
+objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_OSK) += ts_osk.o
+
+omapts-objs := omap_ts.o $(objs-yy)
--- /dev/null
+/*
+ * ads7846.h - header file for ADS7846 touchscreen controller
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * stevel@mvista.com or source@mvista.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
+ */
+
+#ifndef __ADS7846_H
+#define __ADS7846_H
+
+// ADS7846 Control Byte bit defines
+#define ADS7846_S (1<<7)
+#define ADS7846_ADDR_BIT 4
+#define ADS7846_ADDR_MASK (0x7<<ADS7846_ADDR_BIT)
+#define ADS7846_MEASURE_X (0x5<<ADS7846_ADDR_BIT)
+#define ADS7846_MEASURE_Y (0x1<<ADS7846_ADDR_BIT)
+#define ADS7846_MEASURE_Z1 (0x3<<ADS7846_ADDR_BIT)
+#define ADS7846_MEASURE_Z2 (0x4<<ADS7846_ADDR_BIT)
+#define ADS7846_8BITS (1<<3)
+#define ADS7846_12BITS 0
+#define ADS7846_SER (1<<2)
+#define ADS7846_DFR 0
+#define ADS7846_PWR_BIT 0
+#define ADS7846_PD 0
+#define ADS7846_ADC_ON (0x1<<ADS7846_PWR_BIT)
+#define ADS7846_REF_ON (0x2<<ADS7846_PWR_BIT)
+#define ADS7846_REF_ADC_ON (0x3<<ADS7846_PWR_BIT)
+
+#define MEASURE_12BIT_X \
+ (ADS7846_S | ADS7846_MEASURE_X | ADS7846_12BITS | ADS7846_DFR | ADS7846_PD)
+#define MEASURE_12BIT_Y \
+ (ADS7846_S | ADS7846_MEASURE_Y | ADS7846_12BITS | ADS7846_DFR | ADS7846_PD)
+#define MEASURE_12BIT_Z1 \
+ (ADS7846_S | ADS7846_MEASURE_Z1 | ADS7846_12BITS | ADS7846_DFR | ADS7846_PD)
+#define MEASURE_12BIT_Z2 \
+ (ADS7846_S | ADS7846_MEASURE_Z2 | ADS7846_12BITS | ADS7846_DFR | ADS7846_PD)
+
+#endif /* __ADS7846_H */
--- /dev/null
+/*
+ * 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
+#ifdef CONFIG_MACH_OMAP_OSK
+ &osk_ts,
+#endif
+#if defined(CONFIG_MACH_OMAP_INNOVATOR) && defined(CONFIG_ARCH_OMAP15XX)
+ &innovator1510_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, struct pt_regs *regs)
+{
+ 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,
+ SA_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;
+
+ 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");
--- /dev/null
+/*
+ * 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;
+extern struct ts_device osk_ts;
+extern struct ts_device innovator1510_ts;
+
+#endif /* __OMAP_TS_H */
--- /dev/null
+/*
+ * 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 = SA_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
--- /dev/null
+/*
+ * ts_inn1510.c - touchscreen support for OMAP1510 Innovator board
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * stevel@mvista.com or source@mvista.com
+ *
+ * The touchscreen hardware on the Innovator consists of an FPGA
+ * register which is bit-banged to generate SPI-like transactions
+ * to an ADS7846 touch screen controller.
+ *
+ * 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/input.h>
+#include <linux/device.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/arch/fpga.h>
+
+#include "omap_ts.h"
+#include "ads7846.h"
+
+// The Touch Screen Register on Innovator FPGA
+#define FPGA_TS_BCLK (1<<0)
+#define FPGA_TS_BDIN (1<<1)
+#define FPGA_TS_BCS (1<<2)
+#define FPGA_TS_BBUSY (1<<3)
+#define FPGA_TS_BOUT (1<<4)
+#define FPGA_TS_BPENUP (1<<5)
+
+#define X_PLATE_OHMS 419
+#define Y_PLATE_OHMS 486
+
+static int inn1510_ts_penup(void);
+static int inn1510_ts_probe(struct omap_ts_t *ts);
+static void inn1510_ts_read(u16 * data);
+static void inn1510_ts_enable(void);
+static void inn1510_ts_disable(void);
+#ifdef MODULE
+static void inn1510_ts_remove(void);
+#endif
+
+struct ts_device innovator1510_ts = {
+ .probe = inn1510_ts_probe,
+ .read = inn1510_ts_read,
+ .enable = inn1510_ts_enable,
+ .disable = inn1510_ts_disable,
+ .remove = __exit_p(inn1510_ts_remove),
+ .penup = inn1510_ts_penup,
+};
+
+static inline u8 fpga_ts_read(void)
+{
+ return fpga_read(OMAP1510_FPGA_TOUCHSCREEN);
+}
+
+static inline void fpga_ts_write(u8 val)
+{
+ fpga_write(val, OMAP1510_FPGA_TOUCHSCREEN);
+}
+
+static inline void fpga_ts_set_bits(u8 mask)
+{
+ fpga_ts_write(fpga_ts_read() | mask);
+}
+
+static inline void fpga_ts_clear_bits(u8 mask)
+{
+ fpga_ts_write(fpga_ts_read() & ~mask);
+}
+
+static inline void CS_H(void)
+{
+ // EPLD inverts active low signals.
+ fpga_ts_clear_bits(FPGA_TS_BCS);
+}
+
+static inline void CS_L(void)
+{
+ fpga_ts_set_bits(FPGA_TS_BCS);
+}
+
+static inline void SCLK_L(void)
+{
+ fpga_ts_clear_bits(FPGA_TS_BCLK);
+}
+
+static inline void SCLK_H(void)
+{
+ fpga_ts_set_bits(FPGA_TS_BCLK);
+}
+
+static inline void SDI_L(void)
+{
+ fpga_ts_clear_bits(FPGA_TS_BDIN);
+}
+
+static inline void SDI_H(void)
+{
+ fpga_ts_set_bits(FPGA_TS_BDIN);
+}
+
+static inline int BUSY(void)
+{
+ return (((fpga_ts_read() & FPGA_TS_BBUSY) == 0) ? 1 : 0) ;
+}
+
+static inline u8 DOUT(void)
+{
+ return ((fpga_ts_read() & FPGA_TS_BOUT) ? 1 : 0) ;
+}
+
+static u16 ads7846_do(u8 cmd)
+{
+ int i;
+ u16 val=0;
+
+ SCLK_L() ;
+ SDI_L();
+ CS_L() ; // enable the chip select
+
+ // send the command to the ADS7846
+ for (i=0; i<8; i++ ) {
+ if (cmd & 0x80)
+ SDI_H();
+ else
+ SDI_L(); // prepare the data on line sdi OR din
+
+ SCLK_H() ; // clk in the data
+ cmd <<= 1 ;
+ SCLK_L() ;
+ }
+
+ SDI_L();
+ while (BUSY())
+ ;
+
+ // now read returned data
+ for (i=0 ; i<16 ; i++ ) {
+ SCLK_L() ;
+
+ if (i < 12) {
+ val <<= 1 ;
+ val |= DOUT();
+ }
+ SCLK_H() ;
+ }
+
+ SCLK_L() ;
+ CS_H() ; // disable the chip select
+
+ return val;
+}
+
+static int inn1510_ts_penup(void)
+{
+ return ((fpga_ts_read() & FPGA_TS_BPENUP) ? 0 : 1) ;
+}
+
+static int __init inn1510_ts_probe(struct omap_ts_t *ts)
+{
+ if (!cpu_is_omap15xx() || !machine_is_omap_innovator())
+ return -ENODEV;
+
+ ts->irq = OMAP1510_INT_FPGA_TS;
+ ts->irq_type = 0;
+
+ return 0;
+}
+
+static void inn1510_ts_read(u16 *data)
+{
+ unsigned int Rt = 0;
+
+ data[0] = ads7846_do(MEASURE_12BIT_X);
+ data[1] = ads7846_do(MEASURE_12BIT_Y);
+ data[2] = ads7846_do(MEASURE_12BIT_Z1);
+ data[3] = ads7846_do(MEASURE_12BIT_Z2);
+
+ // Calculate touch pressure resistance
+ if (data[2]) {
+ Rt = (X_PLATE_OHMS * (u32)data[0] *
+ ((u32)data[3] - (u32)data[2])) / (u32)data[2];
+
+ Rt = (Rt + 2048) >> 12; // round up to nearest ohm
+ }
+
+ data[2] = Rt;
+}
+
+static void inn1510_ts_enable(void)
+{
+
+}
+
+static void inn1510_ts_disable(void)
+{
+
+}
+
+#ifdef MODULE
+static void __exit inn1510_ts_remove(void)
+{
+ /* Nothing to do here */
+}
+#endif
--- /dev/null
+/*
+ * ts_osk.c - touchscreen support for OMAP OSK board
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * stevel@mvista.com or source@mvista.com
+ *
+ * The touchscreen hardware on the OSK uses OMAP5912 uWire interface,
+ * GPIO4 (/PENIRQ) and GPIO6 (BUSY) to connect to an ADS7846
+ * touch screen controller. GPIO6 doesn't seem to be necessary here.
+ *
+ * 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/input.h>
+#include <linux/device.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/gpio.h>
+#include <asm/mach-types.h>
+
+#include "../drivers/ssi/omap-uwire.h"
+
+#include "omap_ts.h"
+#include "ads7846.h"
+
+// /PENIRQ on GPIO4 on OSK
+#define PEN_IRQ OMAP_GPIO_IRQ(4)
+
+// ADS7846 is on OSK uWire CS 0
+#define ADS7846_UWIRE_CS 0
+#define UWIRE_LEAVE_CS 1
+
+#define X_PLATE_OHMS 419
+#define Y_PLATE_OHMS 486
+
+static int osk_ts_penup(void);
+static int osk_ts_probe(struct omap_ts_t *ts);
+static void osk_ts_read(u16 * data);
+static void osk_ts_enable(void);
+static void osk_ts_disable(void);
+#ifdef MODULE
+static void osk_ts_remove(void);
+#endif
+
+struct ts_device osk_ts = {
+ .probe = osk_ts_probe,
+ .read = osk_ts_read,
+ .enable = osk_ts_enable,
+ .disable = osk_ts_disable,
+ .remove = __exit_p(osk_ts_remove),
+ .penup = osk_ts_penup,
+};
+
+static u16 ads7846_do(u8 cmd)
+{
+ u16 val = 0;
+
+ // send the command to the ADS7846, leave CS active after this
+ omap_uwire_data_transfer(ADS7846_UWIRE_CS, cmd, 8, 0, NULL, UWIRE_LEAVE_CS);
+
+ // now read returned data
+ omap_uwire_data_transfer(ADS7846_UWIRE_CS, 0, 0, 16, &val, !UWIRE_LEAVE_CS);
+
+ return val;
+}
+
+static int osk_ts_penup(void)
+{
+ return (omap_get_gpio_datain(4));
+}
+
+static int __init osk_ts_probe(struct omap_ts_t *ts)
+{
+#ifdef CONFIG_OMAP_OSK_MISTRAL
+ if (!machine_is_omap_osk())
+ return -ENODEV;
+
+ /* Configure GPIO4 (pin M17 ZDY) as /PENIRQ interrupt input */
+ omap_cfg_reg(P20_1610_GPIO4);
+ omap_request_gpio(4);
+ omap_set_gpio_direction(4, 1);
+ ts->irq_type = SA_TRIGGER_FALLING;
+
+ ts->irq = PEN_IRQ;
+
+ /* Configure uWire interface. ADS7846 is on CS0 */
+ omap_uwire_configure_mode(ADS7846_UWIRE_CS, UWIRE_READ_RISING_EDGE |
+ UWIRE_WRITE_RISING_EDGE |
+ UWIRE_CS_ACTIVE_LOW |
+ UWIRE_FREQ_DIV_2);
+
+ /* FIXME verify there's really a Mistral board:
+ * see if the AD7846 chip responds.
+ */
+
+ /* NOTE: no VREF; must ignore the temp, VBAT, and AUX sensors */
+ return 0;
+#else
+ return -ENODEV;
+#endif
+}
+
+static void osk_ts_read(u16 *data)
+{
+ unsigned int Rt = 0;
+
+ data[0] = ads7846_do(MEASURE_12BIT_X);
+ data[1] = ads7846_do(MEASURE_12BIT_Y);
+ data[2] = ads7846_do(MEASURE_12BIT_Z1);
+ data[3] = ads7846_do(MEASURE_12BIT_Z2);
+
+ // Calculate touch pressure resistance
+ if (data[2]) {
+ Rt = (X_PLATE_OHMS * (u32)data[0] *
+ ((u32)data[3] - (u32)data[2])) / (u32)data[2];
+
+ Rt = (Rt + 2048) >> 12; // round up to nearest ohm
+ }
+
+ /*
+ * Raw OSK touchscreen data values are between ~4000 and
+ * ~60000. This seems to be to large for calibration
+ * systems (e.g. tslib). Make the values smaller.
+ */
+ data[0] = data[0] >> 4;
+ data[1] = data[1] >> 4;
+
+ data[2] = Rt;
+}
+
+static void osk_ts_enable(void)
+{
+
+}
+
+static void osk_ts_disable(void)
+{
+
+}
+
+#ifdef MODULE
+static void __exit osk_ts_remove(void)
+{
+ omap_free_gpio(4);
+}
+#endif
Say Y here to compile drivers for SAA7115, SAA7127 and CX25840
video decoders.
+source drivers/media/video/omap/Kconfig
+
endmenu
obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
+obj-$(CONFIG_VIDEO_OMAP_CAMERA) += omap/
obj-$(CONFIG_VIDEO_DECODER) += saa7115.o cx25840/ saa7127.o
--- /dev/null
+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
--- /dev/null
+# Makefile for OMAP1/2 camera driver
+
+obj-$(CONFIG_VIDEO_OMAP_CAMERA) += omapcamera.o
+obj-$(CONFIG_VIDEO_CAMERA_SENSOR_OV9640) += sensor_ov9640.o
+
+objs-yy := camera_core.o
+
+objs-y$(CONFIG_ARCH_OMAP16XX) += omap16xxcam.o
+objs-y$(CONFIG_MACH_OMAP_H3) += h3_sensor_power.o
+
+omapcamera-objs := $(objs-yy)
+
+EXTRA_CFLAGS = -I$(src)/..
--- /dev/null
+/*
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/pagemap.h>
+#include <linux/mm.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/videodev.h>
+#include <linux/pci.h>
+#include <linux/version.h>
+#include <asm/semaphore.h>
+#include <asm/processor.h>
+#include <linux/dma-mapping.h>
+#include <linux/fb.h>
+
+#include <asm/io.h>
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+
+#include "sensor_if.h"
+#include "camera_hw_if.h"
+#include "camera_core.h"
+
+struct camera_device *camera_dev;
+extern struct camera_sensor camera_sensor_if;
+extern struct camera_hardware camera_hardware_if;
+
+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_pci_unmap(NULL, &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(NULL, 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 device *dev, pm_message_t state)
+{
+ struct camera_device *cam = dev_get_drvdata(dev);
+ 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 device *dev)
+{
+ struct camera_device *cam = dev_get_drvdata(dev);
+ 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 struct device_driver camera_core_driver = {
+ .name = CAM_NAME,
+ .bus = &platform_bus_type,
+ .probe = NULL,
+ .remove = NULL,
+#ifdef CONFIG_PM
+ .suspend = camera_core_suspend,
+ .resume = camera_core_resume,
+#endif
+ .shutdown = NULL,
+};
+
+static struct platform_device camera_core_device = {
+ .name = CAM_NAME,
+ .dev = {
+ .release = NULL,
+ },
+ .id = 0,
+};
+
+void
+camera_core_cleanup(void)
+{
+ struct camera_device *cam = camera_dev;
+ struct video_device *vfd;
+
+ if (!cam)
+ return;
+
+ 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);
+ driver_unregister(&camera_core_driver);
+ platform_device_unregister(&camera_core_device);
+ }
+ 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;
+}
+
+
+int __init
+camera_core_init(void)
+{
+ struct camera_device *cam;
+ struct video_device *vfd;
+
+ cam = kzalloc(sizeof(struct camera_device), GFP_KERNEL);
+ if (!cam) {
+ printk(KERN_ERR CAM_NAME ": could not allocate memory\n");
+ goto init_error;
+ }
+
+ /* 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");
+ goto init_error;
+ }
+
+ 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");
+ goto init_error;
+ }
+ }
+ 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");
+ goto init_error;
+ }
+
+ /* 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");
+ goto init_error;
+ }
+
+ 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);
+
+ dev_set_drvdata(&camera_core_device.dev, (void *)cam);
+ if (platform_device_register(&camera_core_device) < 0) {
+ printk(KERN_ERR CAM_NAME
+ ": could not register platform_device\n");
+ goto init_error;
+ }
+
+ if (driver_register(&camera_core_driver) < 0) {
+ printk(KERN_ERR CAM_NAME
+ ": could not register driver\n");
+ platform_device_unregister(&camera_core_device);
+ goto init_error;
+ }
+ if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) {
+ printk(KERN_ERR CAM_NAME
+ ": could not register Video for Linux device\n");
+ platform_device_unregister(&camera_core_device);
+ driver_unregister(&camera_core_driver);
+ goto init_error;
+ }
+
+ printk(KERN_INFO CAM_NAME
+ ": registered device video%d [v4l2]\n", vfd->minor);
+ return 0;
+
+init_error:
+ camera_core_cleanup();
+ return -ENODEV;
+}
+
+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);
+
+
--- /dev/null
+/*
+ * 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 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;
+
+ /* 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 */
--- /dev/null
+/*
+ * 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 *);
+};
+
+#endif /* OMAP_CAMERA_HW_IF_H */
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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*/
--- /dev/null
+/*
+ * 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/config.h>
+#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;
+
+ /* 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 */
+ if (machine_is_omap_h3())
+ clk_enable(clk_get(0, "tc2_ck"));
+ else {
+ clk_enable(clk_get(0, "armper_ck"));
+ clk_enable(clk_get(0, "armxor_ck"));
+ }
+}
+
+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 pt_regs *regs)
+{
+ 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 (machine_is_omap_h3())
+ 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, SA_INTERRUPT,
+ "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;
+
+ omap16xxcam_disable(data);
+ if (machine_is_omap_h3()) {
+ if (data->camera_regs) {
+ 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;
+ }
+
+ return 0;
+}
+
+/* Initialise the OMAP camera interface */
+static void *
+omap16xxcam_init(void)
+{
+ unsigned long cam_iobase;
+
+ if (!request_region(CAMERA_BASE, CAMERA_IOSIZE, "OAMP16xx Camera")) {
+ printk ("OMAP16XX Parallel Camera Interface is already in use\n");
+ return NULL;
+ }
+
+ if (machine_is_omap_h3()) {
+ 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 (machine_is_omap_h3())
+ hardware_data.ocp_clk = clk_get_rate(clk_get(0, "tc_ck"));
+ else
+ hardware_data.ocp_clk = clk_get_rate(clk_get(0, "mpuper_ck"));
+
+ /* 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 Camera Parallel",
+ .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,
+};
+
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
+
--- /dev/null
+
+/*
+ * 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 LEN_SENSOR_NAME 31
+
+struct camera_sensor {
+ unsigned int version;
+ char name[LEN_SENSOR_NAME + 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 *);
+
+};
+
+#endif
--- /dev/null
+
+/*
+ * 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 "sensor_if.h"
+#include "ov9640.h"
+#include "h3sensorpower.h"
+
+#define CAMERA_OV9640
+#ifdef CAMERA_OV9640
+
+struct ov9640_sensor {
+ /* I2C parameters */
+ struct i2c_client client;
+ struct i2c_driver driver;
+ 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 (sizeof(ov9640_formats)/sizeof(ov9640_formats[0]))
+#define NUM_OVERLAY_FORMATS 2
+
+/* 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[] = {
+ { 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 */
+ { 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 */
+ { 0x8A, 0xE6 }, { 0x13, 0xaF }, { 0x15, 0x02 }, /* GST15, COM8 */
+ { 0x22, 0x8a }, /* GROS */
+ { 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 (sizeof(control)/sizeof(control[0]))
+
+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;
+ const static unsigned long clks_per_frame[] =
+ { 200000, 200000, 200000, 200000, 400000, 800000, 3200000 };
+
+ 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;
+
+ if (machine_is_omap_h3()) {
+ err = h3_sensor_powerup();
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+static int
+ov9640_powerdown(void)
+{
+ int err;
+
+ if (machine_is_omap_h2())
+ return 0;
+
+ if (machine_is_omap_h3()) {
+ err = h3_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;
+}
+
+/* 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 = &sensor->driver;
+ client->adapter = adap;
+
+ 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(&sensor->driver);
+ ov9640_powerdown();
+ }
+ return 0;
+}
+
+/* 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;
+ struct i2c_driver *driver = &sensor->driver;
+ int err;
+
+ memset(sensor, 0, sizeof(*sensor));
+
+ /* power-up the sensor */
+ if (ov9640_powerup())
+ return NULL;
+
+ strlcpy(driver->driver.name, "OV9640 I2C driver", sizeof(driver->driver.name));
+ driver->id = I2C_DRIVERID_MISC;
+ driver->attach_adapter = ov9640_i2c_probe_adapter;
+ driver->detach_client = ov9640_i2c_detach_client;
+
+ err = i2c_add_driver(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 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,
+};
+
+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 /* ifdef CAMERA_OV9640 */
mount the filesystem. Almost everyone wishing MMC support
should say Y or M here.
+config MMC_BLOCK_BROKEN_RFD
+ boolean "Write work-around for incompatible cards"
+ depends on MMC_BLOCK
+ default n
+ help
+ Say y here if your MMC card fails write operations. Some cards
+ lie about being ready to receive data while they actually are not.
+
+config MMC_BULKTRANSFER
+ bool "Multi-block writes (EXPERIMENTAL)"
+ depends on MMC_BLOCK != n && EXPERIMENTAL
+ default n
+ help
+ By default all writes are done one sector at a time. Enable
+ this option to transfer as large blocks as the host supports.
+ The transfer speed is in most cases doubled.
+
config MMC_ARMMMCI
tristate "ARM AMBA Multimedia Card Interface support"
depends on ARM_AMBA && MMC
If unsure, say N.
+config MMC_OMAP
+ tristate "TI OMAP Multimedia Card Interface support"
+ depends on ARCH_OMAP && MMC
+ select TPS65010 if MACH_OMAP_H2
+ help
+ This selects the TI OMAP Multimedia card Interface.
+ If you have an OMAP board with a Multimedia Card slot,
+ say Y or M here.
+
+ If unsure, say N.
+
config MMC_WBSD
tristate "Winbond W83L51xD SD/MMC Card Interface support"
depends on MMC && ISA_DMA_API
obj-$(CONFIG_MMC_PXA) += pxamci.o
obj-$(CONFIG_MMC_WBSD) += wbsd.o
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
+obj-$(CONFIG_MMC_OMAP) += omap.o
mmc_core-y := mmc.o mmc_queue.o mmc_sysfs.o
int bit = fls(host->ocr_avail) - 1;
host->ios.vdd = bit;
+ host->ios.clock = host->f_min;
host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
host->ios.chip_select = MMC_CS_DONTCARE;
host->ios.power_mode = MMC_POWER_UP;
mmc_delay(1);
- host->ios.clock = host->f_min;
host->ios.power_mode = MMC_POWER_ON;
host->ops->set_ios(host, &host->ios);
if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
break;
-
+ mmc_delay(1);
err = MMC_ERR_TIMEOUT;
mmc_delay(10);
host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
host->ops->set_ios(host, &host->ios);
+ /*
+ * Some already detectd cards get confused in the card identification
+ * mode and futher commands can fail. Doing an extra status inquiry
+ * after the identification mode seems to get cards back to their
+ * senses.
+ */
+ mmc_check_cards(host);
+
mmc_read_csds(host);
if (host->mode == MMC_MODE_SD)
--- /dev/null
+/*
+ * linux/drivers/media/mmc/omap.c
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Written by Tuukka Tikkanen and Juha Yrjölä <juha.yrjola@nokia.com>
+ * Misc hacks here and there by Tony Lindgren <tony@atomide.com>
+ * Other hacks (DMA, SD, etc) by 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/config.h>
+
+// #define CONFIG_MMC_DEBUG
+#ifdef CONFIG_MMC_DEBUG
+#define DEBUG /* for dev_dbg(), pr_debug(), etc */
+#endif
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/protocol.h>
+#include <linux/mmc/card.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/scatterlist.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/fpga.h>
+#include <asm/arch/tps65010.h>
+#include <asm/arch/menelaus.h>
+
+#include "omap.h"
+
+#define DRIVER_NAME "mmci-omap"
+
+#ifdef CONFIG_MMC_DEBUG
+#define DBG(x...) pr_debug(x)
+//#define DBG(x...) printk(x)
+#else
+#define DBG(x...) do { } while (0)
+#endif
+
+/* Specifies how often in millisecs to poll for card status changes
+ * when the cover switch is open */
+#define OMAP_MMC_SWITCH_POLL_DELAY 500
+
+static int mmc_omap_enable_poll = 1;
+
+struct mmc_omap_host {
+ int initialized;
+ int suspended;
+ struct mmc_request * mrq;
+ struct mmc_command * cmd;
+ struct mmc_data * data;
+ struct mmc_host * mmc;
+ struct device * dev;
+ unsigned char id; /* 16xx chips have 2 MMC blocks */
+ struct clk * iclk;
+ struct clk * fclk;
+ void __iomem *base;
+ int irq;
+ unsigned char bus_mode;
+ unsigned char hw_bus_mode;
+
+ unsigned int sg_len;
+ int sg_idx;
+ u16 * buffer;
+ u32 buffer_bytes_left;
+ u32 total_bytes_left;
+ struct timer_list xfer_timer;
+
+ unsigned use_dma:1;
+ unsigned brs_received:1, dma_done:1;
+ unsigned dma_is_read:1;
+ unsigned dma_in_use:1;
+ int dma_ch;
+ spinlock_t dma_lock;
+ struct timer_list dma_timer;
+ unsigned dma_len;
+
+ short power_pin;
+ short wp_pin;
+
+ int switch_pin;
+ struct work_struct switch_work;
+ struct timer_list switch_timer;
+ int switch_last_state;
+};
+
+static inline int
+mmc_omap_cover_is_open(struct mmc_omap_host *host)
+{
+ if (host->switch_pin < 0)
+ return 0;
+ return omap_get_gpio_datain(host->switch_pin);
+}
+
+static ssize_t
+mmc_omap_show_cover_switch(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mmc_omap_host *host = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", mmc_omap_cover_is_open(host) ? "open" : "closed");
+}
+
+static DEVICE_ATTR(cover_switch, S_IRUGO, mmc_omap_show_cover_switch, NULL);
+
+static ssize_t
+mmc_omap_show_enable_poll(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", mmc_omap_enable_poll);
+}
+
+static ssize_t
+mmc_omap_store_enable_poll(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t size)
+{
+ int enable_poll;
+
+ if (sscanf(buf, "%10d", &enable_poll) != 1)
+ return -EINVAL;
+
+ if (enable_poll != mmc_omap_enable_poll) {
+ struct mmc_omap_host *host = dev_get_drvdata(dev);
+
+ mmc_omap_enable_poll = enable_poll;
+ if (enable_poll && host->switch_pin >= 0)
+ schedule_work(&host->switch_work);
+ }
+ return size;
+}
+
+static DEVICE_ATTR(enable_poll, 0664,
+ mmc_omap_show_enable_poll, mmc_omap_store_enable_poll);
+
+static void
+mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd)
+{
+ u32 cmdreg;
+ u32 resptype;
+ u32 cmdtype;
+
+ pr_debug("MMC%d: CMD%d, argument 0x%08x%s%s%s%s\n",
+ host->id, cmd->opcode, cmd->arg,
+ (cmd->flags & MMC_RSP_SHORT) ? ", 32-bit response" : "",
+ (cmd->flags & MMC_RSP_LONG) ? ", 128-bit response" : "",
+ (cmd->flags & MMC_RSP_CRC) ? ", CRC" : "",
+ (cmd->flags & MMC_RSP_BUSY) ? ", busy notification" : "");
+
+ host->cmd = cmd;
+
+ resptype = 0;
+ cmdtype = 0;
+
+ /*
+ * On 24xx we may have external MMC transceiver on Menelaus.
+ * In that case we need to manually toggle between open-drain
+ * and push-pull states.
+ */
+ if (omap_has_menelaus() && (host->bus_mode != host->hw_bus_mode)) {
+ if (host->bus_mode == MMC_BUSMODE_OPENDRAIN)
+ menelaus_mmc_opendrain(1);
+ else
+ menelaus_mmc_opendrain(0);
+ host->hw_bus_mode = host->bus_mode;
+ }
+
+ if (!(cmd->flags & MMC_RSP_PRESENT))
+ resptype = 0; /* Resp 0 */
+
+ if (cmd->flags & MMC_RSP_136)
+ resptype = 2; /* Resp 2 */
+ else {
+ if (host->bus_mode == MMC_BUSMODE_OPENDRAIN)
+ resptype = 3; /* Resp 3 */
+ else
+ resptype = 1; /* Resp 1, Resp 1b */
+ }
+
+ /* Protocol layer does not provide command type, but our hardware
+ * needs it!
+ * any data transfer means adtc type (but that information is not
+ * in command structure, so we flagged it into host struct.)
+ * However, telling bc, bcr and ac apart based on response is
+ * not foolproof:
+ * CMD0 = bc = resp0 CMD15 = ac = resp0
+ * CMD2 = bcr = resp2 CMD10 = ac = resp2
+ *
+ * Resolve to best guess with some exception testing:
+ * resp0 -> bc, except CMD15 = ac
+ * rest are ac, except if opendrain
+ */
+ if (host->data) {
+ cmdtype = OMAP_MMC_CMDTYPE_ADTC;
+ } else if (resptype == 0 && cmd->opcode != 15) {
+ cmdtype = OMAP_MMC_CMDTYPE_BC;
+ } else if (host->bus_mode == MMC_BUSMODE_OPENDRAIN) {
+ cmdtype = OMAP_MMC_CMDTYPE_BCR;
+ } else {
+ cmdtype = OMAP_MMC_CMDTYPE_AC;
+ }
+
+ cmdreg = cmd->opcode | (resptype << 8) | (cmdtype << 12);
+
+ if (host->bus_mode == MMC_BUSMODE_OPENDRAIN)
+ cmdreg |= 1 << 6;
+
+ if (cmd->flags & MMC_RSP_BUSY)
+ cmdreg |= 1 << 11;
+
+ if (host->data && !(host->data->flags & MMC_DATA_WRITE))
+ cmdreg |= 1 << 15;
+
+ clk_enable(host->fclk);
+
+ OMAP_MMC_WRITE(host->base, CTO, 200);
+ OMAP_MMC_WRITE(host->base, ARGL, cmd->arg & 0xffff);
+ OMAP_MMC_WRITE(host->base, ARGH, cmd->arg >> 16);
+ OMAP_MMC_WRITE(host->base, IE,
+ OMAP_MMC_STAT_A_EMPTY | OMAP_MMC_STAT_A_FULL |
+ OMAP_MMC_STAT_CMD_CRC | OMAP_MMC_STAT_CMD_TOUT |
+ OMAP_MMC_STAT_DATA_CRC | OMAP_MMC_STAT_DATA_TOUT |
+ OMAP_MMC_STAT_END_OF_CMD | OMAP_MMC_STAT_CARD_ERR |
+ OMAP_MMC_STAT_END_OF_DATA);
+ OMAP_MMC_WRITE(host->base, CMD, cmdreg);
+}
+
+static void
+mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
+{
+ del_timer_sync(&host->xfer_timer);
+
+ if (host->dma_in_use) {
+ enum dma_data_direction dma_data_dir;
+
+ BUG_ON(host->dma_ch < 0);
+ if (data->error != MMC_ERR_NONE)
+ omap_stop_dma(host->dma_ch);
+ /* Release DMA channel lazily */
+ mod_timer(&host->dma_timer, jiffies + HZ);
+ if (data->flags & MMC_DATA_WRITE)
+ dma_data_dir = DMA_TO_DEVICE;
+ else
+ dma_data_dir = DMA_FROM_DEVICE;
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len,
+ dma_data_dir);
+ }
+ host->data = NULL;
+ host->sg_len = 0;
+ clk_disable(host->fclk);
+
+ /* NOTE: MMC layer will sometimes poll-wait CMD13 next, issuing
+ * dozens of requests until the card finishes writing data.
+ * It'd be cheaper to just wait till an EOFB interrupt arrives...
+ */
+
+ if (!data->stop) {
+ host->mrq = NULL;
+ mmc_request_done(host->mmc, data->mrq);
+ return;
+ }
+
+ mmc_omap_start_command(host, data->stop);
+}
+
+static void
+mmc_omap_end_of_data(struct mmc_omap_host *host, struct mmc_data *data)
+{
+ unsigned long flags;
+ int done;
+
+ if (!host->dma_in_use) {
+ mmc_omap_xfer_done(host, data);
+ return;
+ }
+ done = 0;
+ spin_lock_irqsave(&host->dma_lock, flags);
+ if (host->dma_done)
+ done = 1;
+ else
+ host->brs_received = 1;
+ spin_unlock_irqrestore(&host->dma_lock, flags);
+ if (done)
+ mmc_omap_xfer_done(host, data);
+}
+
+static void
+mmc_omap_dma_timer(unsigned long data)
+{
+ struct mmc_omap_host *host = (struct mmc_omap_host *) data;
+
+ DBG("MMC%d: Freeing DMA channel %d\n", host->id, host->dma_ch);
+ BUG_ON(host->dma_ch < 0);
+ omap_free_dma(host->dma_ch);
+ host->dma_ch = -1;
+}
+
+static void
+mmc_omap_dma_done(struct mmc_omap_host *host, struct mmc_data *data)
+{
+ unsigned long flags;
+ int done;
+
+ done = 0;
+ spin_lock_irqsave(&host->dma_lock, flags);
+ if (host->brs_received)
+ done = 1;
+ else
+ host->dma_done = 1;
+ spin_unlock_irqrestore(&host->dma_lock, flags);
+ if (done)
+ mmc_omap_xfer_done(host, data);
+}
+
+static void
+mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd, int card_ready)
+{
+ host->cmd = NULL;
+
+ if (cmd->flags & MMC_RSP_136) {
+ /* Response type 2 */
+ cmd->resp[3] =
+ OMAP_MMC_READ(host->base, RSP0) |
+ (OMAP_MMC_READ(host->base, RSP1) << 16);
+ cmd->resp[2] =
+ OMAP_MMC_READ(host->base, RSP2) |
+ (OMAP_MMC_READ(host->base, RSP3) << 16);
+ cmd->resp[1] =
+ OMAP_MMC_READ(host->base, RSP4) |
+ (OMAP_MMC_READ(host->base, RSP5) << 16);
+ cmd->resp[0] =
+ OMAP_MMC_READ(host->base, RSP6) |
+ (OMAP_MMC_READ(host->base, RSP7) << 16);
+ DBG("MMC%d: Response %08x %08x %08x %08x\n", host->id,
+ cmd->resp[0], cmd->resp[1],
+ cmd->resp[2], cmd->resp[3]);
+ } else {
+ /* Response types 1, 1b, 3, 4, 5, 6 */
+ cmd->resp[0] =
+ OMAP_MMC_READ(host->base, RSP6) |
+ (OMAP_MMC_READ(host->base, RSP7) << 16);
+ DBG("MMC%d: Response %08x\n", host->id, cmd->resp[0]);
+ if (card_ready) {
+ pr_debug("MMC%d: Faking card ready based on EOFB\n", host->id);
+ cmd->resp[0] |= R1_READY_FOR_DATA;
+ }
+ }
+
+ if (host->data == NULL || cmd->error != MMC_ERR_NONE) {
+ DBG("MMC%d: End request, err %x\n", host->id, cmd->error);
+ if (host->data != NULL)
+ del_timer_sync(&host->xfer_timer);
+ host->mrq = NULL;
+ clk_disable(host->fclk);
+ mmc_request_done(host->mmc, cmd->mrq);
+ }
+}
+
+static void
+mmc_omap_xfer_timeout(unsigned long data)
+{
+ struct mmc_omap_host *host = (struct mmc_omap_host *) data;
+
+ printk(KERN_ERR "MMC%d: Data xfer timeout\n", host->id);
+ if (host->data != NULL) {
+ host->data->error |= MMC_ERR_TIMEOUT;
+ /* Perform a pseudo-reset of the MMC core logic, since
+ * the controller seems to get really stuck */
+ OMAP_MMC_WRITE(host->base, CON, OMAP_MMC_READ(host->base, CON) & ~(1 << 11));
+ OMAP_MMC_WRITE(host->base, CON, OMAP_MMC_READ(host->base, CON) | (1 << 11));
+ mmc_omap_xfer_done(host, host->data);
+ }
+}
+
+/* PIO only */
+static void
+mmc_omap_sg_to_buf(struct mmc_omap_host *host)
+{
+ struct scatterlist *sg;
+
+ sg = host->data->sg + host->sg_idx;
+ host->buffer_bytes_left = sg->length;
+ host->buffer = page_address(sg->page) + sg->offset;
+ if (host->buffer_bytes_left > host->total_bytes_left)
+ host->buffer_bytes_left = host->total_bytes_left;
+}
+
+/* PIO only */
+static void
+mmc_omap_xfer_data(struct mmc_omap_host *host, int write)
+{
+ int n;
+ void __iomem *reg;
+ u16 *p;
+
+ if (host->buffer_bytes_left == 0) {
+ host->sg_idx++;
+ BUG_ON(host->sg_idx == host->sg_len);
+ mmc_omap_sg_to_buf(host);
+ }
+ n = 64;
+ if (n > host->buffer_bytes_left)
+ n = host->buffer_bytes_left;
+ host->buffer_bytes_left -= n;
+ host->total_bytes_left -= n;
+ host->data->bytes_xfered += n;
+
+ /* Optimize the loop a bit by calculating the register only
+ * once */
+ reg = host->base + OMAP_MMC_REG_DATA;
+ p = host->buffer;
+ n /= 2;
+ if (write) {
+ while (n--)
+ __raw_writew(*p++, reg);
+ } else {
+ while (n-- > 0)
+ *p++ = __raw_readw(reg);
+ }
+ host->buffer = p;
+}
+
+static inline void mmc_omap_report_irq(u16 status)
+{
+ static const char *mmc_omap_status_bits[] = {
+ "EOC", "CD", "CB", "BRS", "EOFB", "DTO", "DCRC", "CTO",
+ "CCRC", "CRW", "AF", "AE", "OCRB", "CIRQ", "CERR"
+ };
+ int i, c = 0;
+
+ for (i = 0; i < ARRAY_SIZE(mmc_omap_status_bits); i++)
+ if (status & (1 << i)) {
+ if (c)
+ printk(" ");
+ printk("%s", mmc_omap_status_bits[i]);
+ c++;
+ }
+}
+
+static irqreturn_t mmc_omap_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct mmc_omap_host * host = (struct mmc_omap_host *)dev_id;
+ u16 status;
+ int end_command;
+ int end_transfer;
+ int card_ready;
+ int transfer_error;
+
+ if (host->cmd == NULL && host->data == NULL) {
+ status = OMAP_MMC_READ(host->base, STAT);
+ printk(KERN_INFO "MMC%d: Spurious interrupt 0x%04x\n", host->id, status);
+ if (status != 0) {
+ OMAP_MMC_WRITE(host->base, STAT, status);
+ OMAP_MMC_WRITE(host->base, IE, 0);
+ }
+ return IRQ_HANDLED;
+ }
+
+ end_command = 0;
+ end_transfer = 0;
+ card_ready = 0;
+ transfer_error = 0;
+
+ while ((status = OMAP_MMC_READ(host->base, STAT)) != 0) {
+ OMAP_MMC_WRITE(host->base, STAT, status); // Reset status bits
+#ifdef CONFIG_MMC_DEBUG
+ printk(KERN_DEBUG "\tMMC IRQ %04x (CMD %d): ", status,
+ host->cmd != NULL ? host->cmd->opcode : -1);
+ mmc_omap_report_irq(status);
+ printk("\n");
+#endif
+ if (host->total_bytes_left) {
+ if ((status & OMAP_MMC_STAT_A_FULL) ||
+ (status & OMAP_MMC_STAT_END_OF_DATA))
+ mmc_omap_xfer_data(host, 0);
+ if (status & OMAP_MMC_STAT_A_EMPTY)
+ mmc_omap_xfer_data(host, 1);
+ }
+
+ if (status & OMAP_MMC_STAT_END_OF_DATA) {
+ // Block sent/received
+ end_transfer = 1;
+ }
+
+ if (status & OMAP_MMC_STAT_DATA_TOUT) {
+ // Data timeout
+ printk(KERN_DEBUG "MMC%d: Data timeout\n", host->id);
+ if (host->data) {
+ host->data->error |= MMC_ERR_TIMEOUT;
+ transfer_error = 1;
+ }
+ }
+
+ if (status & OMAP_MMC_STAT_DATA_CRC) {
+ // Data CRC error
+ if (host->data) {
+ host->data->error |= MMC_ERR_BADCRC;
+ printk(KERN_DEBUG "MMC%d: Data CRC error, bytes left %d\n",
+ host->id, host->total_bytes_left);
+ transfer_error = 1;
+ } else {
+ printk(KERN_DEBUG "MMC%d: Data CRC error\n",
+ host->id);
+ }
+ }
+
+ if (status & OMAP_MMC_STAT_CMD_TOUT) {
+ /* Timeouts are routine with some commands */
+ if (host->cmd) {
+ if (host->cmd->opcode != MMC_ALL_SEND_CID &&
+ host->cmd->opcode != MMC_SEND_OP_COND &&
+ host->cmd->opcode != MMC_APP_CMD &&
+ !mmc_omap_cover_is_open(host))
+ printk(KERN_ERR "MMC%d: Command timeout, CMD%d\n",
+ host->id, host->cmd->opcode);
+ host->cmd->error |= MMC_ERR_TIMEOUT;
+ end_command = 1;
+ }
+ }
+
+ if (status & OMAP_MMC_STAT_CMD_CRC) {
+ // Command CRC error
+ if (host->cmd) {
+ printk(KERN_ERR "MMC%d: Command CRC error (CMD%d, arg 0x%08x)\n",
+ host->id, host->cmd->opcode,
+ host->cmd->arg);
+ host->cmd->error |= MMC_ERR_BADCRC;
+ end_command = 1;
+ } else
+ printk(KERN_ERR "MMC%d: Command CRC error without cmd?\n", host->id);
+ }
+
+ if (status & OMAP_MMC_STAT_OCR_BUSY) {
+ /* OCR Busy ... happens a lot */
+ if (host->cmd && host->cmd->opcode != MMC_SEND_OP_COND
+ && host->cmd->opcode != MMC_SET_RELATIVE_ADDR) {
+ DBG("MMC%d: OCR busy error, CMD%d\n",
+ host->id, host->cmd->opcode);
+ }
+ }
+
+ if (status & OMAP_MMC_STAT_CARD_ERR) {
+ if (host->cmd && host->cmd->opcode == MMC_STOP_TRANSMISSION) {
+ u32 response = OMAP_MMC_READ(host->base, RSP6)
+ | (OMAP_MMC_READ(host->base, RSP7) << 16);
+ /* STOP sometimes sets must-ignore bits */
+ if (!(response & (R1_CC_ERROR
+ | R1_ILLEGAL_COMMAND
+ | R1_COM_CRC_ERROR))) {
+ end_command = 1;
+ continue;
+ }
+ }
+
+ // Card status error
+ printk(KERN_DEBUG "MMC%d: Card status error (CMD%d)\n",
+ host->id, host->cmd->opcode);
+ if (host->cmd) {
+ host->cmd->error |= MMC_ERR_FAILED;
+ end_command = 1;
+ }
+ if (host->data) {
+ host->data->error |= MMC_ERR_FAILED;
+ transfer_error = 1;
+ }
+ }
+
+ /*
+ * NOTE: On 1610 the END_OF_CMD may come too early when
+ * starting a write
+ */
+ if ((status & OMAP_MMC_STAT_END_OF_CMD) &&
+ (!(status & OMAP_MMC_STAT_A_EMPTY))) {
+ // End of command phase
+ end_command = 1;
+ }
+ /*
+ * Some cards produce EOFB interrupt and never
+ * raise R1_READY_FOR_DATA bit after that.
+ * To avoid infinite card status polling loop,
+ * we must fake that bit to MMC layer.
+ */
+ if ((status & OMAP_MMC_STAT_END_OF_CMD) &&
+ (status & OMAP_MMC_STAT_END_BUSY)) {
+ card_ready = 1;
+ }
+ }
+
+ if (end_command) {
+ mmc_omap_cmd_done(host, host->cmd, card_ready);
+ }
+ if (transfer_error)
+ mmc_omap_xfer_done(host, host->data);
+ else if (end_transfer)
+ mmc_omap_end_of_data(host, host->data);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mmc_omap_switch_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct mmc_omap_host *host = (struct mmc_omap_host *) dev_id;
+ int cover_open, detect_now;
+
+ cover_open = mmc_omap_cover_is_open(host);
+ DBG("MMC%d cover is now %s\n", host->id,
+ cover_open ? "open" : "closed");
+ set_irq_type(OMAP_GPIO_IRQ(host->switch_pin), 0);
+ detect_now = 0;
+ if (host->switch_last_state != cover_open) {
+ /* If the cover was just opened and a card is inserted,
+ * we want to inform user-space about the event as soon as
+ * possible */
+ if (cover_open) {
+ struct mmc_card *card;
+
+ list_for_each_entry(card, &host->mmc->cards, node)
+ if (mmc_card_present(card))
+ detect_now = 1;
+ }
+ }
+ if (detect_now)
+ schedule_work(&host->switch_work);
+ else {
+ /* Delay the switch work a little bit to get rid of the GPIO
+ * line bounces */
+ mod_timer(&host->switch_timer,
+ jiffies + msecs_to_jiffies(OMAP_MMC_SWITCH_POLL_DELAY) / 2);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void mmc_omap_switch_timer(unsigned long arg)
+{
+ struct mmc_omap_host *host = (struct mmc_omap_host *) arg;
+
+ schedule_work(&host->switch_work);
+}
+
+/* FIXME: Handle card insertion and removal properly. Maybe use a mask
+ * for MMC state? */
+static void mmc_omap_switch_callback(unsigned long data, u8 mmc_mask)
+{
+ if (machine_is_omap_h4()) {
+ if (mmc_mask & 0x1)
+ printk("XXX card in slot 1\n");
+ if (mmc_mask & 0x2)
+ printk("XXX card in slot 2\n");
+ } else {
+ /* Assume card detect connected to cover switch */
+ if (mmc_mask & 0x2)
+ printk("XXX cover open\n");
+ else
+ printk("XXX cover closed\n");
+ }
+}
+
+static void mmc_omap_switch_handler(void *data)
+{
+ struct mmc_omap_host *host = (struct mmc_omap_host *) data;
+ struct mmc_card *card;
+ static int complained = 0;
+ int cards = 0, cover_open;
+
+ if (host->switch_pin == -1)
+ return;
+ set_irq_type(OMAP_GPIO_IRQ(host->switch_pin), IRQT_RISING | IRQT_FALLING);
+ cover_open = mmc_omap_cover_is_open(host);
+ if (cover_open != host->switch_last_state) {
+ kobject_uevent(&host->dev->kobj, KOBJ_CHANGE);
+ host->switch_last_state = cover_open;
+ }
+ DBG("MMC cover switch handler started\n");
+ mmc_detect_change(host->mmc, 0);
+ list_for_each_entry(card, &host->mmc->cards, node) {
+ if (mmc_card_present(card))
+ cards++;
+ }
+ DBG("MMC%d: %d card(s) present\n", host->id, cards);
+ if (cover_open) {
+ if (!complained) {
+ printk(KERN_INFO "MMC%d: cover is open\n", host->id);
+ complained = 1;
+ }
+ if (cover_open && (cards || mmc_omap_enable_poll))
+ mod_timer(&host->switch_timer, jiffies +
+ msecs_to_jiffies(OMAP_MMC_SWITCH_POLL_DELAY));
+ } else {
+ complained = 0;
+ }
+}
+
+/* prepare to transfer the next segment of a scatterlist */
+static void
+mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data)
+{
+ int dma_ch = host->dma_ch;
+ unsigned long data_addr;
+ u16 buf, frame;
+ u32 count;
+ struct scatterlist *sg = &data->sg[host->sg_idx];
+ int src_port = 0;
+ int dst_port = 0;
+ int sync_dev = 0;
+
+ data_addr = (unsigned long)io_v2p((void __force *) host->base) + OMAP_MMC_REG_DATA;
+ frame = 1 << data->blksz_bits;
+ count = (u32)sg_dma_len(sg);
+
+ /* the MMC layer is confused about single block writes... */
+ if ((data->blocks == 1) && (count > (1 << data->blksz_bits))) {
+ pr_debug("patch bogus single block length! %d > %d\n",
+ count, frame);
+ count = frame;
+ }
+ host->dma_len = count;
+
+ /* FIFO is 16x2 bytes on 15xx, and 32x2 bytes on 16xx and 24xx.
+ * Use 16 or 32 word frames when the blocksize is at least that large.
+ * Blocksize is usually 512 bytes; but not for some SD reads.
+ */
+ if (cpu_is_omap15xx() && frame > 32)
+ frame = 32;
+ else if (frame > 64)
+ frame = 64;
+ count /= frame;
+ frame >>= 1;
+
+ if (!(data->flags & MMC_DATA_WRITE)) {
+ buf = 0x800f | ((frame - 1) << 8);
+
+ if (cpu_class_is_omap1()) {
+ src_port = OMAP_DMA_PORT_TIPB;
+ dst_port = OMAP_DMA_PORT_EMIFF;
+ }
+ if (cpu_is_omap24xx())
+ sync_dev = OMAP24XX_DMA_MMC1_RX;
+
+ omap_set_dma_src_params(dma_ch, src_port,
+ OMAP_DMA_AMODE_CONSTANT,
+ data_addr, 0, 0);
+ omap_set_dma_dest_params(dma_ch, dst_port,
+ OMAP_DMA_AMODE_POST_INC,
+ sg_dma_address(sg), 0, 0);
+ omap_set_dma_dest_data_pack(dma_ch, 1);
+ omap_set_dma_dest_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4);
+ } else {
+ buf = 0x0f80 | ((frame - 1) << 0);
+
+ if (cpu_class_is_omap1()) {
+ src_port = OMAP_DMA_PORT_EMIFF;
+ dst_port = OMAP_DMA_PORT_TIPB;
+ }
+ if (cpu_is_omap24xx())
+ sync_dev = OMAP24XX_DMA_MMC1_TX;
+
+ omap_set_dma_dest_params(dma_ch, dst_port,
+ OMAP_DMA_AMODE_CONSTANT,
+ data_addr, 0, 0);
+ omap_set_dma_src_params(dma_ch, src_port,
+ OMAP_DMA_AMODE_POST_INC,
+ sg_dma_address(sg), 0, 0);
+ omap_set_dma_src_data_pack(dma_ch, 1);
+ omap_set_dma_src_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4);
+ }
+
+ /* Max limit for DMA frame count is 0xffff */
+ if (unlikely(count > 0xffff))
+ BUG();
+
+ OMAP_MMC_WRITE(host->base, BUF, buf);
+ omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S16,
+ frame, count, OMAP_DMA_SYNC_FRAME,
+ sync_dev, 0);
+}
+
+/* a scatterlist segment completed */
+static void mmc_omap_dma_cb(int lch, u16 ch_status, void *data)
+{
+ struct mmc_omap_host *host = (struct mmc_omap_host *) data;
+ struct mmc_data *mmcdat = host->data;
+
+ if (unlikely(host->dma_ch < 0)) {
+ printk(KERN_ERR "MMC%d: DMA callback while DMA not enabled\n",
+ host->id);
+ return;
+ }
+ /* FIXME: We really should do something to _handle_ the errors */
+ if (ch_status & OMAP_DMA_TOUT_IRQ) {
+ printk(KERN_ERR "MMC%d: DMA timeout\n", host->id);
+ return;
+ }
+ if (ch_status & OMAP_DMA_DROP_IRQ) {
+ printk(KERN_ERR "MMC%d: DMA sync error\n", host->id);
+ return;
+ }
+ if (!(ch_status & OMAP_DMA_BLOCK_IRQ)) {
+ /* REVISIT we should be able to avoid getting IRQs with
+ * just SYNC status ...
+ */
+ if ((ch_status & ~OMAP1_DMA_SYNC_IRQ))
+ pr_debug("MMC%d: DMA channel status: %04x\n",
+ host->id, ch_status);
+ return;
+ }
+ mmcdat->bytes_xfered += host->dma_len;
+
+ pr_debug("\tMMC DMA %d bytes CB %04x (%d segments to go), %p\n",
+ host->dma_len, ch_status,
+ host->sg_len - host->sg_idx - 1, host->data);
+
+ host->sg_idx++;
+ if (host->sg_idx < host->sg_len) {
+ mmc_omap_prepare_dma(host, host->data);
+ omap_start_dma(host->dma_ch);
+ } else
+ mmc_omap_dma_done(host, host->data);
+}
+
+static int mmc_omap_get_dma_channel(struct mmc_omap_host *host, struct mmc_data *data)
+{
+ const char *dev_name;
+ int sync_dev, dma_ch, is_read, r;
+
+ is_read = !(data->flags & MMC_DATA_WRITE);
+ del_timer_sync(&host->dma_timer);
+ if (host->dma_ch >= 0) {
+ if (is_read == host->dma_is_read)
+ return 0;
+ omap_free_dma(host->dma_ch);
+ host->dma_ch = -1;
+ }
+
+ if (is_read) {
+ if (host->id == 1) {
+ sync_dev = OMAP_DMA_MMC_RX;
+ dev_name = "MMC1 read";
+ } else {
+ sync_dev = OMAP_DMA_MMC2_RX;
+ dev_name = "MMC2 read";
+ }
+ } else {
+ if (host->id == 1) {
+ sync_dev = OMAP_DMA_MMC_TX;
+ dev_name = "MMC1 write";
+ } else {
+ sync_dev = OMAP_DMA_MMC2_TX;
+ dev_name = "MMC2 write";
+ }
+ }
+ r = omap_request_dma(sync_dev, dev_name, mmc_omap_dma_cb,
+ host, &dma_ch);
+ if (r != 0) {
+ printk("MMC%d: omap_request_dma() failed with %d\n",
+ host->id, r);
+ return r;
+ }
+ host->dma_ch = dma_ch;
+ host->dma_is_read = is_read;
+
+ return 0;
+}
+
+static inline void set_cmd_timeout(struct mmc_omap_host *host, struct mmc_request *req)
+{
+ u16 reg;
+
+ reg = OMAP_MMC_READ(host->base, SDIO);
+ reg &= ~(1 << 5);
+ OMAP_MMC_WRITE(host->base, SDIO, reg);
+ /* Set maximum timeout */
+ OMAP_MMC_WRITE(host->base, CTO, 0xff);
+}
+
+static inline void set_data_timeout(struct mmc_omap_host *host, struct mmc_request *req)
+{
+ int timeout;
+ u16 reg;
+
+ /* Convert ns to clock cycles by assuming 20MHz frequency
+ * 1 cycle at 20MHz = 500 ns
+ */
+ timeout = req->data->timeout_clks + req->data->timeout_ns / 500;
+
+ /* Some cards require more time to do at least the first read operation */
+ timeout = timeout << 4;
+
+ /* Check if we need to use timeout multiplier register */
+ reg = OMAP_MMC_READ(host->base, SDIO);
+ if (timeout > 0xffff) {
+ reg |= (1 << 5);
+ timeout /= 1024;
+ } else
+ reg &= ~(1 << 5);
+ OMAP_MMC_WRITE(host->base, SDIO, reg);
+ OMAP_MMC_WRITE(host->base, DTO, timeout);
+}
+
+static void
+mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
+{
+ struct mmc_data *data = req->data;
+ int i, use_dma, block_size;
+ unsigned sg_len;
+
+ host->data = data;
+ if (data == NULL) {
+ OMAP_MMC_WRITE(host->base, BLEN, 0);
+ OMAP_MMC_WRITE(host->base, NBLK, 0);
+ OMAP_MMC_WRITE(host->base, BUF, 0);
+ host->dma_in_use = 0;
+ set_cmd_timeout(host, req);
+ return;
+ }
+
+
+ block_size = 1 << data->blksz_bits;
+
+ OMAP_MMC_WRITE(host->base, NBLK, data->blocks - 1);
+ OMAP_MMC_WRITE(host->base, BLEN, block_size - 1);
+ set_data_timeout(host, req);
+
+ /* cope with calling layer confusion; it issues "single
+ * block" writes using multi-block scatterlists.
+ */
+ sg_len = (data->blocks == 1) ? 1 : data->sg_len;
+
+ /* Only do DMA for entire blocks */
+ use_dma = host->use_dma;
+ if (use_dma) {
+ for (i = 0; i < sg_len; i++) {
+ if ((data->sg[i].length % block_size) != 0) {
+ use_dma = 0;
+ break;
+ }
+ }
+ }
+
+ host->sg_idx = 0;
+ if (use_dma) {
+ if (mmc_omap_get_dma_channel(host, data) == 0) {
+ enum dma_data_direction dma_data_dir;
+
+ if (data->flags & MMC_DATA_WRITE)
+ dma_data_dir = DMA_TO_DEVICE;
+ else
+ dma_data_dir = DMA_FROM_DEVICE;
+
+ host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
+ sg_len, dma_data_dir);
+ host->total_bytes_left = 0;
+ mmc_omap_prepare_dma(host, req->data);
+ host->brs_received = 0;
+ host->dma_done = 0;
+ host->dma_in_use = 1;
+ } else
+ use_dma = 0;
+ }
+
+ /* Revert to PIO? */
+ if (!use_dma) {
+ OMAP_MMC_WRITE(host->base, BUF, 0x1f1f);
+ host->total_bytes_left = data->blocks * block_size;
+ host->sg_len = sg_len;
+ mmc_omap_sg_to_buf(host);
+ host->dma_in_use = 0;
+ }
+ mod_timer(&host->xfer_timer, jiffies + msecs_to_jiffies(500));
+
+ pr_debug("MMC%d: %s %s %s, DTO %d cycles + %d ns, "
+ "%d blocks of %d bytes, %d segments\n",
+ host->id, use_dma ? "DMA" : "PIO",
+ (data->flags & MMC_DATA_STREAM) ? "stream" : "block",
+ (data->flags & MMC_DATA_WRITE) ? "write" : "read",
+ data->timeout_clks, data->timeout_ns, data->blocks,
+ block_size, host->sg_len);
+}
+
+static inline int is_broken_card(struct mmc_card *card)
+{
+ int i;
+ struct mmc_cid *c = &card->cid;
+ static const struct broken_card_cid {
+ unsigned int manfid;
+ char prod_name[8];
+ unsigned char hwrev;
+ unsigned char fwrev;
+ } broken_cards[] = {
+ { 0x00150000, "\x30\x30\x30\x30\x30\x30\x15\x00", 0x06, 0x03 },
+ };
+
+ for (i = 0; i < sizeof(broken_cards)/sizeof(broken_cards[0]); i++) {
+ const struct broken_card_cid *b = broken_cards + i;
+
+ if (b->manfid != c->manfid)
+ continue;
+ if (memcmp(b->prod_name, c->prod_name, sizeof(b->prod_name)) != 0)
+ continue;
+ if (b->hwrev != c->hwrev || b->fwrev != c->fwrev)
+ continue;
+ return 1;
+ }
+ return 0;
+}
+
+static void mmc_omap_request(struct mmc_host *mmc, struct mmc_request *req)
+{
+ struct mmc_omap_host *host = mmc_priv(mmc);
+
+ WARN_ON(host->mrq != NULL);
+
+ host->mrq = req;
+
+ /* Some cards (vendor left unnamed to protect the guilty) seem to
+ * require this delay after power-up. Otherwise we'll get mysterious
+ * data timeouts. */
+ if (req->cmd->opcode == MMC_SEND_CSD) {
+ struct mmc_card *card;
+ int broken_present = 0;
+
+ list_for_each_entry(card, &mmc->cards, node) {
+ if (is_broken_card(card)) {
+ broken_present = 1;
+ break;
+ }
+ }
+ if (broken_present) {
+ static int complained = 0;
+
+ if (!complained) {
+ printk(KERN_WARNING "MMC%d: Broken card workaround enabled\n",
+ host->id);
+ complained = 1;
+ }
+ if (in_interrupt()) {
+ /* This is nasty */
+ printk(KERN_ERR "Sleeping in IRQ handler, FIXME please!\n");
+ dump_stack();
+ mdelay(100);
+ } else {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(100 * HZ / 1000);
+ }
+ }
+ }
+
+ /* only touch fifo AFTER the controller readies it */
+ mmc_omap_prepare_data(host, req);
+ mmc_omap_start_command(host, req->cmd);
+ if (host->dma_in_use)
+ omap_start_dma(host->dma_ch);
+}
+
+static void innovator_fpga_socket_power(int on)
+{
+#if defined(CONFIG_MACH_OMAP_INNOVATOR) && defined(CONFIG_ARCH_OMAP15XX)
+
+ if (on) {
+ fpga_write(fpga_read(OMAP1510_FPGA_POWER) | (1 << 3),
+ OMAP1510_FPGA_POWER);
+ } else {
+ fpga_write(fpga_read(OMAP1510_FPGA_POWER) & ~(1 << 3),
+ OMAP1510_FPGA_POWER);
+ }
+#endif
+}
+
+/*
+ * Turn the socket power on/off. Innovator uses FPGA, most boards
+ * probably use GPIO.
+ */
+static void mmc_omap_power(struct mmc_omap_host *host, int on)
+{
+ if (on) {
+ if (machine_is_omap_innovator())
+ innovator_fpga_socket_power(1);
+ else if (machine_is_omap_h2())
+ tps65010_set_gpio_out_value(GPIO3, HIGH);
+ else if (machine_is_omap_h3())
+ /* GPIO 4 of TPS65010 sends SD_EN signal */
+ tps65010_set_gpio_out_value(GPIO4, HIGH);
+ else if (cpu_is_omap24xx()) {
+ u16 reg = OMAP_MMC_READ(host->base, CON);
+ OMAP_MMC_WRITE(host->base, CON, reg | (1 << 11));
+ } else
+ if (host->power_pin >= 0)
+ omap_set_gpio_dataout(host->power_pin, 1);
+ } else {
+ if (machine_is_omap_innovator())
+ innovator_fpga_socket_power(0);
+ else if (machine_is_omap_h2())
+ tps65010_set_gpio_out_value(GPIO3, LOW);
+ else if (machine_is_omap_h3())
+ tps65010_set_gpio_out_value(GPIO4, LOW);
+ else if (cpu_is_omap24xx()) {
+ u16 reg = OMAP_MMC_READ(host->base, CON);
+ OMAP_MMC_WRITE(host->base, CON, reg & ~(1 << 11));
+ } else
+ if (host->power_pin >= 0)
+ omap_set_gpio_dataout(host->power_pin, 0);
+ }
+}
+
+static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct mmc_omap_host *host = mmc_priv(mmc);
+ int dsor;
+ int realclock, i;
+
+ DBG("MMC%d: set_ios: clock %dHz busmode %d powermode %d Vdd %d.%02d\n",
+ host->id, ios->clock, ios->bus_mode, ios->power_mode,
+ ios->vdd / 100, ios->vdd % 100);
+
+ if (ios->power_mode == MMC_POWER_UP && ios->clock < 400000)
+ realclock = 400000; /* Fix for broken stack */
+ else
+ realclock = ios->clock;
+
+ if (ios->clock == 0)
+ dsor = 0;
+ else {
+ int func_clk_rate = clk_get_rate(host->fclk);
+
+ dsor = func_clk_rate / realclock;
+ if (dsor < 1)
+ dsor = 1;
+
+ if (func_clk_rate / dsor > realclock)
+ dsor++;
+
+ if (dsor > 250)
+ dsor = 250;
+ dsor++;
+
+ if (ios->bus_width == MMC_BUS_WIDTH_4)
+ dsor |= 1 << 15;
+ }
+
+ switch (ios->power_mode) {
+ case MMC_POWER_OFF:
+ mmc_omap_power(host, 0);
+ break;
+ case MMC_POWER_UP:
+ case MMC_POWER_ON:
+ mmc_omap_power(host, 1);
+ dsor |= 1<<11;
+ break;
+ }
+
+ host->bus_mode = ios->bus_mode;
+ if (omap_has_menelaus()) {
+ if (host->bus_mode == MMC_BUSMODE_OPENDRAIN)
+ menelaus_mmc_opendrain(1);
+ else
+ menelaus_mmc_opendrain(0);
+ }
+ host->hw_bus_mode = host->bus_mode;
+
+ clk_enable(host->fclk);
+
+ /* On insanely high arm_per frequencies something sometimes
+ * goes somehow out of sync, and the POW bit is not being set,
+ * which results in the while loop below getting stuck.
+ * Writing to the CON register twice seems to do the trick. */
+ for (i = 0; i < 2; i++)
+ OMAP_MMC_WRITE(host->base, CON, dsor);
+ if (ios->power_mode == MMC_POWER_UP) {
+ /* Wait a little while for the power regulator to
+ * settle */
+ msleep(1);
+ /* Send clock cycles, poll completion */
+ OMAP_MMC_WRITE(host->base, IE, 0);
+ OMAP_MMC_WRITE(host->base, STAT, 0xffff);
+ OMAP_MMC_WRITE(host->base, CMD, 1<<7);
+ while (0 == (OMAP_MMC_READ(host->base, STAT) & 1));
+ OMAP_MMC_WRITE(host->base, STAT, 1);
+ }
+ clk_disable(host->fclk);
+}
+
+static int mmc_omap_get_ro(struct mmc_host *mmc)
+{
+ struct mmc_omap_host *host = mmc_priv(mmc);
+
+ return host->wp_pin && omap_get_gpio_datain(host->wp_pin);
+}
+
+static struct mmc_host_ops mmc_omap_ops = {
+ .request = mmc_omap_request,
+ .set_ios = mmc_omap_set_ios,
+ .get_ro = mmc_omap_get_ro,
+};
+
+static int __init mmc_omap_probe(struct platform_device *pdev)
+{
+ struct omap_mmc_conf *minfo = pdev->dev.platform_data;
+ struct mmc_host *mmc;
+ struct mmc_omap_host *host = NULL;
+ int ret = 0;
+
+ if (pdev->resource[0].flags != IORESOURCE_MEM
+ || pdev->resource[1].flags != IORESOURCE_IRQ) {
+ printk(KERN_ERR "mmc_omap_probe: invalid resource type\n");
+ return -ENODEV;
+ }
+
+ if (!request_mem_region(pdev->resource[0].start,
+ pdev->resource[0].end - pdev->resource[0].start + 1,
+ pdev->name)) {
+ dev_dbg(&pdev->dev, "request_mem_region failed\n");
+ return -EBUSY;
+ }
+
+ mmc = mmc_alloc_host(sizeof(struct mmc_omap_host), &pdev->dev);
+ if (!mmc) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ host = mmc_priv(mmc);
+ host->mmc = mmc;
+
+ spin_lock_init(&host->dma_lock);
+ init_timer(&host->dma_timer);
+ host->dma_timer.function = mmc_omap_dma_timer;
+ host->dma_timer.data = (unsigned long) host;
+
+ init_timer(&host->xfer_timer);
+ host->xfer_timer.function = mmc_omap_xfer_timeout;
+ host->xfer_timer.data = (unsigned long) host;
+
+ host->id = pdev->id;
+
+ if (cpu_is_omap24xx()) {
+ host->iclk = clk_get(&pdev->dev, "mmc_ick");
+ if (IS_ERR(host->iclk))
+ goto out;
+ clk_enable(host->iclk);
+ }
+
+ if (!cpu_is_omap24xx())
+ host->fclk = clk_get(&pdev->dev, "mmc_ck");
+ else
+ host->fclk = clk_get(&pdev->dev, "mmc_fck");
+
+ if (IS_ERR(host->fclk)) {
+ ret = PTR_ERR(host->fclk);
+ goto out;
+ }
+
+ /* REVISIT:
+ * Also, use minfo->cover to decide how to manage
+ * the card detect sensing.
+ */
+ host->power_pin = minfo->power_pin;
+ host->switch_pin = minfo->switch_pin;
+ host->wp_pin = minfo->wp_pin;
+ host->use_dma = 1;
+ host->dma_ch = -1;
+
+ host->irq = pdev->resource[1].start;
+ host->base = (void __iomem *)pdev->resource[0].start;
+
+ if (minfo->wire4)
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
+
+ mmc->ops = &mmc_omap_ops;
+ mmc->f_min = 400000;
+ mmc->f_max = 24000000;
+ mmc->ocr_avail = MMC_VDD_33_34;
+
+ /* Use scatterlist DMA to reduce per-transfer costs.
+ * NOTE max_seg_size assumption that small blocks aren't
+ * normally used (except e.g. for reading SD registers).
+ */
+ mmc->max_phys_segs = 32;
+ mmc->max_hw_segs = 32;
+ mmc->max_sectors = 120; /* NBLK max 11-bits, OMAP also limited by DMA */
+ mmc->max_seg_size = mmc->max_sectors * 512;
+
+ if (host->power_pin >= 0) {
+ if ((ret = omap_request_gpio(host->power_pin)) != 0) {
+ printk(KERN_ERR "MMC%d: Unable to get GPIO pin for MMC power\n",
+ host->id);
+ goto out;
+ }
+ omap_set_gpio_direction(host->power_pin, 0);
+ }
+
+ ret = request_irq(host->irq, mmc_omap_irq, 0, DRIVER_NAME, host);
+ if (ret)
+ goto out;
+
+ host->dev = &pdev->dev;
+ platform_set_drvdata(pdev, host);
+
+ mmc_add_host(mmc);
+
+ if (host->switch_pin >= 0) {
+ INIT_WORK(&host->switch_work, mmc_omap_switch_handler, host);
+ init_timer(&host->switch_timer);
+ host->switch_timer.function = mmc_omap_switch_timer;
+ host->switch_timer.data = (unsigned long) host;
+ if (omap_request_gpio(host->switch_pin) != 0) {
+ printk(KERN_WARNING "MMC%d: Unable to get GPIO pin for MMC cover switch\n",
+ host->id);
+ host->switch_pin = -1;
+ goto no_switch;
+ }
+
+ omap_set_gpio_direction(host->switch_pin, 1);
+ ret = request_irq(OMAP_GPIO_IRQ(host->switch_pin),
+ mmc_omap_switch_irq,
+ SA_TRIGGER_RISING | SA_TRIGGER_FALLING,
+ DRIVER_NAME, host);
+ if (ret) {
+ printk(KERN_WARNING "MMC%d: Unable to get IRQ for MMC cover switch\n",
+ host->id);
+ omap_free_gpio(host->switch_pin);
+ host->switch_pin = -1;
+ goto no_switch;
+ }
+ ret = device_create_file(&pdev->dev, &dev_attr_cover_switch);
+ if (ret == 0) {
+ ret = device_create_file(&pdev->dev, &dev_attr_enable_poll);
+ if (ret != 0)
+ device_remove_file(&pdev->dev, &dev_attr_cover_switch);
+ }
+ if (ret) {
+ printk(KERN_WARNING "MMC%d: Unable to create sysfs attributes\n",
+ host->id);
+ free_irq(OMAP_GPIO_IRQ(host->switch_pin), host);
+ omap_free_gpio(host->switch_pin);
+ host->switch_pin = -1;
+ goto no_switch;
+ }
+ host->switch_last_state = mmc_omap_cover_is_open(host);
+ if (mmc_omap_enable_poll && mmc_omap_cover_is_open(host))
+ schedule_work(&host->switch_work);
+ }
+
+ if (omap_has_menelaus())
+ menelaus_mmc_register(mmc_omap_switch_callback,
+ (unsigned long)&host);
+
+no_switch:
+ return 0;
+
+out:
+ /* FIXME: Free other resources too. */
+ if (host) {
+ if (host->iclk && !IS_ERR(host->iclk))
+ clk_put(host->iclk);
+ if (host->fclk && !IS_ERR(host->fclk))
+ clk_put(host->fclk);
+ mmc_free_host(host->mmc);
+ }
+ return ret;
+}
+
+static int mmc_omap_remove(struct platform_device *pdev)
+{
+ struct mmc_omap_host *host = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ if (host) {
+ mmc_remove_host(host->mmc);
+ free_irq(host->irq, host);
+ mmc_omap_power(host, 0);
+
+ if (host->power_pin >= 0)
+ omap_free_gpio(host->power_pin);
+ if (host->switch_pin >= 0) {
+ device_remove_file(&pdev->dev, &dev_attr_enable_poll);
+ device_remove_file(&pdev->dev, &dev_attr_cover_switch);
+ free_irq(OMAP_GPIO_IRQ(host->switch_pin), host);
+ omap_free_gpio(host->switch_pin);
+ host->switch_pin = -1;
+ del_timer_sync(&host->switch_timer);
+ flush_scheduled_work();
+ }
+ if (host->iclk && !IS_ERR(host->iclk))
+ clk_put(host->iclk);
+ if (host->fclk && !IS_ERR(host->fclk))
+ clk_put(host->fclk);
+ mmc_free_host(host->mmc);
+ }
+
+ if (omap_has_menelaus())
+ menelaus_mmc_remove();
+
+ release_mem_region(pdev->resource[0].start,
+ pdev->resource[0].end - pdev->resource[0].start + 1);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int mmc_omap_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ int ret = 0;
+ struct mmc_omap_host *host = platform_get_drvdata(pdev);
+
+ if (host && host->suspended)
+ return 0;
+
+ if (!irqs_disabled())
+ return -EAGAIN;
+
+ if (host) {
+ ret = mmc_suspend_host(host->mmc, mesg);
+ if (ret == 0)
+ host->suspended = 1;
+ }
+ return ret;
+}
+
+static int mmc_omap_resume(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct mmc_omap_host *host = platform_get_drvdata(pdev);
+
+ if (host && !host->suspended)
+ return 0;
+
+ if (host) {
+ ret = mmc_resume_host(host->mmc);
+ if (ret == 0)
+ host->suspended = 0;
+ }
+
+ return ret;
+}
+#else
+#define mmc_omap_suspend NULL
+#define mmc_omap_resume NULL
+#endif
+
+static struct platform_driver mmc_omap_driver = {
+ .probe = mmc_omap_probe,
+ .remove = mmc_omap_remove,
+ .suspend = mmc_omap_suspend,
+ .resume = mmc_omap_resume,
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+};
+
+static int __init mmc_omap_init(void)
+{
+ return platform_driver_register(&mmc_omap_driver);
+}
+
+static void __exit mmc_omap_exit(void)
+{
+ platform_driver_unregister(&mmc_omap_driver);
+}
+
+module_init(mmc_omap_init);
+module_exit(mmc_omap_exit);
+
+MODULE_DESCRIPTION("OMAP Multimedia Card driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS(DRIVER_NAME);
+MODULE_AUTHOR("Juha Yrjölä");
--- /dev/null
+#ifndef DRIVERS_MEDIA_MMC_OMAP_H
+#define DRIVERS_MEDIA_MMC_OMAP_H
+
+#define OMAP_MMC_REG_CMD 0x00
+#define OMAP_MMC_REG_ARGL 0x04
+#define OMAP_MMC_REG_ARGH 0x08
+#define OMAP_MMC_REG_CON 0x0c
+#define OMAP_MMC_REG_STAT 0x10
+#define OMAP_MMC_REG_IE 0x14
+#define OMAP_MMC_REG_CTO 0x18
+#define OMAP_MMC_REG_DTO 0x1c
+#define OMAP_MMC_REG_DATA 0x20
+#define OMAP_MMC_REG_BLEN 0x24
+#define OMAP_MMC_REG_NBLK 0x28
+#define OMAP_MMC_REG_BUF 0x2c
+#define OMAP_MMC_REG_SDIO 0x34
+#define OMAP_MMC_REG_REV 0x3c
+#define OMAP_MMC_REG_RSP0 0x40
+#define OMAP_MMC_REG_RSP1 0x44
+#define OMAP_MMC_REG_RSP2 0x48
+#define OMAP_MMC_REG_RSP3 0x4c
+#define OMAP_MMC_REG_RSP4 0x50
+#define OMAP_MMC_REG_RSP5 0x54
+#define OMAP_MMC_REG_RSP6 0x58
+#define OMAP_MMC_REG_RSP7 0x5c
+#define OMAP_MMC_REG_IOSR 0x60
+#define OMAP_MMC_REG_SYSC 0x64
+#define OMAP_MMC_REG_SYSS 0x68
+
+#define OMAP_MMC_STAT_CARD_ERR (1 << 14)
+#define OMAP_MMC_STAT_CARD_IRQ (1 << 13)
+#define OMAP_MMC_STAT_OCR_BUSY (1 << 12)
+#define OMAP_MMC_STAT_A_EMPTY (1 << 11)
+#define OMAP_MMC_STAT_A_FULL (1 << 10)
+#define OMAP_MMC_STAT_CMD_CRC (1 << 8)
+#define OMAP_MMC_STAT_CMD_TOUT (1 << 7)
+#define OMAP_MMC_STAT_DATA_CRC (1 << 6)
+#define OMAP_MMC_STAT_DATA_TOUT (1 << 5)
+#define OMAP_MMC_STAT_END_BUSY (1 << 4)
+#define OMAP_MMC_STAT_END_OF_DATA (1 << 3)
+#define OMAP_MMC_STAT_CARD_BUSY (1 << 2)
+#define OMAP_MMC_STAT_END_OF_CMD (1 << 0)
+
+#define OMAP_MMC_READ(base, reg) __raw_readw((base) + OMAP_MMC_REG_##reg)
+#define OMAP_MMC_WRITE(base, reg, val) __raw_writew((val), (base) + OMAP_MMC_REG_##reg)
+
+/*
+ * Command types
+ */
+#define OMAP_MMC_CMDTYPE_BC 0
+#define OMAP_MMC_CMDTYPE_BCR 1
+#define OMAP_MMC_CMDTYPE_AC 2
+#define OMAP_MMC_CMDTYPE_ADTC 3
+
+#endif
{
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;
+ }
}
}
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
help
If you had to ask, you don't have one. Say 'N'.
+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_TOTO
tristate "NAND Flash device on TOTO board"
depends on ARCH_OMAP && MTD_NAND
help
The simulator may simulate verious NAND flash chips for the
MTD nand layer.
-
+
+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.
+
endmenu
obj-$(CONFIG_MTD_NAND_RTC_FROM4) += rtc_from4.o
obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o
obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
+obj-$(CONFIG_MTD_NAND_OMAP) += omap-nand-flash.o
+obj-$(CONFIG_MTD_NAND_OMAP_HW) += omap-hw.o
nand-objs = nand_base.o nand_bbt.o
--- /dev/null
+/*
+ * 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 void omap_nand_write_byte(struct mtd_info *mtd, u_char byte)
+{
+ nand_write_reg8(NND_ACCESS, byte);
+}
+
+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->oobblock) {
+ /* OOB area */
+ column -= mtd->oobblock;
+ 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->oobblock;
+ 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;
+
+ if (this->eccmode == NAND_ECC_HW12_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;
+ if (this->eccmode == NAND_ECC_HW12_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_config *cfg;
+ char *part_str = NULL;
+ size_t part_str_len;
+ int c;
+
+ cfg = omap_get_var_config(OMAP_TAG_FLASH_PART, &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->write_byte = omap_nand_write_byte;
+
+ this->select_chip = omap_nand_select_chip;
+ this->dev_ready = omap_nand_dev_ready;
+ this->chip_delay = 0;
+ this->eccmode = NAND_ECC_HW3_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->calculate_ecc = omap_nand_calculate_ecc;
+ this->correct_data = omap_nand_correct_data;
+ this->enable_hwecc = 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->eccmode = NAND_ECC_HW12_2048;
+ this->eccsteps = 1;
+ this->eccsize = 2048;
+ this->eccbytes = 12;
+ omap_mtd->eccsize = 2048;
+ nand_write_reg(NND_ECC_SELECT, 6);
+ }
+
+ /* We have to do bbt scanning ourselves */
+ if (this->scan_bbt (omap_mtd)) {
+ err = -ENXIO;
+ goto out_mtd;
+ }
+
+ err = add_dynamic_parts(omap_mtd);
+ if (err < 0) {
+ printk(KERN_ERR "omap-hw-nand: no partitions defined\n");
+ err = -ENODEV;
+ nand_release(omap_mtd);
+ goto out_mtd;
+ }
+ /* init completed */
+ return 0;
+out_mtd:
+ if (omap_nand_dma_ch >= 0)
+ omap_free_dma(omap_nand_dma_ch);
+ kfree(omap_mtd);
+free_clock:
+ clk_put(omap_nand_clk);
+ return err;
+}
+
+module_init(omap_nand_init);
+
+/*
+ * Clean up routine
+ */
+static void __exit omap_nand_cleanup (void)
+{
+ clk_disable(omap_nand_clk);
+ clk_put(omap_nand_clk);
+ nand_release(omap_mtd);
+ kfree(omap_mtd);
+}
+
+module_exit(omap_nand_cleanup);
+
--- /dev/null
+/*
+ * 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/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!!
+ */
+#define MASK_CLE 0x02
+#define MASK_ALE 0x04
+static void omap_nand_hwcontrol(struct mtd_info *mtd, int cmd)
+{
+ struct nand_chip *this = mtd->priv;
+ unsigned long IO_ADDR_W = (unsigned long) this->IO_ADDR_W;
+
+ switch (cmd) {
+ case NAND_CTL_SETCLE: IO_ADDR_W |= MASK_CLE; break;
+ case NAND_CTL_CLRCLE: IO_ADDR_W &= ~MASK_CLE; break;
+ case NAND_CTL_SETALE: IO_ADDR_W |= MASK_ALE; break;
+ case NAND_CTL_CLRALE: IO_ADDR_W &= ~MASK_ALE; break;
+ }
+ this->IO_ADDR_W = (void __iomem *) IO_ADDR_W;
+}
+
+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 = kmalloc(sizeof(struct omap_nand_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ memset(info, 0, sizeof(struct omap_nand_info));
+
+ 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.hwcontrol = omap_nand_hwcontrol;
+ info->nand.eccmode = 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");
+
To compile it as a module, choose M here: the module will be called
donauboe.
+config OMAP_IR
+ tristate "OMAP IrDA(SIR/MIR/FIR)"
+ depends on IRDA && (ARCH_OMAP1 || ARCH_OMAP2)
+ select GPIOEXPANDER_OMAP if (MACH_OMAP_H3 || MACH_OMAP_H4)
+ help
+ Say Y here if you want to build support for the OMAP IR.
+
config AU1000_FIR
tristate "Alchemy Au1000 SIR/FIR"
depends on MIPS_AU1000 && IRDA
obj-$(CONFIG_MCP2120_DONGLE) += mcp2120-sir.o
obj-$(CONFIG_ACT200L_DONGLE) += act200l-sir.o
obj-$(CONFIG_MA600_DONGLE) += ma600-sir.o
+obj-$(CONFIG_OMAP_IR) += omap-ir.o
+
# The SIR helper module
sir-dev-objs := sir_dev.o sir_dongle.o sir_kthread.o
--- /dev/null
+/*
+ * BRIEF MODULE DESCRIPTION
+ *
+ * Infra-red driver for the OMAP1610-H2 and OMAP1710-H3 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/config.h>
+#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 <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(si) ((si)->speed >= 4000000)
+#define IRDA_FRAME_SIZE_LIMIT 4096
+
+static int rx_state = 0; /* RX state for IOCTL */
+
+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 irda_device_setup(struct net_device *dev);
+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 *si)
+{
+ /* Configure DMA */
+ omap_set_dma_src_params(si->rx_dma_channel, 0x3, 0x0,
+ si->pdata->src_start,
+ 0, 0);
+
+ omap_enable_dma_irq(si->rx_dma_channel, 0x01);
+
+ omap_set_dma_dest_params(si->rx_dma_channel, 0x0, 0x1,
+ si->rx_buf_dma_phys,
+ 0, 0);
+
+ omap_set_dma_transfer_params(si->rx_dma_channel, 0x0,
+ IRDA_FRAME_SIZE_LIMIT, 0x1,
+ 0x0, si->pdata->rx_trigger, 0);
+
+ omap_start_dma(si->rx_dma_channel);
+}
+
+static void omap_start_tx_dma(struct omap_irda *si, int size)
+{
+ /* Configure DMA */
+ omap_set_dma_dest_params(si->tx_dma_channel, 0x03, 0x0,
+ si->pdata->dest_start, 0, 0);
+
+ omap_enable_dma_irq(si->tx_dma_channel, 0x01);
+
+ omap_set_dma_src_params(si->tx_dma_channel, 0x0, 0x1,
+ si->tx_buf_dma_phys,
+ 0, 0);
+
+ omap_set_dma_transfer_params(si->tx_dma_channel, 0x0, size, 0x1,
+ 0x0, si->pdata->tx_trigger, 0);
+
+ /* Start DMA */
+ omap_start_dma(si->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 *si = dev->priv;
+
+ printk(KERN_ERR "RX Transfer error or very big frame\n");
+
+ /* Clear interrupts */
+ uart_reg_in(UART3_IIR);
+
+ si->stats.rx_frame_errors++;
+
+ uart_reg_in(UART3_RESUME);
+
+ /* Re-init RX DMA */
+ omap_irda_start_rx_dma(si);
+}
+
+/* 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 *si = dev->priv;
+
+ /*Stop DMA controller */
+ omap_stop_dma(si->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 *si = dev->priv;
+
+
+ /* 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 (si->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);
+ si->pdata->transceiver_mode(si->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 *si)
+{
+ 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 pt_regs *hw_regs)
+{
+ struct net_device *dev = dev_id;
+ struct omap_irda *si = dev->priv;
+ 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");
+
+ si->stats.tx_packets++;
+
+ if (si->newspeed) {
+ omap_irda_set_speed(dev, si->newspeed);
+ si->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(si->rx_dma_channel);
+
+ status = uart_reg_in(UART3_SFLSR); /* Take a frame status */
+
+ if (status != 0) { /* Bad frame? */
+ si->stats.rx_frame_errors++;
+ uart_reg_in(UART3_RESUME);
+ } else {
+ /* We got a frame! */
+ skb = alloc_skb(IRDA_FRAME_SIZE_LIMIT, GFP_ATOMIC);
+
+ 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(si->rx_dma_channel);
+
+ if (cpu_is_omap16xx())
+ w -= OMAP1_DMA_CDSA_L_REG(si->rx_dma_channel);
+ if (cpu_is_omap24xx())
+ w -= OMAP2_DMA_CDSA_REG(si->rx_dma_channel);
+
+ if (!IS_FIR(si)) {
+ /* Copy DMA buffer to skb */
+ memcpy(skb_put(skb, w - 2), si->rx_buf_dma_virt, w - 2);
+ } else {
+ /* Copy DMA buffer to skb */
+ memcpy(skb_put(skb, w - 4), si->rx_buf_dma_virt, w - 4);
+ }
+
+ skb->dev = dev;
+ skb->mac.raw = skb->data;
+ skb->protocol = htons(ETH_P_IRDA);
+ si->stats.rx_packets++;
+ si->stats.rx_bytes += skb->len;
+ netif_receive_skb(skb); /* Send data to upper level */
+ }
+
+ /* Re-init RX DMA */
+ omap_irda_start_rx_dma(si);
+
+ dev->last_rx = jiffies;
+
+ return IRQ_HANDLED;
+}
+
+static int omap_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct omap_irda *si = dev->priv;
+ 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 != si->speed && speed != -1)
+ si->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 (si->newspeed) {
+ si->newspeed = 0;
+ omap_irda_set_speed(dev, speed);
+ }
+ dev_kfree_skb(skb);
+ return 0;
+ }
+
+ netif_stop_queue(dev);
+
+ /* Copy skb data to DMA buffer */
+ memcpy(si->tx_buf_dma_virt, skb->data, skb->len);
+
+ /* Copy skb data to DMA buffer */
+ si->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(si, 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 *si = dev->priv;
+ 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 (si->open)
+ ret = omap_irda_set_speed(dev,
+ rq->ifr_baudrate);
+ else {
+ printk(KERN_ERR "omap_irda_ioctl: 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 = rx_state;
+ break;
+
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static struct net_device_stats *omap_irda_stats(struct net_device *dev)
+{
+ struct omap_irda *si = dev->priv;
+ return &si->stats;
+}
+
+static int omap_irda_start(struct net_device *dev)
+{
+ struct omap_irda *si = dev->priv;
+ int err;
+
+ si->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(si->pdata->rx_channel, "IrDA Rx DMA",
+ (void *)omap_irda_rx_dma_callback,
+ dev, &(si->rx_dma_channel))) {
+ printk(KERN_ERR "Failed to request IrDA Rx DMA\n");
+ goto err_irq;
+ }
+
+ if (omap_request_dma(si->pdata->tx_channel, "IrDA Tx DMA",
+ (void *)omap_irda_tx_dma_callback,
+ dev, &(si->tx_dma_channel))) {
+ printk(KERN_ERR "Failed to request IrDA Tx DMA\n");
+ goto err_irq;
+ }
+
+ /* Allocate TX and RX buffers for DMA channels */
+ si->rx_buf_dma_virt =
+ dma_alloc_coherent(NULL, IRDA_FRAME_SIZE_LIMIT,
+ &(si->rx_buf_dma_phys),
+ GFP_KERNEL);
+
+ if (!si->rx_buf_dma_virt) {
+ printk(KERN_ERR "Unable to allocate memory for rx_buf_dma\n");
+ goto err_irq;
+ }
+
+ si->tx_buf_dma_virt =
+ dma_alloc_coherent(NULL, IRDA_FRAME_SIZE_LIMIT,
+ &(si->tx_buf_dma_phys),
+ GFP_KERNEL);
+
+ if (!si->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 (si->pdata->select_irda)
+ si->pdata->select_irda(si->dev, IR_SEL);
+
+ err = omap_irda_startup(dev);
+
+ if (err)
+ goto err_startup;
+
+ omap_irda_set_speed(dev, si->speed = 9600);
+
+ /*
+ * Open a new IrLAP layer instance.
+ */
+ si->irlap = irlap_open(dev, &si->qos, "omap_sir");
+
+ err = -ENOMEM;
+ if (!si->irlap)
+ goto err_irlap;
+
+ /* Now enable the interrupt and start the queue */
+ si->open = 1;
+
+ /* Start RX DMA */
+ omap_irda_start_rx_dma(si);
+
+ enable_irq(dev->irq);
+ netif_start_queue(dev);
+
+ return 0;
+
+err_irlap:
+ si->open = 0;
+ omap_irda_shutdown(si);
+err_startup:
+ dma_free_coherent(NULL, IRDA_FRAME_SIZE_LIMIT,
+ si->tx_buf_dma_virt, si->tx_buf_dma_phys);
+err_mem1:
+ dma_free_coherent(NULL, IRDA_FRAME_SIZE_LIMIT,
+ si->rx_buf_dma_virt, si->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 *si = dev->priv;
+
+ disable_irq(dev->irq);
+
+ netif_stop_queue(dev);
+
+ omap_free_dma(si->rx_dma_channel);
+ omap_free_dma(si->tx_dma_channel);
+
+ if (si->rx_buf_dma_virt)
+ dma_free_coherent(NULL, IRDA_FRAME_SIZE_LIMIT,
+ si->rx_buf_dma_virt, si->rx_buf_dma_phys);
+ if (si->tx_buf_dma_virt)
+ dma_free_coherent(NULL, IRDA_FRAME_SIZE_LIMIT,
+ si->tx_buf_dma_virt, si->tx_buf_dma_phys);
+
+ omap_irda_shutdown(si);
+
+ /* Stop IrLAP */
+ if (si->irlap) {
+ irlap_close(si->irlap);
+ si->irlap = NULL;
+ }
+
+ si->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 *si = dev->priv;
+ int divisor;
+ unsigned long flags;
+
+ /* Set IrDA speed */
+ if (speed <= 115200) {
+
+ local_irq_save(flags);
+
+ /* SIR mode */
+ if (si->pdata->transceiver_mode)
+ si->pdata->transceiver_mode(si->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 (si->pdata->transceiver_mode)
+ si->pdata->transceiver_mode(si->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 (si->pdata->transceiver_mode)
+ si->pdata->transceiver_mode(si->dev, IR_FIRMODE);
+
+ local_irq_restore(flags);
+ }
+
+ si->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 *si = dev->priv;
+
+ if (!dev)
+ return 0;
+
+ if (si->open) {
+ /*
+ * Stop the transmit queue
+ */
+ netif_device_detach(dev);
+ disable_irq(dev->irq);
+ omap_irda_shutdown(si);
+ }
+ 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 *si= dev->priv;
+
+ if (!dev)
+ return 0;
+
+ if (si->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 (si->newspeed) {
+ si->speed = si->newspeed;
+ si->newspeed = 0;
+ }
+
+ omap_irda_startup(dev);
+ omap_irda_set_speed(dev, si->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 *si;
+ 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;
+
+
+ si = dev->priv;
+ si->dev = &pdev->dev;
+ si->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(&si->qos);
+
+ baudrate_mask = 0;
+ if (si->pdata->transceiver_cap & IR_SIRMODE)
+ baudrate_mask |= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
+ if (si->pdata->transceiver_cap & IR_MIRMODE)
+ baudrate_mask |= IR_57600 | IR_1152000;
+ if (si->pdata->transceiver_cap & IR_FIRMODE)
+ baudrate_mask |= IR_4000000 << 8;
+
+ si->qos.baud_rate.bits &= baudrate_mask;
+ si->qos.min_turn_time.bits = 7;
+
+ irda_qos_bits_to_value(&si->qos);
+
+ /* Any better way to avoid this? No. */
+ if (machine_is_omap_h3() || machine_is_omap_h4())
+ INIT_WORK(&si->pdata->gpio_expa, NULL, 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");
+
dev->name, packet_number, status,
packet_len, packet_len);
+ if (unlikely(packet_len == 0 && !(status & RS_ERRORS))) {
+ printk(KERN_ERR "%s: bad memory timings: rxlen %u status %x\n",
+ dev->name, packet_len, status);
+ status |= RS_TOOSHORT;
+ }
back:
if (unlikely(packet_len < 6 || status & RS_ERRORS)) {
if (status & RS_TOOLONG && packet_len <= (1514 + 4 + 6)) {
#define SMC_IRQ_FLAGS (( \
machine_is_omap_h2() \
|| machine_is_omap_h3() \
+ || machine_is_omap_h4() \
|| (machine_is_omap_innovator() && !cpu_is_omap1510()) \
) ? SA_TRIGGER_FALLING : SA_TRIGGER_RISING)
*sp = SS_READY | SS_DETECT | SS_POWERON | SS_3VCARD;
cf = container_of(s, struct omap_cf_socket, socket);
- s->irq.AssignedIRQ = cf->irq;
+ s->irq.AssignedIRQ = 0;
+ s->pci_irq = cf->irq;
} else
*sp = 0;
return 0;
struct omap_cf_socket *cf = dev_get_drvdata(dev);
cf->active = 0;
- pcmcia_unregister_socket(&cf->socket);
del_timer_sync(&cf->timer);
iounmap((void __iomem *) cf->socket.io_offset);
release_mem_region(cf->phys_cf, SZ_8K);
DEBUG_INTR("end.\n");
- return IRQ_RETVAL(handled);
+ //return IRQ_RETVAL(handled);
+ return IRQ_HANDLED; /* FIXME: iir status not ready on 1510 */
}
/*
serial_outp(up, UART_EFR, efr);
}
+#ifdef CONFIG_ARCH_OMAP15XX
+ /* Workaround to enable 115200 baud on OMAP1510 internal ports */
+ if (cpu_is_omap1510() && is_omap_port((unsigned int)up->port.membase)) {
+ if (baud == 115200) {
+ quot = 1;
+ serial_out(up, UART_OMAP_OSC_12M_SEL, 1);
+ } else
+ serial_out(up, UART_OMAP_OSC_12M_SEL, 0);
+ }
+#endif
+
if (up->capabilities & UART_NATSEMI) {
/* Switch to bank 2 not bank 1, to avoid resetting EXCR2 */
serial_outp(up, UART_LCR, 0xe0);
/* emulated UARTs (Lucent Venus 167x) need two steps */
serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
}
+
+ /* Note that we need to set ECB to access write water mark
+ * bits. First allow FCR tx fifo write, then set fcr with
+ * possible TX fifo settings. */
+ if (uart_config[up->port.type].flags & UART_CAP_EFR) {
+ serial_outp(up, UART_LCR, 0xbf); /* Access EFR */
+ serial_outp(up, UART_EFR, UART_EFR_ECB);
+ serial_outp(up, UART_LCR, 0x0); /* Access FCR */
+ serial_outp(up, UART_FCR, fcr);
+ serial_outp(up, UART_LCR, 0xbf); /* Access EFR */
+ serial_outp(up, UART_EFR, 0);
+ serial_outp(up, UART_LCR, cval); /* Access FCR */
+ } else
serial_outp(up, UART_FCR, fcr); /* set fcr */
}
serial8250_set_mctrl(&up->port, up->port.mctrl);
unsigned int size = 8 << up->port.regshift;
int ret = 0;
+#ifdef CONFIG_ARCH_OMAP
+ if (is_omap_port((unsigned int)up->port.membase))
+ size = 0x16 << up->port.regshift;
+#endif
+
switch (up->port.iotype) {
case UPIO_MEM:
if (!up->port.mapbase)
inexpensive battery powered microcontroller evaluation board.
This same cable can be used to flash new firmware.
+config SPI_BUTTERFLY
+ tristate "Parallel port adapter for AVR Butterfly (DEVELOPMENT)"
+ depends on SPI_MASTER && PARPORT && EXPERIMENTAL
+ select SPI_BITBANG
+ help
+ This uses a custom parallel port cable to connect to an AVR
+ Butterfly <http://www.atmel.com/products/avr/butterfly>, an
+ inexpensive battery powered microcontroller evaluation board.
+ This same cable can be used to flash new firmware.
+
+config SPI_OMAP_UWIRE
+ tristate "OMAP MicroWire"
+ depends on SPI_MASTER && ARCH_OMAP
+ select SPI_BITBANG
+ help
+ This hooks up to the MicroWire controller on OMAP chips.
+
+config SPI_OMAP24XX
+ bool "McSPI driver for OMAP24xx"
+ depends on SPI_MASTER && ARCH_OMAP24XX
+ help
+ SPI master controller for OMAP24xx McSPI modules.
+
#
# Add new SPI master controllers in alphabetical order above this line
#
# SPI master controller drivers (bus)
obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o
obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o
+obj-$(CONFIG_SPI_OMAP24XX) += omap2_mcspi.o
+obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o
# ... add above this line ...
# SPI protocol drivers (device/link on bus)
--- /dev/null
+/*
+ * OMAP2 McSPI controller driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation
+ * Author: Samuel Ortiz <samuel.ortiz@nokia.com> and
+ * Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+
+#include <linux/spi/spi.h>
+
+#include <asm/io.h>
+#include <asm/arch/mcspi.h>
+
+#define OMAP2_MCSPI_MAX_FREQ 48000000
+
+#define OMAP2_MCSPI_REVISION 0x00
+#define OMAP2_MCSPI_SYSCONFIG 0x10
+#define OMAP2_MCSPI_SYSSTATUS 0x14
+#define OMAP2_MCSPI_IRQSTATUS 0x18
+#define OMAP2_MCSPI_IRQENABLE 0x1c
+#define OMAP2_MCSPI_WAKEUPENABLE 0x20
+#define OMAP2_MCSPI_SYST 0x24
+#define OMAP2_MCSPI_MODULCTRL 0x28
+#define OMAP2_MCSPI_CHCONF0 0x2c
+#define OMAP2_MCSPI_CHSTAT0 0x30
+#define OMAP2_MCSPI_CHCTRL0 0x34
+#define OMAP2_MCSPI_TX0 0x38
+#define OMAP2_MCSPI_RX0 0x3c
+
+#define OMAP2_MCSPI_SYSCONFIG_SOFTRESET (1 << 1)
+
+#define OMAP2_MCSPI_SYSSTATUS_RESETDONE (1 << 0)
+
+#define OMAP2_MCSPI_MODULCTRL_SINGLE (1 << 0)
+#define OMAP2_MCSPI_MODULCTRL_MS (1 << 2)
+#define OMAP2_MCSPI_MODULCTRL_STEST (1 << 3)
+
+#define OMAP2_MCSPI_CHCONF_PHA (1 << 0)
+#define OMAP2_MCSPI_CHCONF_POL (1 << 1)
+#define OMAP2_MCSPI_CHCONF_CLKD_MASK (0x0f << 2)
+#define OMAP2_MCSPI_CHCONF_EPOL (1 << 6)
+#define OMAP2_MCSPI_CHCONF_WL_MASK (0x1f << 7)
+#define OMAP2_MCSPI_CHCONF_TRM_RX_ONLY (0x01 << 12)
+#define OMAP2_MCSPI_CHCONF_TRM_TX_ONLY (0x02 << 12)
+#define OMAP2_MCSPI_CHCONF_TRM_MASK (0x03 << 12)
+#define OMAP2_MCSPI_CHCONF_DPE0 (1 << 16)
+#define OMAP2_MCSPI_CHCONF_DPE1 (1 << 17)
+#define OMAP2_MCSPI_CHCONF_IS (1 << 18)
+#define OMAP2_MCSPI_CHCONF_TURBO (1 << 19)
+#define OMAP2_MCSPI_CHCONF_FORCE (1 << 20)
+
+
+#define OMAP2_MCSPI_CHSTAT_RXS (1 << 0)
+#define OMAP2_MCSPI_CHSTAT_TXS (1 << 1)
+#define OMAP2_MCSPI_CHSTAT_EOT (1 << 2)
+
+#define OMAP2_MCSPI_CHCTRL_EN (1 << 0)
+
+struct omap2_mcspi {
+ struct tasklet_struct tasklet;
+ spinlock_t lock;
+ struct list_head msg_queue;
+ struct spi_master *master;
+};
+
+struct omap2_mcspi_cs {
+ u8 transmit_mode;
+};
+
+#define MOD_REG_BIT(val, mask, set) do { \
+ if (set) \
+ val |= mask; \
+ else \
+ val &= ~mask; \
+} while(0)
+
+
+#define MASTER_PDATA(master) (struct omap2_mcspi_platform_config *)((master)->cdev.dev->platform_data)
+
+static inline void mcspi_write_reg(const struct spi_master *master,
+ int idx, u32 val)
+{
+ struct omap2_mcspi_platform_config *pdata = MASTER_PDATA(master);
+
+ __raw_writel(val, pdata->base + idx);
+}
+
+static inline u32 mcspi_read_reg(const struct spi_master *master,
+ int idx)
+{
+ struct omap2_mcspi_platform_config *pdata = MASTER_PDATA(master);
+
+ return __raw_readl(pdata->base + idx);
+}
+
+static inline void mcspi_write_cs_reg(const struct spi_device *spi,
+ int idx, u32 val)
+{
+ struct omap2_mcspi_platform_config *pdata = MASTER_PDATA(spi->master);
+
+ __raw_writel(val, pdata->base + spi->chip_select * 0x14 + idx);
+}
+
+static inline u32 mcspi_read_cs_reg(const struct spi_device *spi,
+ int idx)
+{
+ struct omap2_mcspi_platform_config *pdata = MASTER_PDATA(spi->master);
+
+ return __raw_readl(pdata->base + spi->chip_select * 0x14 + idx);
+}
+
+static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable)
+{
+ u32 l;
+
+ l = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0);
+ MOD_REG_BIT(l, OMAP2_MCSPI_CHCTRL_EN, enable);
+ mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, l);
+}
+
+static void omap2_mcspi_force_cs(struct spi_device *spi, int cs_active)
+{
+ u32 l;
+
+ l = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
+ MOD_REG_BIT(l, OMAP2_MCSPI_CHCONF_FORCE, cs_active);
+ mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, l);
+}
+
+static void omap2_mcspi_set_master_mode(struct spi_device *spi, int single_channel)
+{
+ u32 l;
+
+ /* Need reset when switching from slave mode */
+ l = mcspi_read_reg(spi->master, OMAP2_MCSPI_MODULCTRL);
+ MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_STEST, 0);
+ MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_MS, 0);
+ MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_SINGLE, single_channel);
+ mcspi_write_reg(spi->master, OMAP2_MCSPI_MODULCTRL, l);
+}
+
+static void omap2_mcspi_txrx(struct spi_device *spi, struct spi_transfer *xfer)
+{
+ unsigned int count, c;
+ u32 l;
+ unsigned long base, tx_reg, rx_reg, chstat_reg;
+
+ count = xfer->len;
+ c = count;
+
+ l = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
+ l &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
+ if (xfer->tx_buf == NULL)
+ l |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY;
+ else if (xfer->rx_buf == NULL)
+ l |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY;
+ mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, l);
+
+ omap2_mcspi_set_enable(spi, 1);
+
+ /* We store the pre-calculated register addresses on stack to speed
+ * up the transfer loop. */
+ base = (MASTER_PDATA(spi->master))->base + spi->chip_select * 0x14;
+ tx_reg = base + OMAP2_MCSPI_TX0;
+ rx_reg = base + OMAP2_MCSPI_RX0;
+ chstat_reg = base + OMAP2_MCSPI_CHSTAT0;
+
+ /* RX_ONLY mode needs dummy data in TX reg */
+ if (xfer->tx_buf == NULL)
+ __raw_writel(0, tx_reg);
+
+ if (spi->bits_per_word <= 8) {
+ u8 *rx;
+ const u8 *tx;
+
+ rx = xfer->rx_buf;
+ tx = xfer->tx_buf;
+
+ while (c--) {
+ if (tx != NULL) {
+ while (!(__raw_readl(chstat_reg) & OMAP2_MCSPI_CHSTAT_TXS));
+ __raw_writel(*tx, tx_reg);
+ }
+ if (rx != NULL) {
+ while (!(__raw_readl(chstat_reg) & OMAP2_MCSPI_CHSTAT_RXS));
+ if (c == 0 && tx == NULL)
+ omap2_mcspi_set_enable(spi, 0);
+ *rx++ = __raw_readl(rx_reg);
+ }
+ }
+ } else if (spi->bits_per_word <= 16) {
+ u16 *rx;
+ const u16 *tx;
+
+ rx = xfer->rx_buf;
+ tx = xfer->tx_buf;
+ c >>= 1;
+ while (c--) {
+ if (tx != NULL) {
+ while (!(__raw_readl(chstat_reg) & OMAP2_MCSPI_CHSTAT_TXS));
+ __raw_writel(*tx++, tx_reg);
+ }
+ if (rx != NULL) {
+ while (!(__raw_readl(chstat_reg) & OMAP2_MCSPI_CHSTAT_RXS));
+ if (c == 0 && tx == NULL)
+ omap2_mcspi_set_enable(spi, 0);
+ *rx++ = __raw_readl(rx_reg);
+ }
+ }
+ } else if (spi->bits_per_word <= 32) {
+ u32 *rx;
+ const u32 *tx;
+
+ rx = xfer->rx_buf;
+ tx = xfer->tx_buf;
+ c >>= 2;
+ while (c--) {
+ if (tx != NULL) {
+ while (!(__raw_readl(chstat_reg) & OMAP2_MCSPI_CHSTAT_TXS));
+ __raw_writel(*tx++, tx_reg);
+ }
+ if (rx != NULL) {
+ while (!(__raw_readl(chstat_reg) & OMAP2_MCSPI_CHSTAT_RXS));
+ if (c == 0 && tx == NULL)
+ omap2_mcspi_set_enable(spi, 0);
+ *rx++ = __raw_readl(rx_reg);
+ }
+ }
+ }
+
+ if (xfer->tx_buf != NULL) {
+ while (!(__raw_readl(chstat_reg) & OMAP2_MCSPI_CHSTAT_TXS));
+ while (!(__raw_readl(chstat_reg) & OMAP2_MCSPI_CHSTAT_EOT));
+ omap2_mcspi_set_enable(spi, 0);
+ }
+}
+
+static int omap2_mcspi_setup(struct spi_device *spi)
+{
+ struct omap2_mcspi_cs *cs = spi->controller_state;
+ struct omap2_mcspi_device_config *conf;
+ u32 l = 0, div = 0;
+ u8 word_len = spi->bits_per_word;
+
+ if (!word_len)
+ return 0;
+
+ if (!cs) {
+ cs = kzalloc(sizeof *cs, SLAB_KERNEL);
+ if (!cs)
+ return -ENOMEM;
+ spi->controller_state = cs;
+ }
+
+ if (spi->bits_per_word > 32)
+ return -EINVAL;
+
+ conf = (struct omap2_mcspi_device_config *) spi->controller_data;
+
+ if (conf->single_channel == 1)
+ omap2_mcspi_set_master_mode(spi, 1);
+ else
+ omap2_mcspi_set_master_mode(spi, 0);
+
+ if (spi->max_speed_hz) {
+ while (div <= 15 && (OMAP2_MCSPI_MAX_FREQ / (1 << div)) > spi->max_speed_hz)
+ div++;
+ } else
+ div = 15;
+
+ if (spi->chip_select > 3 ||
+ word_len < 4 || word_len > 32 ||
+ div > 15) {
+ dev_err(&spi->dev, "Invalid McSPI channel setting\n");
+ return -EINVAL;
+ }
+
+ l = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
+ l &= ~OMAP2_MCSPI_CHCONF_IS;
+ l &= ~OMAP2_MCSPI_CHCONF_DPE1;
+ l |= OMAP2_MCSPI_CHCONF_DPE0;
+ l &= ~OMAP2_MCSPI_CHCONF_WL_MASK;
+ l |= (word_len - 1) << 7;
+ if (!(spi->mode & SPI_CS_HIGH))
+ l |= OMAP2_MCSPI_CHCONF_EPOL;
+ l &= ~OMAP2_MCSPI_CHCONF_CLKD_MASK;
+ l |= div << 2;
+ if (spi->mode & SPI_CPOL)
+ l |= OMAP2_MCSPI_CHCONF_POL;
+ if (spi->mode & SPI_CPHA)
+ l |= OMAP2_MCSPI_CHCONF_PHA;
+ mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, l);
+
+ return 0;
+}
+
+static void omap2_mcspi_cleanup(const struct spi_device *spi)
+{
+ if (spi->controller_state != NULL)
+ kfree(spi->controller_state);
+}
+
+
+static void omap2_mcspi_work(unsigned long arg)
+{
+ struct omap2_mcspi *mcspi = (struct omap2_mcspi *) arg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mcspi->lock, flags);
+ while (!list_empty(&mcspi->msg_queue)) {
+ struct spi_message *m;
+ struct spi_device *spi;
+ struct spi_transfer *t = NULL;
+ int cs_active;
+ struct omap2_mcspi_device_config *conf;
+ struct omap2_mcspi_cs *cs;
+ int status = 0;
+
+ m = container_of(mcspi->msg_queue.next, struct spi_message,
+ queue);
+
+ list_del_init(&m->queue);
+ spin_unlock_irqrestore(&mcspi->lock, flags);
+
+ spi = m->spi;
+ conf = (struct omap2_mcspi_device_config *) spi->controller_data;
+ cs = (struct omap2_mcspi_cs *) spi->controller_state;
+
+ omap2_mcspi_force_cs(spi, 1);
+ cs_active = 1;
+
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
+ status = -EINVAL;
+ break;
+ }
+
+ if (!cs_active) {
+ omap2_mcspi_force_cs(spi, 1);
+ cs_active = 1;
+ }
+
+ omap2_mcspi_txrx(spi, t);
+
+ if (t->cs_change) {
+ omap2_mcspi_force_cs(spi, 0);
+ cs_active = 0;
+ }
+ }
+
+ if (cs_active)
+ omap2_mcspi_force_cs(spi, 0);
+
+ m->status = status;
+ m->complete(m->context);
+
+ spin_lock_irqsave(&mcspi->lock, flags);
+ }
+ spin_unlock_irqrestore(&mcspi->lock, flags);
+}
+
+static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m)
+{
+ struct omap2_mcspi *mcspi;
+ unsigned long flags;
+
+ m->actual_length = 0;
+ m->status = 0;
+
+ mcspi = class_get_devdata(&spi->master->cdev);
+
+ spin_lock_irqsave(&mcspi->lock, flags);
+ list_add_tail(&m->queue, &mcspi->msg_queue);
+ spin_unlock_irqrestore(&mcspi->lock, flags);
+
+ tasklet_hi_schedule(&mcspi->tasklet);
+
+ return 0;
+}
+
+static int __devinit omap2_mcspi_reset(struct spi_master *master)
+{
+#if 0
+ mcspi_write_reg(master, OMAP2_MCSPI_SYSCONFIG,
+ OMAP2_MCSPI_SYSCONFIG_SOFTRESET);
+ while (!(mcspi_read_reg(master, OMAP2_MCSPI_SYSSTATUS) & OMAP2_MCSPI_SYSSTATUS_RESETDONE));
+#else
+ return 0;
+#endif
+}
+
+static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct omap2_mcspi_platform_config *pdata = pdev->dev.platform_data;
+ struct omap2_mcspi *mcspi;
+ int status = 0;
+
+ if (!pdata)
+ return -EINVAL;
+
+ master = spi_alloc_master(&pdev->dev, sizeof *mcspi);
+ if (!master) {
+ dev_err(&pdev->dev, "master allocation failed\n");
+ return -ENOMEM;
+ }
+
+ if (pdev->id != -1)
+ master->bus_num = pdev->id;
+
+ master->setup = omap2_mcspi_setup;
+ master->transfer = omap2_mcspi_transfer;
+ master->cleanup = omap2_mcspi_cleanup;
+ master->num_chipselect = pdata->num_cs;
+
+ if (class_device_get(&master->cdev) == NULL) {
+ dev_err(&pdev->dev, "no master->cdev");
+ status = -ENOMEM;
+ goto err0;
+ }
+
+ dev_set_drvdata(&pdev->dev, master);
+
+ mcspi = class_get_devdata(&master->cdev);
+ mcspi->master = master;
+
+ tasklet_init(&mcspi->tasklet, omap2_mcspi_work, (unsigned long) mcspi);
+
+ spin_lock_init(&mcspi->lock);
+ INIT_LIST_HEAD(&mcspi->msg_queue);
+
+ if (omap2_mcspi_reset(master) < 0)
+ goto err1;
+
+ status = spi_register_master(master);
+ if (status < 0)
+ goto err1;
+
+ return status;
+
+ err1:
+ class_device_put(&master->cdev);
+ err0:
+ return status;
+}
+
+static int __devexit omap2_mcspi_remove(struct platform_device *pdev)
+{
+ struct spi_master *master;
+
+ master = dev_get_drvdata(&pdev->dev);
+
+ spi_unregister_master(master);
+
+ return 0;
+}
+
+struct platform_driver omap2_mcspi_driver = {
+ .driver = {
+ .name = "omap2_mcspi",
+ .owner = THIS_MODULE,
+ },
+ .probe = omap2_mcspi_probe,
+ .remove = __devexit_p(omap2_mcspi_remove),
+};
+EXPORT_SYMBOL_GPL(omap2_mcspi_driver);
+
+
+static int __init omap2_mcspi_init(void)
+{
+ printk(KERN_INFO "OMAP24xx McSPI driver initializing\n");
+ return platform_driver_register(&omap2_mcspi_driver);
+}
+subsys_initcall(omap2_mcspi_init);
+
+static void __exit omap2_mcspi_exit(void)
+{
+ platform_driver_unregister(&omap2_mcspi_driver);
+}
+module_exit(omap2_mcspi_exit);
+
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * omap_uwire.c -- MicroWire interface driver for OMAP
+ *
+ * Copyright 2003 MontaVista Software Inc. <source@mvista.com>
+ *
+ * Ported to 2.6 OMAP uwire interface.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * Generalization patches by Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * Copyright (C) 2005 David Brownell (ported to 2.6 SPI interface)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/mux.h>
+#include <asm/arch/omap730.h> /* OMAP730_IO_CONF registers */
+
+
+/* FIXME address is now a platform device resource,
+ * and irqs should show there too...
+ */
+#define UWIRE_BASE_PHYS 0xFFFB3000
+#define UWIRE_BASE ((void *__iomem)IO_ADDRESS(UWIRE_BASE_PHYS))
+
+/* uWire Registers: */
+#define UWIRE_IO_SIZE 0x20
+#define UWIRE_TDR 0x00
+#define UWIRE_RDR 0x00
+#define UWIRE_CSR 0x01
+#define UWIRE_SR1 0x02
+#define UWIRE_SR2 0x03
+#define UWIRE_SR3 0x04
+#define UWIRE_SR4 0x05
+#define UWIRE_SR5 0x06
+
+/* CSR bits */
+#define RDRB (1 << 15)
+#define CSRB (1 << 14)
+#define START (1 << 13)
+#define CS_CMD (1 << 12)
+
+/* SR1 or SR2 bits */
+#define UWIRE_READ_FALLING_EDGE 0x0000
+#define UWIRE_READ_RISING_EDGE 0x0001
+#define UWIRE_WRITE_FALLING_EDGE 0x0000
+#define UWIRE_WRITE_RISING_EDGE 0x0002
+#define UWIRE_CS_ACTIVE_LOW 0x0000
+#define UWIRE_CS_ACTIVE_HIGH 0x0004
+#define UWIRE_FREQ_DIV_2 0x0000
+#define UWIRE_FREQ_DIV_4 0x0008
+#define UWIRE_FREQ_DIV_8 0x0010
+#define UWIRE_CHK_READY 0x0020
+#define UWIRE_CLK_INVERTED 0x0040
+
+
+struct uwire_spi {
+ struct spi_bitbang bitbang;
+ struct clk *ck;
+};
+
+/* REVISIT compile time constant for idx_shift? */
+static unsigned int uwire_idx_shift;
+
+static inline void uwire_write_reg(int idx, u16 val)
+{
+ __raw_writew(val, UWIRE_BASE + (idx << uwire_idx_shift));
+}
+
+static inline u16 uwire_read_reg(int idx)
+{
+ return __raw_readw(UWIRE_BASE + (idx << uwire_idx_shift));
+}
+
+static inline void omap_uwire_configure_mode(u8 cs, unsigned long flags)
+{
+ u16 w, val = 0;
+ int shift, reg;
+
+ if (flags & UWIRE_CLK_INVERTED)
+ val ^= 0x03;
+ val = flags & 0x3f;
+ if (cs & 1)
+ shift = 6;
+ else
+ shift = 0;
+ if (cs <= 1)
+ reg = UWIRE_SR1;
+ else
+ reg = UWIRE_SR2;
+
+ w = uwire_read_reg(reg);
+ w &= ~(0x3f << shift);
+ w |= val << shift;
+ uwire_write_reg(reg, w);
+}
+
+static int wait_uwire_csr_flag(u16 mask, u16 val, int might_not_catch)
+{
+ u16 w;
+ int c = 0;
+ unsigned long max_jiffies = jiffies + HZ;
+
+ for (;;) {
+ w = uwire_read_reg(UWIRE_CSR);
+ if ((w & mask) == val)
+ break;
+ if (time_after(jiffies, max_jiffies)) {
+ printk(KERN_ERR "%s: timeout. reg=%#06x "
+ "mask=%#06x val=%#06x\n",
+ __FUNCTION__, w, mask, val);
+ return -1;
+ }
+ c++;
+ if (might_not_catch && c > 64)
+ break;
+ }
+ return 0;
+}
+
+static void uwire_chipselect(struct spi_device *spi, int value)
+{
+ u16 w;
+ int old_cs;
+
+ BUG_ON(wait_uwire_csr_flag(CSRB, 0, 0));
+
+ w = uwire_read_reg(UWIRE_CSR);
+ old_cs = (w >> 10) & 0x03;
+ if (value == BITBANG_CS_INACTIVE || old_cs != spi->chip_select) {
+ /* Deselect this CS, or the previous CS */
+ w &= ~CS_CMD;
+ uwire_write_reg(UWIRE_CSR, w);
+ }
+ /* activate specfied chipselect */
+ if (value == BITBANG_CS_ACTIVE) {
+ /* invert clock? */
+ if (spi->mode & SPI_CPOL)
+ uwire_write_reg(UWIRE_SR4, 1);
+ else
+ uwire_write_reg(UWIRE_SR4, 0);
+
+ w = spi->chip_select << 10;
+ w |= CS_CMD;
+ uwire_write_reg(UWIRE_CSR, w);
+ }
+}
+
+static int uwire_txrx(struct spi_device *spi, struct spi_transfer *t)
+{
+ unsigned len = t->len;
+ unsigned bits = spi->bits_per_word;
+ unsigned bytes;
+ u16 val, w;
+ int status = 0;;
+
+ if (!t->tx_buf && !t->rx_buf)
+ return 0;
+
+ /* Microwire doesn't read and write concurrently */
+ if (t->tx_buf && t->rx_buf)
+ return -EPERM;
+
+ w = spi->chip_select << 10;
+ w |= CS_CMD;
+
+ if (t->tx_buf) {
+ const u8 *buf = t->tx_buf;
+
+ /* NOTE: DMA could be used for TX transfers */
+
+ /* write one or two bytes at a time */
+ while (len >= 1) {
+ /* tx is msb-aligned */
+ val = *buf++;
+ if (len > 1 && (!bits || bits > 8)) {
+ if (!bits)
+ bits = 16;
+ bytes = 2;
+ val |= *buf++ << 8;
+ } else {
+ if (!bits || bits > 8)
+ bits = 8;
+ bytes = 1;
+ }
+ val <<= 16 - bits;
+
+#ifdef VERBOSE
+ pr_debug("%s: write-%d =%04x\n",
+ spi->dev.bus_id, bits, val);
+#endif
+ uwire_write_reg(UWIRE_TDR, val);
+
+ /* start write */
+ val = START | w | (bits << 5);
+ if (wait_uwire_csr_flag(CSRB, 0, 0))
+ goto eio;
+
+ uwire_write_reg(UWIRE_CSR, val);
+ len -= bytes;
+
+ /* Wait till write actually starts.
+ * This is needed with MPU clock 60+ MHz.
+ * REVISIT: we may not have time to catch it...
+ */
+ if (wait_uwire_csr_flag(CSRB, CSRB, 1))
+ goto eio;
+
+ status += bytes;
+ }
+
+ /* REVISIT: save this for later to get more i/o overlap */
+ if (wait_uwire_csr_flag(CSRB, 0, 0))
+ goto eio;
+
+ } else if (t->rx_buf) {
+ u8 *buf = t->rx_buf;
+
+ /* read one or two bytes at a time */
+ while (len) {
+ if (len > 1 && (!bits || bits > 8)) {
+ if (!bits)
+ bits = 16;
+ bytes = 2;
+ } else {
+ if (!bits || bits > 8)
+ bits = 8;
+ bytes = 1;
+ }
+
+ /* start read */
+ val = START | w | (bits << 0);
+ uwire_write_reg(UWIRE_CSR, val);
+ len -= bytes;
+
+ /* Wait till read actually starts */
+ (void) wait_uwire_csr_flag(CSRB, CSRB, 1);
+
+ if (wait_uwire_csr_flag(RDRB | CSRB,
+ RDRB, 0))
+ goto eio;
+
+ /* rx is lsb-aligned */
+ val = uwire_read_reg(UWIRE_RDR);
+ val &= (1 << bits) - 1;
+ *buf++ = (u8) val;
+ if (bytes == 2)
+ *buf++ = val >> 8;
+ status += bytes;
+#ifdef VERBOSE
+ pr_debug("%s: read-%d =%04x\n",
+ spi->dev.bus_id, bits, val);
+#endif
+
+ }
+ }
+ return status;
+eio:
+ return -EIO;
+}
+
+static int uwire_setup(struct spi_device *spi)
+{
+ struct uwire_spi *uwire;
+ unsigned flags = 0;
+ unsigned long rate;
+ int div1_idx;
+ int div1;
+ int div2;
+ u16 w;
+ int status;
+
+ uwire = spi_master_get_devdata(spi->master);
+
+ if (spi->chip_select > 3) {
+ pr_debug("%s: cs%d?\n", spi->dev.bus_id, spi->chip_select);
+ status = -ENODEV;
+ goto done;
+ }
+
+ if (spi->bits_per_word > 16) {
+ pr_debug("%s: wordsize %d?\n", spi->dev.bus_id,
+ spi->bits_per_word);
+ status = -ENODEV;
+ goto done;
+ }
+
+ /* mode 0..3, clock inverted separately;
+ * standard nCS signaling;
+ * don't treat DI=high as "not ready"
+ */
+ if (spi->mode & SPI_CS_HIGH)
+ flags |= UWIRE_CS_ACTIVE_HIGH;
+
+ if (spi->mode & SPI_CPOL)
+ flags |= UWIRE_CLK_INVERTED;
+
+ switch (spi->mode & (SPI_CPOL | SPI_CPHA)) {
+ case SPI_MODE_0:
+ case SPI_MODE_3:
+ flags |= UWIRE_WRITE_FALLING_EDGE | UWIRE_READ_FALLING_EDGE;
+ break;
+ case SPI_MODE_1:
+ case SPI_MODE_2:
+ flags |= UWIRE_WRITE_FALLING_EDGE | UWIRE_READ_RISING_EDGE;
+ break;
+ }
+
+ /* assume it's already enabled */
+ rate = clk_get_rate(uwire->ck);
+
+ /* F_INT = mpu_per_clk / DIV1 */
+ for (div1_idx = 0; div1_idx < 4; div1_idx++) {
+ switch (div1_idx) {
+ case 0:
+ div1 = 2;
+ break;
+ case 1:
+ div1 = 4;
+ break;
+ case 2:
+ div1 = 7;
+ break;
+ default:
+ case 3:
+ div1 = 10;
+ break;
+ }
+ div2 = (rate / div1 + spi->max_speed_hz - 1) /
+ spi->max_speed_hz;
+ if (div2 <= 8)
+ break;
+ }
+ if (div1_idx == 4) {
+ pr_debug("%s: lowest clock %ld, need %d\n",
+ spi->dev.bus_id, rate / 10 / 8, spi->max_speed_hz);
+ status = -EDOM;
+ goto done;
+ }
+
+ w = uwire_read_reg(UWIRE_SR3);
+ w &= ~(0x03 << 1);
+ w |= div1_idx << 1;
+ uwire_write_reg(UWIRE_SR3, w);
+
+ rate /= div1;
+
+ switch (div2) {
+ case 0:
+ case 1:
+ case 2:
+ flags |= UWIRE_FREQ_DIV_2;
+ rate /= 2;
+ break;
+ case 3:
+ case 4:
+ flags |= UWIRE_FREQ_DIV_4;
+ rate /= 4;
+ break;
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ flags |= UWIRE_FREQ_DIV_8;
+ rate /= 8;
+ break;
+ }
+ omap_uwire_configure_mode(spi->chip_select, flags);
+ pr_debug("%s: uwire flags %02x, armper %lu KHz, SCK %lu KHz\n",
+ __FUNCTION__, flags,
+ clk_get_rate(uwire->ck) / 1000,
+ rate / 1000);
+ status = 0;
+done:
+ return status;
+}
+
+static void uwire_off(struct uwire_spi *uwire)
+{
+ uwire_write_reg(UWIRE_SR3, 0);
+ clk_disable(uwire->ck);
+ clk_put(uwire->ck);
+ spi_master_put(uwire->bitbang.master);
+}
+
+static int uwire_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct uwire_spi *uwire;
+ int status;
+
+ master = spi_alloc_master(&pdev->dev, sizeof *uwire);
+ if (!master)
+ return -ENODEV;
+
+ uwire = spi_master_get_devdata(master);
+ dev_set_drvdata(&pdev->dev, uwire);
+
+ uwire->ck = clk_get(&pdev->dev, "armper_ck");
+ if (!uwire->ck || IS_ERR(uwire->ck)) {
+ dev_dbg(&pdev->dev, "no mpu_per_clk ?\n");
+ spi_master_put(master);
+ return -ENODEV;
+ }
+ clk_enable(uwire->ck);
+
+ if (cpu_is_omap730())
+ uwire_idx_shift = 1;
+ else
+ uwire_idx_shift = 2;
+
+ uwire_write_reg(UWIRE_SR3, 1);
+
+ master->bus_num = 2; /* "official" */
+ master->num_chipselect = 4;
+ master->setup = uwire_setup;
+
+ uwire->bitbang.master = master;
+ uwire->bitbang.chipselect = uwire_chipselect;
+ uwire->bitbang.txrx_bufs = uwire_txrx;
+
+ status = spi_bitbang_start(&uwire->bitbang);
+ if (status < 0)
+ uwire_off(uwire);
+ return status;
+}
+
+static int uwire_remove(struct platform_device *pdev)
+{
+ struct uwire_spi *uwire = dev_get_drvdata(&pdev->dev);
+ int status;
+
+ // FIXME remove all child devices, somewhere ...
+
+ status = spi_bitbang_stop(&uwire->bitbang);
+ uwire_off(uwire);
+ return status;
+}
+
+static struct platform_driver uwire_driver = {
+ .driver = {
+ .name = "omap_uwire",
+ .bus = &platform_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = uwire_probe,
+ .remove = uwire_remove,
+ // suspend ... unuse ck
+ // resume ... use ck
+};
+
+static int __init omap_uwire_init(void)
+{
+ /* FIXME move these into the relevant board init code. also, include
+ * H3 support; it uses tsc2101 like H2 (on a different chipselect).
+ */
+
+ if (machine_is_omap_h2()) {
+ /* defaults: W21 SDO, U18 SDI, V19 SCL */
+ omap_cfg_reg(N14_1610_UWIRE_CS0);
+ omap_cfg_reg(N15_1610_UWIRE_CS1);
+ }
+ if (machine_is_omap_perseus2()) {
+ /* configure pins: MPU_UW_nSCS1, MPU_UW_SDO, MPU_UW_SCLK */
+ int val = omap_readl(OMAP730_IO_CONF_9) & ~0x00EEE000;
+ omap_writel(val | 0x00AAA000, OMAP730_IO_CONF_9);
+ }
+
+ return platform_driver_register(&uwire_driver);
+}
+
+static void __exit omap_uwire_exit(void)
+{
+ platform_driver_unregister(&uwire_driver);
+}
+
+subsys_initcall(omap_uwire_init);
+module_exit(omap_uwire_exit);
+
+MODULE_LICENSE("GPL");
--- /dev/null
+menu "Synchronous Serial Interfaces (SSI)"
+
+config OMAP_UWIRE
+ depends on ARCH_OMAP1
+ tristate "MicroWire support on OMAP"
+ ---help---
+ Say Y here if you want support for the MicroWire interface
+ on an OMAP processor.
+
+config OMAP_TSC2101
+ depends on ARCH_OMAP1 || ARCH_OMAP24XX
+ tristate "TSC2101 codec support for Touchscreen and audio"
+ select OMAP_UWIRE if MACH_OMAP_H3 || MACH_OMAP_H2
+ select GPIOEXPANDER_OMAP if MACH_OMAP_H3
+ ---help---
+ Say Y here if you want support for the TSC2101 codec. It is
+ needed for touchscreen and audio on OMAP1610 and 1710.
+endmenu
--- /dev/null
+#
+# Makefile for the SSI drivers
+#
+
+obj-$(CONFIG_OMAP_UWIRE) += omap-uwire.o
+obj-$(CONFIG_OMAP_TSC2101) += omap-tsc2101.o
--- /dev/null
+/*
+ * linux/drivers/ssi/omap-tsc2101.c
+ *
+ * TSC2101 codec interface driver for the OMAP platform
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ * 2004/11/07 Nishanth Menon - Modified for common hooks for Audio and Touchscreen
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+
+#include <asm/arch/mux.h>
+#include <asm/arch/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/hardware/tsc2101.h>
+#include <asm/arch/gpioexpander.h>
+
+#include "omap-tsc2101.h"
+
+#if CONFIG_ARCH_OMAP16XX
+#include <../drivers/ssi/omap-uwire.h>
+#else
+#error "Unsupported configuration"
+#endif
+
+#define SPIO 1
+
+static int count;
+static spinlock_t tsc2101_lock = SPIN_LOCK_UNLOCKED;
+static struct clk * tsc2101_mclk_ck;
+
+static int omap_tsc2101_configure(void);
+
+/* FIXME: add driver model usage to powerdown the tsc2101 on suspend */
+/* Clock -Hard coding for the time being */
+#define CLK_SOFT_REQ_REG_BASE (0xFFFE0800+0x34)
+#define SOFT_COM_MCK0_REQ_MASK (0x1<<6)
+
+int omap_tsc2101_enable(void)
+{
+ int ret = 0;
+
+ spin_lock(&tsc2101_lock);
+ if (count++ == 0) {
+ int ret = 0;
+ /* set the Mux to provide MCLK to TSC2101 */
+ if (machine_is_omap_h3()) {
+ ret = omap_cfg_reg(V5_1710_MCLK_ON);
+ } else {
+ if (machine_is_omap_h2()) {
+ ret = omap_cfg_reg(R10_1610_MCLK_ON);
+ }
+ }
+
+ /* Get the MCLK */
+ tsc2101_mclk_ck = clk_get(NULL, "mclk");
+ if (NULL == tsc2101_mclk_ck) {
+ printk(KERN_ERR "Unable to get the clock MCLK!!!\n");;
+ ret = -EPERM;
+ goto done;
+ }
+ if (clk_set_rate(tsc2101_mclk_ck, 12000000)) {
+ printk(KERN_ERR "Unable to set rate to the MCLK!!!\n");;
+ ret = -EPERM;
+ goto done;
+ }
+ clk_enable(tsc2101_mclk_ck);
+
+ ret = omap_tsc2101_configure();
+
+ /* Lock the module */
+ if (!ret && !try_module_get(THIS_MODULE)) {
+ printk(KERN_CRIT "Failed to get TSC module\n");
+ ret = -ESTALE;
+ }
+ }
+
+done:
+ spin_unlock(&tsc2101_lock);
+ return ret;
+}
+
+void omap_tsc2101_disable(void)
+{
+ spin_lock(&tsc2101_lock);
+ if (--count == 0) {
+ int ret = 0;
+ /* Remove the Mux to Stop MCLK to TSC2101 */
+ if (machine_is_omap_h3()) {
+ ret = omap_cfg_reg(V5_1710_MCLK_OFF);
+ } else {
+ if (machine_is_omap_h2()) {
+ ret = omap_cfg_reg(R10_1610_MCLK_OFF);
+ }
+ }
+
+ /* Release the MCLK */
+ clk_disable(tsc2101_mclk_ck);
+ clk_put(tsc2101_mclk_ck);
+ tsc2101_mclk_ck = NULL;
+
+ module_put(THIS_MODULE);
+ }
+ spin_unlock(&tsc2101_lock);
+}
+
+void omap_tsc2101_write(int page, u8 address, u16 data)
+{
+
+ int ret = 0;
+
+ if (machine_is_omap_h2()) {
+ ret =
+ omap_uwire_data_transfer(1,
+ (((page) << 11) | (address << 5)),
+ 16, 0, NULL, 1);
+ if (ret) {
+ printk(KERN_ERR
+ "uwire-write returned error for address %x\n",
+ address);
+ return;
+ }
+ ret = omap_uwire_data_transfer(1, data, 16, 0, NULL, 0);
+ if (ret) {
+ printk(KERN_ERR
+ "uwire-write returned error for address %x\n",
+ address);
+ return;
+ }
+ }
+ if (machine_is_omap_h3()) {
+
+ ret =
+ omap_uwire_data_transfer(0, ((page << 11) | (address << 5)),
+ 16, 0, NULL, 1);
+ if (ret) {
+ printk(KERN_ERR
+ "uwire-write returned error for address %x\n",
+ address);
+ return;
+ }
+ ret = omap_uwire_data_transfer(0, data, 16, 0, NULL, 0);
+ if (ret) {
+ printk(KERN_ERR
+ "uwire-write returned error for address %x\n",
+ address);
+ return;
+ }
+ }
+
+}
+
+void omap_tsc2101_reads(int page, u8 startaddress, u16 * data, int numregs)
+{
+ int cs = 0, i;
+ if (machine_is_omap_h2()) {
+ cs = 1;
+ }
+ if (machine_is_omap_h3()) {
+ cs = 0;
+ }
+ (void)omap_uwire_data_transfer(cs, (0x8000 | (page << 11)
+ | (startaddress << 5)),
+ 16, 0, NULL, 1);
+ for (i = 0; i < (numregs - 1); i++, data++) {
+ omap_uwire_data_transfer(cs, 0, 0, 16, data, 1);
+ }
+ omap_uwire_data_transfer(cs, 0, 0, 16, data, 0);
+}
+
+u16 omap_tsc2101_read(int page, u8 address)
+{
+ u16 ret;
+ omap_tsc2101_reads(page, address, &ret, 1);
+ return ret;
+}
+
+/* FIXME: adapt clock divisors for uwire to current ARM xor clock rate */
+static int omap_tsc2101_configure(void)
+{
+ unsigned long uwire_flags = 0;
+
+#ifdef CONFIG_MACH_OMAP_H3
+ int err = 0;
+ u8 ioExpanderVal = 0;
+
+ if ((err = read_gpio_expa(&ioExpanderVal, 0x24))) {
+ printk(" Error reading from I/O EXPANDER \n");
+ return err;
+ }
+ ioExpanderVal |= 0x8;
+
+ if ((err = write_gpio_expa(ioExpanderVal, 0x24))) {
+ printk(KERN_ERR ": Error writing to I/O EXPANDER \n");
+ return err;
+ }
+#endif
+
+ if (machine_is_omap_h2()) {
+ uwire_flags = UWIRE_READ_RISING_EDGE | UWIRE_WRITE_RISING_EDGE;
+ omap_cfg_reg(N15_1610_UWIRE_CS1);
+ omap_uwire_configure_mode(1, uwire_flags);
+ }
+ if (machine_is_omap_h3()) {
+ uwire_flags = UWIRE_READ_RISING_EDGE | UWIRE_WRITE_RISING_EDGE;
+ omap_cfg_reg(N14_1610_UWIRE_CS0);
+ omap_uwire_configure_mode(0, uwire_flags);
+ }
+
+ /* Configure MCLK enable */
+ omap_writel(omap_readl(PU_PD_SEL_2) | (1 << 22), PU_PD_SEL_2);
+
+ return 0;
+}
+
+EXPORT_SYMBOL(omap_tsc2101_enable);
+EXPORT_SYMBOL(omap_tsc2101_read);
+EXPORT_SYMBOL(omap_tsc2101_reads);
+EXPORT_SYMBOL(omap_tsc2101_write);
+EXPORT_SYMBOL(omap_tsc2101_disable);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION
+ ("Glue audio driver for the TI OMAP1610/OMAP1710 TSC2101 codec.");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * linux/drivers/ssi/omap-tsc2101.h
+ *
+ * TSC2101 codec interface driver for the OMAP platform
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ * 2004/11/07 Nishanth Menon - Provided common hooks for Audio and Touchscreen
+ */
+
+#ifndef __OMAP_TSC2101_H
+#define __OMAP_TSC2101_H
+
+extern u16 omap_tsc2101_read(int page, u8 address);
+extern void omap_tsc2101_reads(int page, u8 startaddress, u16 * data,
+ int numregs);
+extern void omap_tsc2101_write(int page, u8 address, u16 data);
+
+extern void omap_tsc2101_disable(void);
+extern int omap_tsc2101_enable(void);
+
+#endif
--- /dev/null
+/*
+ * BRIEF MODULE DESCRIPTION
+ *
+ * uWire interface driver for the OMAP Platform
+ *
+ * Copyright 2003 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * source@mvista.com
+ *
+ * Ported to 2.6 uwire interface.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * Generalization patches by Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/omap730.h> /* OMAP730_IO_CONF registers */
+
+#include "omap-uwire.h"
+
+/* uWire Registers: */
+#define UWIRE_BASE 0xFFFB3000
+#define UWIRE_IO_SIZE 0x20
+#define UWIRE_TDR 0x00
+#define UWIRE_RDR 0x00
+#define UWIRE_CSR 0x01
+#define UWIRE_SR1 0x02
+#define UWIRE_SR2 0x03
+#define UWIRE_SR3 0x04
+#define UWIRE_SR4 0x05
+#define UWIRE_SR5 0x06
+
+static unsigned short uwire_flags[4];
+static unsigned long uwire_base = io_p2v(UWIRE_BASE);
+static spinlock_t uwire_lock;
+static unsigned int uwire_idx_shift;
+
+static inline void uwire_write_reg(int idx, u16 val)
+{
+ __raw_writew(val, uwire_base + (idx << uwire_idx_shift));
+}
+
+static inline u16 uwire_read_reg(int idx)
+{
+ return __raw_readw(uwire_base + (idx << uwire_idx_shift));
+}
+
+void omap_uwire_configure_mode(int cs, unsigned long flags)
+{
+ u16 w, val = 0;
+ int shift, reg;
+
+ BUG_ON(cs > 3);
+
+ val = flags & 0x3f;
+ if (flags & UWIRE_CLK_INVERTED)
+ val ^= 0x03;
+ if (cs & 1)
+ shift = 6;
+ else
+ shift = 0;
+ if (cs <= 1)
+ reg = UWIRE_SR1;
+ else
+ reg = UWIRE_SR2;
+ spin_lock(&uwire_lock);
+ w = uwire_read_reg(reg);
+ w &= ~(0x3f << shift);
+ w |= val << shift;
+ uwire_write_reg(reg, w);
+ spin_unlock(&uwire_lock);
+
+ uwire_flags[cs] = flags;
+}
+
+static int wait_uwire_csr_flag(u16 mask, u16 val, int might_not_catch)
+{
+ u16 w;
+ int c = 0;
+ unsigned long max_jiffies = jiffies + HZ;
+
+ for (;;) {
+ w = uwire_read_reg(UWIRE_CSR);
+ if ((w & mask) == val)
+ break;
+ if (time_after(jiffies, max_jiffies)) {
+ printk(KERN_ERR "%s: timeout. reg=%#06x mask=%#06x val=%#06x\n",
+ __FUNCTION__, w, mask, val);
+ return -1;
+ }
+ c++;
+ if (might_not_catch && c > 64)
+ break;
+ }
+ return 0;
+}
+
+int omap_uwire_data_transfer(int cs, u16 tx_data, int tx_size, int rx_size,
+ u16 *rx_buf, int leave_cs_active)
+{
+ u16 ret = -1, w;
+ u16 mask;
+
+ BUG_ON(cs > 3);
+ BUG_ON(rx_size && !rx_buf);
+
+ spin_lock(&uwire_lock);
+
+ if (wait_uwire_csr_flag(1 << 14, 0, 0))
+ goto exit;
+
+ if (uwire_flags[cs] & UWIRE_CLK_INVERTED)
+ uwire_write_reg(UWIRE_SR4, 1);
+ else
+ uwire_write_reg(UWIRE_SR4, 0);
+
+ w = cs << 10;
+ w |= 1 << 12; /* CS_CMD : activate CS */
+ uwire_write_reg(UWIRE_CSR, w);
+
+ /* Shift data to 16bit MSb and place it in TX register. */
+ uwire_write_reg(UWIRE_TDR, tx_data << (16 - tx_size));
+
+ if (wait_uwire_csr_flag(1 << 14, 0, 0))
+ goto exit;
+
+ w = rx_size | (tx_size << 5) | (cs << 10);
+ w |= (1 << 12) | (1 << 13);
+ /* Start uWire read/write */
+ uwire_write_reg(UWIRE_CSR, w);
+
+ /* Wait till read/write actually starts.
+ * This is needed at high (>=60MHz) MPU frequencies
+ * REVISIT: But occasionally we won't have time to catch it
+ */
+ if (wait_uwire_csr_flag(1 << 14, 1 << 14, 1))
+ goto exit;
+
+ /* Wait for both transfers to be completed */
+ mask = 1 << 14; /* CSRB : reg busy */
+ w = 0;
+ if (rx_size) {
+ mask |= 1 << 15; /* RDRB : reg busy */
+ w |= 1 << 15;
+ }
+
+ if (wait_uwire_csr_flag(mask, w, 0))
+ goto exit;
+
+ if (rx_size)
+ *rx_buf = uwire_read_reg(UWIRE_RDR);
+
+ if (!leave_cs_active)
+ uwire_write_reg(UWIRE_CSR, cs << 10);
+
+ ret = 0;
+
+exit:
+ spin_unlock(&uwire_lock);
+ return ret;
+}
+
+static int __init omap_uwire_init(void)
+{
+ spin_lock_init(&uwire_lock);
+ if (cpu_is_omap730())
+ uwire_idx_shift = 1;
+ else
+ uwire_idx_shift = 2;
+
+ uwire_write_reg(UWIRE_SR3, 1);
+ if (machine_is_omap_h2()) {
+ /* defaults: W21 SDO, U18 SDI, V19 SCL */
+ omap_cfg_reg(N14_1610_UWIRE_CS0);
+ omap_cfg_reg(N15_1610_UWIRE_CS1);
+ }
+ if (machine_is_omap_osk()) {
+ /* this is the standard expansion connector usage, with
+ * the other chipselect pins for MPUIO2 and MPUIO4.
+ */
+ omap_cfg_reg(N14_1610_UWIRE_CS0);
+ omap_cfg_reg(P15_1610_UWIRE_CS3);
+ }
+ if (machine_is_omap_perseus2()) {
+ /* configure pins: MPU_UW_nSCS1, MPU_UW_SDO, MPU_UW_SCLK */
+ int val = omap_readl(OMAP730_IO_CONF_9) & ~0x00EEE000;
+ omap_writel(val | 0x00AAA000, OMAP730_IO_CONF_9);
+ }
+ return 0;
+}
+
+static void __exit omap_uwire_exit(void)
+{
+}
+
+subsys_initcall(omap_uwire_init);
+module_exit(omap_uwire_exit);
+
+EXPORT_SYMBOL(omap_uwire_configure_mode);
+EXPORT_SYMBOL(omap_uwire_data_transfer);
+
+MODULE_LICENSE("GPL");
--- /dev/null
+#ifndef __ARCH_OMAP_UWIRE_H
+#define __ARCH_OMAP_UWIRE_H
+
+#define UWIRE_READ_FALLING_EDGE 0x0000
+#define UWIRE_READ_RISING_EDGE 0x0001
+#define UWIRE_WRITE_FALLING_EDGE 0x0000
+#define UWIRE_WRITE_RISING_EDGE 0x0002
+#define UWIRE_CS_ACTIVE_LOW 0x0000
+#define UWIRE_CS_ACTIVE_HIGH 0x0004
+#define UWIRE_FREQ_DIV_2 0x0000
+#define UWIRE_FREQ_DIV_4 0x0008
+#define UWIRE_FREQ_DIV_8 0x0010
+#define UWIRE_CHK_READY 0x0020
+#define UWIRE_CLK_INVERTED 0x0040
+
+/*
+ * uWire for OMAP declarations
+ */
+extern void omap_uwire_configure_mode(int cs, unsigned long flags);
+
+/* NOTE: Make sure you don't call this from an interrupt handler! */
+extern int omap_uwire_data_transfer(int cs, u16 tx_data, int tx_size,
+ int rx_size, u16 *rx_buf,
+ int leave_cs_active);
+
+#endif
config USB_GADGET_OMAP
boolean "OMAP USB Device Controller"
- depends on ARCH_OMAP
+ depends on ARCH_OMAP1
select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
help
Many Texas Instruments OMAP processors have flexible full
#include <linux/usb_gadget.h>
#include <linux/usb_otg.h>
#include <linux/dma-mapping.h>
+#include <linux/clk.h>
#include <asm/byteorder.h>
#include <asm/io.h>
/* omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is
* read before the DMA controller finished disabling the channel.
*/
- csac = omap_readw(OMAP_DMA_CSAC(lch));
+ csac = OMAP_DMA_CSAC_REG(lch);
if (csac == 0)
- csac = omap_readw(OMAP_DMA_CSAC(lch));
+ csac = OMAP_DMA_CSAC_REG(lch);
return csac;
}
/* omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is
* read before the DMA controller finished disabling the channel.
*/
- cdac = omap_readw(OMAP_DMA_CDAC(lch));
+ cdac = OMAP_DMA_CDAC_REG(lch);
if (cdac == 0)
- cdac = omap_readw(OMAP_DMA_CDAC(lch));
+ cdac = OMAP_DMA_CDAC_REG(lch);
return cdac;
}
}
#define DMA_DEST_LAST(x) (cpu_is_omap15xx() \
- ? omap_readw(OMAP_DMA_CSAC(x)) /* really: CPC */ \
+ ? OMAP_DMA_CSAC_REG(x) /* really: CPC */ \
: dma_cdac(x))
static u16 dma_dest_len(struct omap_ep *ep, dma_addr_t start)
|| (cpu_is_omap15xx() && length < ep->maxpacket)) {
txdma_ctrl = UDC_TXN_EOT | length;
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
- length, 1, sync_mode);
+ length, 1, sync_mode, 0, 0);
} else {
length = min(length / ep->maxpacket,
(unsigned) UDC_TXN_TSC + 1);
txdma_ctrl = length;
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
- ep->ep.maxpacket >> 1, length, sync_mode);
+ ep->ep.maxpacket >> 1, length, sync_mode,
+ 0, 0);
length *= ep->maxpacket;
}
omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF,
- OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual);
+ OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual,
+ 0, 0);
omap_start_dma(ep->lch);
ep->dma_counter = dma_csac(ep->lch);
req->dma_bytes = packets * ep->ep.maxpacket;
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
ep->ep.maxpacket >> 1, packets,
- OMAP_DMA_SYNC_ELEMENT);
+ OMAP_DMA_SYNC_ELEMENT,
+ 0, 0);
omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF,
- OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual);
+ OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual,
+ 0, 0);
ep->dma_counter = DMA_DEST_LAST(ep->lch);
UDC_RXDMA_REG(ep->dma_channel) = UDC_RXN_STOP | (packets - 1);
omap_set_dma_dest_params(ep->lch,
OMAP_DMA_PORT_TIPB,
OMAP_DMA_AMODE_CONSTANT,
- (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG));
+ (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG),
+ 0, 0);
}
} else {
status = omap_request_dma(OMAP_DMA_USB_W2FC_RX0 - 1 + channel,
omap_set_dma_src_params(ep->lch,
OMAP_DMA_PORT_TIPB,
OMAP_DMA_AMODE_CONSTANT,
- (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG));
+ (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG),
+ 0, 0);
/* EMIFF */
omap_set_dma_dest_burst_mode(ep->lch,
OMAP_DMA_DATA_BURST_4);
/* channel type P: hw synch (fifo) */
if (!cpu_is_omap15xx())
- omap_writew(2, OMAP_DMA_LCH_CTRL(ep->lch));
+ OMAP1_DMA_LCH_CTRL_REG(ep->lch) = 2;
}
just_restart:
else
req = NULL;
- active = ((1 << 7) & omap_readl(OMAP_DMA_CCR(ep->lch))) != 0;
+ active = ((1 << 7) & OMAP_DMA_CCR_REG(ep->lch)) != 0;
DBG("%s release %s %cxdma%d %p\n", ep->ep.name,
active ? "active" : "idle",
UDC_SYSCON1_REG &= ~UDC_PULLUP_EN;
}
+static struct omap_udc *udc;
+
+static void omap_udc_enable_clock(int enable)
+{
+ if (udc == NULL || udc->dc_clk == NULL || udc->hhc_clk == NULL)
+ return;
+
+ if (enable) {
+ clk_enable(udc->dc_clk);
+ clk_enable(udc->hhc_clk);
+ udelay(100);
+ } else {
+ clk_disable(udc->hhc_clk);
+ clk_disable(udc->dc_clk);
+ }
+}
+
/*
* Called by whatever detects VBUS sessions: external transceiver
* driver, or maybe GPIO0 VBUS IRQ. May request 48 MHz clock.
else
FUNC_MUX_CTRL_0_REG &= ~VBUS_CTRL_1510;
}
+ if (udc->dc_clk != NULL && is_active) {
+ if (!udc->clk_requested) {
+ omap_udc_enable_clock(1);
+ udc->clk_requested = 1;
+ }
+ }
if (can_pullup(udc))
pullup_enable(udc);
else
pullup_disable(udc);
+ if (udc->dc_clk != NULL && !is_active) {
+ if (udc->clk_requested) {
+ omap_udc_enable_clock(0);
+ udc->clk_requested = 0;
+ }
+ }
spin_unlock_irqrestore(&udc->lock, flags);
return 0;
}
spin_lock_irqsave(&ep->udc->lock, flags);
if (!list_empty(&ep->queue) && ep->ackwait) {
- use_ep(ep, 0);
+ use_ep(ep, UDC_EP_SEL);
stat_flg = UDC_STAT_FLG_REG;
if ((stat_flg & UDC_ACK) && (!(stat_flg & UDC_FIFO_EN)
VDBG("%s: lose, %04x\n", ep->ep.name, stat_flg);
req = container_of(ep->queue.next,
struct omap_req, queue);
- UDC_EP_NUM_REG = ep->bEndpointAddress | UDC_EP_SEL;
(void) read_fifo(ep, req);
UDC_EP_NUM_REG = ep->bEndpointAddress;
UDC_CTRL_REG = UDC_SET_FIFO_EN;
ep->ackwait = 1 + ep->double_buf;
}
+ else {
+ deselect_ep();
+ }
}
mod_timer(&ep->timer, PIO_OUT_TIMEOUT);
spin_unlock_irqrestore(&ep->udc->lock, flags);
/*-------------------------------------------------------------------------*/
-static struct omap_udc *udc;
int usb_gadget_register_driver (struct usb_gadget_driver *driver)
{
udc->gadget.dev.driver = &driver->driver;
spin_unlock_irqrestore(&udc->lock, flags);
+ if (udc->dc_clk != NULL)
+ omap_udc_enable_clock(1);
+
status = driver->bind (&udc->gadget);
if (status) {
DBG("bind to %s --> %d\n", driver->driver.name, status);
omap_vbus_session(&udc->gadget, 1);
done:
+ if (udc->dc_clk != NULL)
+ omap_udc_enable_clock(0);
return status;
}
EXPORT_SYMBOL(usb_gadget_register_driver);
if (!driver || driver != udc->driver)
return -EINVAL;
+ if (udc->dc_clk != NULL)
+ omap_udc_enable_clock(1);
+
if (machine_is_omap_innovator() || machine_is_omap_osk())
omap_vbus_session(&udc->gadget, 0);
udc->gadget.dev.driver = NULL;
udc->driver = NULL;
+ if (udc->dc_clk != NULL)
+ omap_udc_enable_clock(0);
DBG("unregistered driver '%s'\n", driver->driver.name);
return status;
}
struct otg_transceiver *xceiv = NULL;
const char *type = NULL;
struct omap_usb_config *config = pdev->dev.platform_data;
+ struct clk *dc_clk;
+ struct clk *hhc_clk;
/* NOTE: "knows" the order of the resources! */
if (!request_mem_region(pdev->resource[0].start,
return -EBUSY;
}
+ if (cpu_is_omap16xx()) {
+ dc_clk = clk_get(&pdev->dev, "usb_dc_ck");
+ hhc_clk = clk_get(&pdev->dev, "usb_hhc_ck");
+ BUG_ON(IS_ERR(dc_clk) || IS_ERR(hhc_clk));
+ /* can't use omap_udc_enable_clock yet */
+ clk_enable(dc_clk);
+ clk_enable(hhc_clk);
+ udelay(100);
+ }
+
INFO("OMAP UDC rev %d.%d%s\n",
UDC_REV_REG >> 4, UDC_REV_REG & 0xf,
config->otg ? ", Mini-AB" : "");
goto cleanup3;
}
#endif
+ if (cpu_is_omap16xx()) {
+ udc->dc_clk = dc_clk;
+ udc->hhc_clk = hhc_clk;
+ clk_disable(hhc_clk);
+ clk_disable(dc_clk);
+ }
create_proc_file();
device_add(&udc->gadget.dev);
cleanup0:
if (xceiv)
put_device(xceiv->dev);
+
+ if (cpu_is_omap16xx()) {
+ clk_disable(hhc_clk);
+ clk_disable(dc_clk);
+ clk_put(hhc_clk);
+ clk_put(dc_clk);
+ }
+
release_mem_region(pdev->resource[0].start,
pdev->resource[0].end - pdev->resource[0].start + 1);
+
return status;
}
free_irq(pdev->resource[2].start, udc);
free_irq(pdev->resource[1].start, udc);
+ if (udc->dc_clk) {
+ if (udc->clk_requested)
+ omap_udc_enable_clock(0);
+ clk_put(udc->hhc_clk);
+ clk_put(udc->dc_clk);
+ }
+
release_mem_region(pdev->resource[0].start,
pdev->resource[0].end - pdev->resource[0].start + 1);
unsigned ep0_reset_config:1;
unsigned ep0_setup:1;
struct completion *done;
+ struct clk *dc_clk;
+ struct clk *hhc_clk;
+ unsigned clk_requested:1;
};
/*-------------------------------------------------------------------------*/
extern int ocpi_enable(void);
static struct clk *usb_host_ck;
+static struct clk *usb_dc_ck;
+static int host_enabled;
+static int host_initialized;
static void omap_ohci_clock_power(int on)
{
if (on) {
+ clk_enable(usb_dc_ck);
clk_enable(usb_host_ck);
/* guesstimate for T5 == 1x 32K clock + APLL lock time */
udelay(100);
} else {
clk_disable(usb_host_ck);
+ clk_disable(usb_dc_ck);
}
}
return 0;
}
+#ifdef CONFIG_ARCH_OMAP15XX
/*
* OMAP-1510 specific Local Bus clock on/off
*/
return 0;
}
+#else
+#define omap_1510_local_bus_power(x) {}
+#define omap_1510_local_bus_init() {}
+#endif
#ifdef CONFIG_USB_OTG
/* always called with process context; sleeping is OK */
+int ohci_omap_host_enable(struct usb_bus *host, int enable)
+{
+ struct usb_hcd *hcd;
+ struct ohci_hcd *ohci;
+ int retval;
+
+ if (host_enabled == enable)
+ return 0;
+
+ host_enabled = enable;
+
+ if (!host_initialized)
+ return 0;
+
+ hcd = (struct usb_hcd *)host->hcpriv;
+ ohci = hcd_to_ohci(hcd);
+ if (enable) {
+ omap_ohci_clock_power(1);
+ if ((retval = ohci_init(ohci)) < 0) {
+ dev_err(hcd->self.controller, "init error %d\n",
+ retval);
+ return retval;
+ }
+ if ((retval = hcd->driver->start(hcd)) < 0) {
+ dev_err(hcd->self.controller, "startup error %d\n",
+ retval);
+ return retval;
+ }
+ } else {
+ usb_disconnect(&hcd->self.root_hub);
+ hcd->driver->stop(hcd);
+ omap_ohci_clock_power(0);
+ }
+
+ return 0;
+}
+
/**
* usb_hcd_omap_probe - initialize OMAP-based HCDs
* Context: !in_interrupt()
if (IS_ERR(usb_host_ck))
return PTR_ERR(usb_host_ck);
+ usb_dc_ck = clk_get(0, "usb_dc_ck");
+ if (IS_ERR(usb_dc_ck)) {
+ clk_put(usb_host_ck);
+ return PTR_ERR(usb_dc_ck);
+ }
+
+
hcd = usb_create_hcd (driver, &pdev->dev, pdev->dev.bus_id);
if (!hcd) {
retval = -ENOMEM;
ohci = hcd_to_ohci(hcd);
ohci_hcd_init(ohci);
+ host_initialized = 0;
+ host_enabled = 1;
+
retval = omap_start_hc(ohci, pdev);
if (retval < 0)
goto err2;
retval = usb_add_hcd(hcd, platform_get_irq(pdev, 0), SA_INTERRUPT);
- if (retval == 0)
- return retval;
+ if (retval)
+ goto err3;
+
+ host_initialized = 1;
+
+ if (!host_enabled)
+ omap_ohci_clock_power(0);
+
+ return 0;
+err3:
omap_stop_hc(pdev);
err2:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err1:
usb_put_hcd(hcd);
err0:
+ clk_put(usb_dc_ck);
clk_put(usb_host_ck);
return retval;
}
omap_stop_hc(pdev);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
+ clk_put(usb_dc_ck);
clk_put(usb_host_ck);
}
/*-------------------------------------------------------------------------*/
-static int __devinit
+static int
ohci_omap_start (struct usb_hcd *hcd)
{
struct omap_usb_config *config;
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int ret;
+ if (!host_enabled)
+ return 0;
config = hcd->self.controller->platform_data;
if (config->otg || config->rwc)
writel(OHCI_CTRL_RWC, &ohci->regs->control);
omap_ohci_clock_power(0);
ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
- dev->power.power_state = PMSG_SUSPEND;
+ dev->dev.power.power_state = PMSG_SUSPEND;
return 0;
}
ohci->next_statechange = jiffies;
omap_ohci_clock_power(1);
- dev->power.power_state = PMSG_ON;
- usb_hcd_resume_root_hub(dev_get_drvdata(dev));
+ dev->dev.power.power_state = PMSG_ON;
+ usb_hcd_resume_root_hub(platform_get_drvdata(dev));
return 0;
}
Turn on debugging messages. Note that you can set/unset at run time
through sysfs
+source "drivers/video/omap/Kconfig"
+
config FB_VIRTUAL
tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)"
depends on FB
obj-$(CONFIG_FB_VESA) += vesafb.o
obj-$(CONFIG_FB_VGA16) += vga16fb.o vgastate.o
obj-$(CONFIG_FB_OF) += offb.o
+obj-$(CONFIG_FB_OMAP) += omap/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o
# the test framebuffer is last
obj-$(CONFIG_FB_VIRTUAL) += vfb.o
--- /dev/null
+config FB_OMAP
+ tristate "OMAP frame buffer support (EXPERIMENTAL)"
+ depends on FB
+ help
+ Frame buffer driver for OMAP based boards.
+
+config FB_OMAP_LCDC_EXTERNAL
+ bool "External LCD controller support"
+ depends on FB_OMAP
+ help
+ Say Y here, if you want to have support for boards with an
+ external LCD controller connected to the SoSSI/RFBI interface.
+
+config FB_OMAP_LCDC_HWA742
+ bool "Epson HWA742 LCD controller support"
+ depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL
+ help
+ Say Y here if you want to have support for the external
+ Epson HWA742 LCD controller.
+
+config FB_OMAP_MANUAL_UPDATE
+ bool "Default to manual update mode"
+ depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL
+ help
+ Say Y here, if your user-space applications are capable of
+ notifying the frame buffer driver when a change has occured in
+ the frame buffer content and thus a reload of the image data to
+ the external frame buffer is required. If unsure, say N.
+
+config FB_OMAP_LCD_LPH8923
+ bool "Philips LPH8923 LCD support"
+ depends on FB_OMAP
+ help
+ Say Y here if you want to have support for the Philips
+ LPH8923 LCD.
+
+config FB_OMAP_BOOTLOADER_INIT
+ bool "Check bootloader initializaion"
+ depends on FB_OMAP
+ help
+ Say Y here if you want to enable checking if the bootloader has
+ already initialized the display controller. In this case the
+ driver will skip the initialization.
+
+config FB_OMAP_DMA_TUNE
+ bool "Set DMA SDRAM access priority high"
+ depends on FB_OMAP && ARCH_OMAP1
+ help
+ On systems in which video memory is in system memory
+ (SDRAM) this will speed up graphics DMA operations.
+ If you have such a system and want to use rotation
+ answer yes. Answer no if you have a dedicated video
+ memory, or don't use any of the accelerated features.
+
+
--- /dev/null
+#
+# Makefile for the new OMAP framebuffer device driver
+#
+
+obj-$(CONFIG_FB_OMAP) += omapfb.o
+
+objs-yy := omapfb_main.o
+
+objs-y$(CONFIG_ARCH_OMAP1) += lcdc.o
+objs-y$(CONFIG_ARCH_OMAP2) += dispc.o
+
+objs-$(CONFIG_ARCH_OMAP1)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += sossi.o
+objs-$(CONFIG_ARCH_OMAP2)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += rfbi.o
+
+objs-y$(CONFIG_FB_OMAP_LCDC_HWA742) += hwa742.o
+
+objs-y$(CONFIG_MACH_OMAP_H4) += lcd_h4.o
+objs-y$(CONFIG_MACH_OMAP_H3) += lcd_h3.o
+objs-y$(CONFIG_MACH_OMAP_H2) += lcd_h2.o
+objs-y$(CONFIG_MACH_OMAP_PALMTE) += lcd_palmte.o
+objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1610.o
+objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1510.o
+objs-y$(CONFIG_MACH_OMAP_OSK) += lcd_osk.o
+objs-y$(CONFIG_MACH_OMAP_PERSEUS2) += lcd_p2.o
+objs-y$(CONFIG_MACH_OMAP_APOLLON) += lcd_apollon.o
+
+objs-y$(CONFIG_FB_OMAP_LCD_LPH8923) += lcd_lph8923.o
+
+omapfb-objs := $(objs-yy)
+
--- /dev/null
+/*
+ * File: drivers/video/omap_new/debug.c
+ *
+ * Debug support for the omapfb driver
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@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.
+ */
+
+#ifndef __OMAPFB_DEBUG_H
+#define __OMAPFB_DEBUG_H
+
+#ifdef OMAPFB_DBG
+
+#define DBGPRINT(level, fmt, ...) if (level <= OMAPFB_DBG) do { \
+ printk(KERN_DEBUG "%s: "fmt, \
+ __FUNCTION__, ## __VA_ARGS__); \
+ } while (0)
+#define DBGENTER(level) DBGPRINT(level, "Enter\n")
+#define DBGLEAVE(level) DBGPRINT(level, "Leave\n")
+
+#else /* OMAPFB_DBG */
+
+#define DBGPRINT(level, format, ...)
+#define DBGENTER(level)
+#define DBGLEAVE(level)
+
+#endif /* OMAPFB_DBG */
+
+#endif /* __OMAPFB_DEBUG_H */
--- /dev/null
+/*
+ * File: drivers/video/omap/omap2/dispc.c
+ *
+ * OMAP2 display controller support
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Imre Deak <imre.deak@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/dma-mapping.h>
+#include <linux/vmalloc.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+
+#include <asm/arch/sram.h>
+#include <asm/arch/omapfb.h>
+#include <asm/arch/board.h>
+
+#include "dispc.h"
+
+/* #define OMAPFB_DBG 1 */
+
+#include "debug.h"
+
+#define MODULE_NAME "omapfb-dispc"
+
+#define DISPC_BASE 0x48050400
+
+/* DISPC common */
+#define DISPC_REVISION 0x0000
+#define DISPC_SYSCONFIG 0x0010
+#define DISPC_SYSSTATUS 0x0014
+#define DISPC_IRQSTATUS 0x0018
+#define DISPC_IRQENABLE 0x001C
+#define DISPC_CONTROL 0x0040
+#define DISPC_CONFIG 0x0044
+#define DISPC_CAPABLE 0x0048
+#define DISPC_DEFAULT_COLOR0 0x004C
+#define DISPC_DEFAULT_COLOR1 0x0050
+#define DISPC_TRANS_COLOR0 0x0054
+#define DISPC_TRANS_COLOR1 0x0058
+#define DISPC_LINE_STATUS 0x005C
+#define DISPC_LINE_NUMBER 0x0060
+#define DISPC_TIMING_H 0x0064
+#define DISPC_TIMING_V 0x0068
+#define DISPC_POL_FREQ 0x006C
+#define DISPC_DIVISOR 0x0070
+#define DISPC_SIZE_DIG 0x0078
+#define DISPC_SIZE_LCD 0x007C
+
+#define DISPC_DATA_CYCLE1 0x01D4
+#define DISPC_DATA_CYCLE2 0x01D8
+#define DISPC_DATA_CYCLE3 0x01DC
+
+/* DISPC GFX plane */
+#define DISPC_GFX_BA0 0x0080
+#define DISPC_GFX_BA1 0x0084
+#define DISPC_GFX_POSITION 0x0088
+#define DISPC_GFX_SIZE 0x008C
+#define DISPC_GFX_ATTRIBUTES 0x00A0
+#define DISPC_GFX_FIFO_THRESHOLD 0x00A4
+#define DISPC_GFX_FIFO_SIZE_STATUS 0x00A8
+#define DISPC_GFX_ROW_INC 0x00AC
+#define DISPC_GFX_PIXEL_INC 0x00B0
+#define DISPC_GFX_WINDOW_SKIP 0x00B4
+#define DISPC_GFX_TABLE_BA 0x00B8
+
+/* DISPC Video plane 1/2 */
+#define DISPC_VID1_BASE 0x00BC
+#define DISPC_VID2_BASE 0x014C
+
+/* Offsets into DISPC_VID1/2_BASE */
+#define DISPC_VID_BA0 0x0000
+#define DISPC_VID_BA1 0x0004
+#define DISPC_VID_POSITION 0x0008
+#define DISPC_VID_SIZE 0x000C
+#define DISPC_VID_ATTRIBUTES 0x0010
+#define DISPC_VID_FIFO_THRESHOLD 0x0014
+#define DISPC_VID_FIFO_SIZE_STATUS 0x0018
+#define DISPC_VID_ROW_INC 0x001C
+#define DISPC_VID_PIXEL_INC 0x0020
+#define DISPC_VID_FIR 0x0024
+#define DISPC_VID_PICTURE_SIZE 0x0028
+#define DISPC_VID_ACCU0 0x002C
+#define DISPC_VID_ACCU1 0x0030
+
+/* 8 elements in 8 byte increments */
+#define DISPC_VID_FIR_COEF_H0 0x0034
+/* 8 elements in 8 byte increments */
+#define DISPC_VID_FIR_COEF_HV0 0x0038
+/* 5 elements in 4 byte increments */
+#define DISPC_VID_CONV_COEF0 0x0074
+
+#define DISPC_IRQ_FRAMEMASK 0x0001
+#define DISPC_IRQ_VSYNC 0x0002
+#define DISPC_IRQ_EVSYNC_EVEN 0x0004
+#define DISPC_IRQ_EVSYNC_ODD 0x0008
+#define DISPC_IRQ_ACBIAS_COUNT_STAT 0x0010
+#define DISPC_IRQ_PROG_LINE_NUM 0x0020
+#define DISPC_IRQ_GFX_FIFO_UNDERFLOW 0x0040
+#define DISPC_IRQ_GFX_END_WIN 0x0080
+#define DISPC_IRQ_PAL_GAMMA_MASK 0x0100
+#define DISPC_IRQ_OCP_ERR 0x0200
+#define DISPC_IRQ_VID1_FIFO_UNDERFLOW 0x0400
+#define DISPC_IRQ_VID1_END_WIN 0x0800
+#define DISPC_IRQ_VID2_FIFO_UNDERFLOW 0x1000
+#define DISPC_IRQ_VID2_END_WIN 0x2000
+#define DISPC_IRQ_SYNC_LOST 0x4000
+
+#define DISPC_IRQ_MASK_ALL 0x7fff
+
+#define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
+ DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
+ DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
+ DISPC_IRQ_SYNC_LOST)
+
+#define RFBI_CONTROL 0x48050040
+
+#define MAX_PALETTE_SIZE (256 * 16)
+
+#define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
+
+#define FLD_MASK(pos, len) (((1 << len) - 1) << pos)
+
+#define MOD_REG_FLD(reg, mask, val) \
+ dispc_write_reg((reg), (dispc_read_reg(reg) & ~(mask)) | (val));
+
+static struct {
+ u32 base;
+
+ dma_addr_t fb_sram_paddr;
+ u32 fb_sram_size;
+ int fb_sram_lines;
+
+ dma_addr_t fb_sdram_paddr;
+ void *fb_sdram_vaddr;
+ u32 fb_sdram_size;
+ int fb_sdram_lines;
+
+ dma_addr_t palette_paddr;
+ void *palette_vaddr;
+
+ void *fb_kern_vaddr;
+
+ int multiplane_head;
+
+ int ext_mode;
+ int fbmem_allocated;
+
+ unsigned long enabled_irqs;
+ void (*irq_callback)(void *);
+ void *irq_callback_data;
+ struct completion frame_done;
+
+ struct clk *dss_ick, *dss1_fck;
+ struct clk *dss_54m_fck;
+
+ enum omapfb_update_mode update_mode;
+ struct omapfb_device *fbdev;
+} dispc;
+
+static void inline dispc_write_reg(int idx, u32 val)
+{
+ __raw_writel(val, dispc.base + idx);
+}
+
+static u32 inline dispc_read_reg(int idx)
+{
+ u32 l = __raw_readl(dispc.base + idx);
+ return l;
+}
+
+/* Select RFBI or bypass mode */
+static void enable_rfbi_mode(int enable)
+{
+ u32 l;
+
+ l = dispc_read_reg(DISPC_CONTROL);
+ /* Enable RFBI, GPIO0/1 */
+ l &= ~((1 << 11) | (1 << 15) | (1 << 16));
+ l |= enable ? (1 << 11) : 0;
+ /* RFBI En: GPIO0/1=10 RFBI Dis: GPIO0/1=11 */
+ l |= 1 << 15;
+ l |= enable ? 0 : (1 << 16);
+ dispc_write_reg(DISPC_CONTROL, l);
+
+ /* Set bypass mode in RFBI module */
+ l = __raw_readl(io_p2v(RFBI_CONTROL));
+ l |= enable ? 0 : (1 << 1);
+ __raw_writel(l, io_p2v(RFBI_CONTROL));
+}
+
+static void set_lcd_data_lines(int data_lines)
+{
+ u32 l;
+ int code = 0;
+
+ switch (data_lines) {
+ case 12:
+ code = 0;
+ break;
+ case 16:
+ code = 1;
+ break;
+ case 18:
+ code = 2;
+ break;
+ case 24:
+ code = 3;
+ break;
+ default:
+ BUG();
+ }
+
+ l = dispc_read_reg(DISPC_CONTROL);
+ l &= ~(0x03 << 8);
+ l |= code << 8;
+ dispc_write_reg(DISPC_CONTROL, l);
+}
+
+static void set_load_mode(int mode)
+{
+ BUG_ON(mode & ~(DISPC_LOAD_CLUT_ONLY | DISPC_LOAD_FRAME_ONLY |
+ DISPC_LOAD_CLUT_ONCE_FRAME));
+ MOD_REG_FLD(DISPC_CONFIG, 0x03 << 1, mode << 1);
+}
+
+void omap_dispc_set_lcd_size(int x, int y)
+{
+ BUG_ON((x > (1 << 11)) || (y > (1 << 11)));
+ MOD_REG_FLD(DISPC_SIZE_LCD, FLD_MASK(16, 11) | FLD_MASK(0, 11),
+ ((y - 1) << 16) | (x - 1));
+}
+EXPORT_SYMBOL(omap_dispc_set_lcd_size);
+
+void omap_dispc_set_digit_size(int x, int y)
+{
+ BUG_ON((x > (1 << 11)) || (y > (1 << 11)));
+ MOD_REG_FLD(DISPC_SIZE_DIG, FLD_MASK(16, 11) | FLD_MASK(0, 11),
+ ((y - 1) << 16) | (x - 1));
+}
+EXPORT_SYMBOL(omap_dispc_set_digit_size);
+
+static void setup_plane_fifo(int plane)
+{
+ const u32 ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD,
+ DISPC_VID1_BASE + DISPC_VID_FIFO_THRESHOLD,
+ DISPC_VID2_BASE + DISPC_VID_FIFO_THRESHOLD };
+ const u32 fsz_reg[] = { DISPC_GFX_FIFO_SIZE_STATUS,
+ DISPC_VID1_BASE + DISPC_VID_FIFO_SIZE_STATUS,
+ DISPC_VID2_BASE + DISPC_VID_FIFO_SIZE_STATUS };
+
+ u32 l;
+
+ BUG_ON(plane > 2);
+
+ l = dispc_read_reg(fsz_reg[plane]);
+ l &= FLD_MASK(0, 9);
+ /* HIGH=3/4 LOW=1/4 */
+ MOD_REG_FLD(ftrs_reg[plane], FLD_MASK(16, 9) | FLD_MASK(0, 9),
+ ((l * 3 / 4) << 16) | (l / 4));
+}
+
+void omap_dispc_enable_lcd_out(int enable)
+{
+ MOD_REG_FLD(DISPC_CONTROL, 1, enable ? 1 : 0);
+}
+EXPORT_SYMBOL(omap_dispc_enable_lcd_out);
+
+void omap_dispc_enable_digit_out(int enable)
+{
+ MOD_REG_FLD(DISPC_CONTROL, 1 << 1, enable ? 1 << 1 : 0);
+}
+EXPORT_SYMBOL(omap_dispc_enable_digit_out);
+
+static inline int _setup_plane(int plane, int channel_out,
+ u32 paddr, int screen_width,
+ int pos_x, int pos_y, int width, int height,
+ int color_mode)
+{
+ const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES,
+ DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES,
+ DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES };
+ const u32 ba_reg[] = { DISPC_GFX_BA0, DISPC_VID1_BASE + DISPC_VID_BA0,
+ DISPC_VID2_BASE + DISPC_VID_BA0 };
+ const u32 ps_reg[] = { DISPC_GFX_POSITION,
+ DISPC_VID1_BASE + DISPC_VID_POSITION,
+ DISPC_VID2_BASE + DISPC_VID_POSITION };
+ const u32 sz_reg[] = { DISPC_GFX_SIZE, DISPC_VID1_BASE + DISPC_VID_SIZE,
+ DISPC_VID2_BASE + DISPC_VID_SIZE };
+ const u32 ri_reg[] = { DISPC_GFX_ROW_INC,
+ DISPC_VID1_BASE + DISPC_VID_ROW_INC,
+ DISPC_VID2_BASE + DISPC_VID_ROW_INC };
+ int chout_shift, burst_shift;
+ int chout_val;
+ int color_code;
+ int bpp;
+ u32 l;
+
+ DBGPRINT(2, "plane %d channel %d paddr %u scr_width %d pos_x %d pos_y %d "
+ "width %d height %d color_mode %d\n",
+ plane, channel_out, paddr, screen_width, pos_x, pos_y,
+ width, height, color_mode);
+
+ switch (plane) {
+ case OMAPFB_PLANE_GFX:
+ burst_shift = 6;
+ chout_shift = 8;
+ break;
+ case OMAPFB_PLANE_VID1:
+ case OMAPFB_PLANE_VID2:
+ burst_shift = 14;
+ chout_shift = 16;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (channel_out) {
+ case OMAPFB_CHANNEL_OUT_LCD:
+ chout_val = 0;
+ break;
+ case OMAPFB_CHANNEL_OUT_DIGIT:
+ chout_val = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (color_mode) {
+ case OMAPFB_COLOR_RGB565:
+ color_code = DISPC_RGB_16_BPP;
+ bpp = 16;
+ break;
+ case OMAPFB_COLOR_YUV422:
+ if (plane != 0)
+ return -EINVAL;
+ color_code = DISPC_UYVY_422;
+ bpp = 16;
+ break;
+ case OMAPFB_COLOR_YUV420:
+ if (plane != 0)
+ return -EINVAL;
+ color_code = DISPC_YUV2_422;
+ bpp = 12;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ l = dispc_read_reg(at_reg[plane]);
+
+ l &= ~(0x0f << 1);
+ l |= color_code << 1;
+
+ l &= ~(0x03 << burst_shift);
+ l |= DISPC_BURST_8x32 << burst_shift;
+
+ l &= ~(1 << chout_shift);
+ l |= chout_val << chout_shift;
+
+ dispc_write_reg(at_reg[plane], l);
+
+ dispc_write_reg(ba_reg[plane], paddr);
+ MOD_REG_FLD(ps_reg[plane],
+ FLD_MASK(16, 11) | FLD_MASK(0, 11), (pos_y << 16) | pos_x);
+
+ MOD_REG_FLD(sz_reg[plane], FLD_MASK(16, 11) | FLD_MASK(0, 11),
+ ((height - 1) << 16) | (width - 1));
+
+ dispc_write_reg(ri_reg[plane], (screen_width - width) * bpp / 8 + 1);
+
+ return height * screen_width * bpp / 8;
+}
+
+static int omap_dispc_setup_plane(int plane, int channel_out,
+ unsigned long offset, int screen_width,
+ int pos_x, int pos_y, int width, int height,
+ int color_mode)
+{
+ int yspan;
+ u32 paddr;
+ int mp_head = -1;
+ int r;
+
+ if (offset > dispc.fb_sram_size + dispc.fb_sdram_size)
+ return -EINVAL;
+
+ if (offset < dispc.fb_sram_size) {
+ paddr = dispc.fb_sram_paddr + offset;
+ yspan = min_t(int, height, dispc.fb_sram_lines);
+ if (yspan) {
+ if ((r = _setup_plane(plane, channel_out, paddr,
+ screen_width, pos_x, pos_y,
+ width, height, color_mode)) < 0)
+ return r;
+ offset += r;
+ height -= yspan;
+ pos_y += yspan;
+ mp_head = plane;
+ if (++plane > 2)
+ plane = OMAPFB_PLANE_GFX;
+ }
+ }
+ if (height) {
+ offset -= dispc.fb_sram_size;
+ paddr = dispc.fb_sdram_paddr + offset;
+ yspan = min_t(int, height, dispc.fb_sdram_lines);
+ if (yspan) {
+ if ((r = _setup_plane(plane, channel_out, paddr,
+ screen_width, pos_x, pos_y,
+ width, height, color_mode)) < 0)
+ return r;
+ if (mp_head != -1)
+ dispc.multiplane_head = mp_head;
+ }
+ }
+
+ return 0;
+}
+
+static int omap_dispc_enable_plane(int plane, int enable)
+{
+ const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES,
+ DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES,
+ DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES };
+ DBGENTER(2);
+
+ if ((unsigned int)plane > 2)
+ return -EINVAL;
+ MOD_REG_FLD(at_reg[plane], 1, enable ? 1 : 0);
+ if (plane == dispc.multiplane_head) {
+ if (++plane > 2)
+ plane = OMAPFB_PLANE_GFX;
+ MOD_REG_FLD(at_reg[plane], 1, enable ? 1 : 0);
+ }
+
+ return 0;
+}
+
+static int omap_dispc_set_color_key(struct omapfb_color_key *ck)
+{
+ u32 df_reg, tr_reg;
+ int shift, val;
+
+ switch (ck->channel_out) {
+ case OMAPFB_CHANNEL_OUT_LCD:
+ df_reg = DISPC_DEFAULT_COLOR0;
+ tr_reg = DISPC_TRANS_COLOR0;
+ shift = 10;
+ break;
+ case OMAPFB_CHANNEL_OUT_DIGIT:
+ df_reg = DISPC_DEFAULT_COLOR1;
+ tr_reg = DISPC_TRANS_COLOR1;
+ shift = 12;
+ break;
+ default:
+ return -EINVAL;
+ }
+ switch (ck->key_type) {
+ case OMAPFB_COLOR_KEY_DISABLED:
+ val = 0;
+ break;
+ case OMAPFB_COLOR_KEY_GFX_DST:
+ val = 1;
+ break;
+ case OMAPFB_COLOR_KEY_VID_SRC:
+ val = 3;
+ break;
+ default:
+ return -EINVAL;
+ }
+ MOD_REG_FLD(DISPC_CONFIG, FLD_MASK(shift, 2), val << shift);
+
+ if (val != 0)
+ dispc_write_reg(tr_reg, ck->trans_key);
+ dispc_write_reg(df_reg, ck->background);
+
+ return 0;
+}
+
+static void load_palette(void)
+{
+}
+
+static int omap_dispc_set_update_mode(enum omapfb_update_mode mode)
+{
+ int r = 0;
+
+ DBGENTER(1);
+
+ if (mode != dispc.update_mode) {
+ switch (mode) {
+ case OMAPFB_AUTO_UPDATE:
+ case OMAPFB_MANUAL_UPDATE:
+ omap_dispc_enable_lcd_out(1);
+ dispc.update_mode = mode;
+ break;
+ case OMAPFB_UPDATE_DISABLED:
+ init_completion(&dispc.frame_done);
+ omap_dispc_enable_lcd_out(0);
+ if (!wait_for_completion_timeout(&dispc.frame_done,
+ msecs_to_jiffies(500))) {
+ pr_err("timeout waiting for FRAME DONE\n");
+ }
+ dispc.update_mode = mode;
+ break;
+ default:
+ r = -EINVAL;
+ }
+ }
+
+ DBGLEAVE(1);
+
+ return r;
+}
+
+static enum omapfb_update_mode omap_dispc_get_update_mode(void)
+{
+ return dispc.update_mode;
+}
+
+static void calc_ck_div(int is_tft, int pck, int *lck_div, int *pck_div)
+{
+ unsigned long fck, lck;
+
+ *lck_div = 1;
+ pck = max(1, pck);
+ fck = clk_get_rate(dispc.dss1_fck);
+ lck = fck;
+ *pck_div = (lck + pck - 1) / pck;
+ if (is_tft)
+ *pck_div = max(2, *pck_div);
+ else
+ *pck_div = max(3, *pck_div);
+ if (*pck_div > 255) {
+ *pck_div = 255;
+ lck = pck * *pck_div;
+ *lck_div = fck / lck;
+ BUG_ON(*lck_div < 1);
+ if (*lck_div > 255) {
+ *lck_div = 255;
+ printk(KERN_WARNING
+ MODULE_NAME ": pixclock %d kHz too low.\n",
+ pck / 1000);
+ }
+ }
+}
+
+static void set_lcd_tft_mode(int enable)
+{
+ u32 mask;
+
+ mask = 1 << 3;
+ MOD_REG_FLD(DISPC_CONTROL, mask, enable ? mask : 0);
+}
+
+static void set_lcd_timings(void)
+{
+ u32 l;
+ int lck_div, pck_div;
+ struct lcd_panel *panel = dispc.fbdev->panel;
+ int is_tft = panel->config & OMAP_LCDC_PANEL_TFT;
+ unsigned long fck;
+
+ DBGENTER(1);
+
+ l = dispc_read_reg(DISPC_TIMING_H);
+ l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8));
+ l |= ( max(1, (min(64, panel->hsw))) - 1 ) << 0;
+ l |= ( max(1, (min(256, panel->hfp))) - 1 ) << 8;
+ l |= ( max(1, (min(256, panel->hbp))) - 1 ) << 20;
+ dispc_write_reg(DISPC_TIMING_H, l);
+
+ l = dispc_read_reg(DISPC_TIMING_V);
+ l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8));
+ l |= ( max(1, (min(64, panel->vsw))) - 1 ) << 0;
+ l |= ( max(0, (min(255, panel->vfp))) - 0 ) << 8;
+ l |= ( max(0, (min(255, panel->vbp))) - 0 ) << 20;
+ dispc_write_reg(DISPC_TIMING_V, l);
+
+ l = dispc_read_reg(DISPC_POL_FREQ);
+ l &= ~FLD_MASK(12, 6);
+ l |= (panel->config & OMAP_LCDC_SIGNAL_MASK) << 12;
+ l |= panel->acb & 0xff;
+ dispc_write_reg(DISPC_POL_FREQ, l);
+
+ calc_ck_div(is_tft, panel->pixel_clock * 1000, &lck_div, &pck_div);
+
+ l = dispc_read_reg(DISPC_DIVISOR);
+ l &= ~(FLD_MASK(16, 8) | FLD_MASK(0, 8));
+ l |= (lck_div << 16) | (pck_div << 0);
+ dispc_write_reg(DISPC_DIVISOR, l);
+
+ /* update panel info with the exact clock */
+ fck = clk_get_rate(dispc.dss1_fck);
+ panel->pixel_clock = fck / lck_div / pck_div / 1000;
+}
+
+int omap_dispc_request_irq(void (*callback)(void *data), void *data)
+{
+ int r = 0;
+
+ BUG_ON(callback == NULL);
+
+ if (dispc.irq_callback)
+ r = -EBUSY;
+ else {
+ dispc.irq_callback = callback;
+ dispc.irq_callback_data = data;
+ }
+
+ return r;
+}
+EXPORT_SYMBOL(omap_dispc_request_irq);
+
+void omap_dispc_enable_irqs(int irq_mask)
+{
+ dispc.enabled_irqs = irq_mask;
+ irq_mask |= DISPC_IRQ_MASK_ERROR;
+ MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask);
+}
+EXPORT_SYMBOL(omap_dispc_enable_irqs);
+
+void omap_dispc_disable_irqs(int irq_mask)
+{
+ dispc.enabled_irqs &= ~irq_mask;
+ irq_mask &= ~DISPC_IRQ_MASK_ERROR;
+ MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask);
+}
+EXPORT_SYMBOL(omap_dispc_disable_irqs);
+
+void omap_dispc_free_irq(void)
+{
+ omap_dispc_disable_irqs(DISPC_IRQ_MASK_ALL);
+ dispc.irq_callback = NULL;
+ dispc.irq_callback_data = NULL;
+}
+EXPORT_SYMBOL(omap_dispc_free_irq);
+
+static irqreturn_t omap_dispc_irq_handler(int irq, void *dev, struct pt_regs *regs)
+{
+ u32 stat = dispc_read_reg(DISPC_IRQSTATUS);
+ static int jabber;
+
+ DBGENTER(2);
+
+ if (stat & DISPC_IRQ_FRAMEMASK)
+ complete(&dispc.frame_done);
+
+ if (stat & DISPC_IRQ_MASK_ERROR) {
+ if (jabber++ < 5) {
+ pr_err("irq error status %04x\n", stat & 0x7fff);
+ } else {
+ pr_err("disable irq\n");
+ dispc_write_reg(DISPC_IRQENABLE, 0);
+ }
+ }
+
+ if ((stat & dispc.enabled_irqs) && dispc.irq_callback)
+ dispc.irq_callback(dispc.irq_callback_data);
+
+ dispc_write_reg(DISPC_IRQSTATUS, stat);
+
+ return IRQ_HANDLED;
+}
+
+static int get_dss_clocks(void)
+{
+ if (IS_ERR((dispc.dss_ick = clk_get(dispc.fbdev->dev, "dss_ick")))) {
+ pr_err("can't get dss_ick");
+ return PTR_ERR(dispc.dss_ick);
+ }
+
+ if (IS_ERR((dispc.dss1_fck = clk_get(dispc.fbdev->dev, "dss1_fck")))) {
+ pr_err("can't get dss1_fck");
+ clk_put(dispc.dss_ick);
+ return PTR_ERR(dispc.dss1_fck);
+ }
+
+ if (IS_ERR((dispc.dss_54m_fck =
+ clk_get(dispc.fbdev->dev, "dss_54m_fck")))) {
+ pr_err("can't get dss_54m_fck");
+ clk_put(dispc.dss_ick);
+ clk_put(dispc.dss1_fck);
+ return PTR_ERR(dispc.dss_54m_fck);
+ }
+
+ return 0;
+}
+
+static void put_dss_clocks(void)
+{
+ clk_put(dispc.dss_54m_fck);
+ clk_put(dispc.dss1_fck);
+ clk_put(dispc.dss_ick);
+}
+
+static void enable_lcd_clocks(int enable)
+{
+ if (enable) {
+ clk_enable(dispc.dss_ick);
+ clk_enable(dispc.dss1_fck);
+ } else {
+ clk_disable(dispc.dss1_fck);
+ clk_disable(dispc.dss_ick);
+ }
+}
+
+static void enable_digit_clocks(int enable)
+{
+ if (enable)
+ clk_enable(dispc.dss_54m_fck);
+ else
+ clk_disable(dispc.dss_54m_fck);
+}
+
+static void omap_dispc_suspend(void)
+{
+ DBGENTER(1);
+
+ if (dispc.update_mode == OMAPFB_AUTO_UPDATE) {
+ init_completion(&dispc.frame_done);
+ omap_dispc_enable_lcd_out(0);
+ if (!wait_for_completion_timeout(&dispc.frame_done,
+ msecs_to_jiffies(500))) {
+ pr_err("timeout waiting for FRAME DONE\n");
+ }
+ enable_lcd_clocks(0);
+ }
+
+ DBGLEAVE(1);
+}
+
+static void omap_dispc_resume(void)
+{
+ DBGENTER(1);
+
+ if (dispc.update_mode == OMAPFB_AUTO_UPDATE) {
+ enable_lcd_clocks(1);
+ set_lcd_timings();
+ load_palette();
+ omap_dispc_enable_lcd_out(1);
+ }
+
+ DBGLEAVE(1);
+}
+
+
+static int omap_dispc_update_window(struct omapfb_update_window *win,
+ void (*complete_callback)(void *arg),
+ void *complete_callback_data)
+{
+ return dispc.update_mode == OMAPFB_UPDATE_DISABLED ? -ENODEV : 0;
+}
+
+/* Greatest common divisor */
+static int calc_gcd(int a, int b)
+{
+ int tmp;
+
+ if (a < b) {
+ tmp = a;
+ a = b;
+ b = tmp;
+ }
+ for (;;) {
+ tmp = a % b;
+ if (tmp != 0) {
+ a = b;
+ b = tmp;
+ } else
+ break;
+ }
+
+ return b;
+}
+
+/* Least common multiple */
+static int calc_lcm(int a, int b)
+{
+ return a * b / calc_gcd(a, b);
+}
+
+static void omap_dispc_get_vram_layout(unsigned long *size, void **virt,
+ dma_addr_t *phys)
+{
+ *size = dispc.fb_sram_size + dispc.fb_sdram_size;
+ *virt = dispc.fb_kern_vaddr;
+ /* Physical vram might not be contiguous. No one except own mmap
+ * should use this addr.
+ */
+ *phys = 0;
+}
+
+static int omap_dispc_mmap_user(struct vm_area_struct *vma)
+{
+ unsigned long len;
+ unsigned long offset;
+ unsigned long vaddr;
+ int r;
+
+ DBGPRINT(1, "vm_pgoff 0x%08lx vm_start 0x%08lx vm_end 0x%08lx\n",
+ vma->vm_pgoff, vma->vm_start, vma->vm_end);
+
+ if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+ return -EINVAL;
+ offset = vma->vm_pgoff << PAGE_SHIFT;
+
+ if (offset >= dispc.fb_sram_size + dispc.fb_sdram_size)
+ return -EINVAL;
+
+ len = vma->vm_end - vma->vm_start;
+ if (offset + len > dispc.fb_sram_size + dispc.fb_sdram_size)
+ return -EINVAL;
+
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ vma->vm_flags |= VM_PFNMAP;
+
+ vaddr = vma->vm_start;
+
+ if (dispc.fb_sram_size) {
+ if (offset < dispc.fb_sram_size) {
+ int chunk = min_t(int, dispc.fb_sram_size - offset, len);
+ DBGPRINT(1, "map sram va %08lx pa %08lx size %d\n",
+ vaddr, dispc.fb_sram_paddr + offset, chunk);
+ r = io_remap_pfn_range(vma, vaddr,
+ (dispc.fb_sram_paddr +
+ offset) >> PAGE_SHIFT, chunk,
+ vma->vm_page_prot);
+ if (r == -EINVAL)
+ return r;
+ if (r < 0)
+ return -EAGAIN;
+
+ vaddr += chunk;
+ len -= chunk;
+ offset = 0;
+ } else
+ offset -= dispc.fb_sram_size;
+ }
+
+ if (len) {
+ DBGPRINT(1, "map sdram va %08lx pa %08lx size %ld\n",
+ vaddr, dispc.fb_sdram_paddr + offset, len);
+ BUG_ON(offset > dispc.fb_sdram_size ||
+ offset + len > dispc.fb_sdram_size ||
+ vma->vm_end - vaddr != len);
+ r = io_remap_pfn_range(vma, vaddr, (dispc.fb_sdram_paddr +
+ offset) >> PAGE_SHIFT, len,
+ vma->vm_page_prot);
+ /* no teardown of the previous mapping here.
+ * do_mmap_pgoff will take core of that. */
+ if (r == -EINVAL)
+ return r;
+ if (r < 0)
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+static int mmap_kern(void)
+{
+ struct vm_struct *kvma;
+ struct vm_area_struct vma;
+ pgprot_t pgprot;
+ unsigned long vaddr;
+
+ DBGENTER(1);
+
+ kvma = get_vm_area(dispc.fb_sram_size + dispc.fb_sdram_size, VM_IOREMAP);
+ if (kvma == NULL) {
+ pr_err("can't get kernel vm area\n");
+ return -ENOMEM;
+ }
+ vma.vm_mm = &init_mm;
+
+ dispc.fb_kern_vaddr = kvma->addr;
+ vaddr = (unsigned long)kvma->addr;
+
+ pgprot = pgprot_writecombine(pgprot_kernel);
+ if (dispc.fb_sram_size) {
+ vma.vm_start = vaddr;
+ vma.vm_end = vaddr + dispc.fb_sram_size;
+ if (io_remap_pfn_range(&vma, vaddr,
+ dispc.fb_sram_paddr >> PAGE_SHIFT,
+ dispc.fb_sram_size, pgprot) < 0) {
+ pr_err("kernel mmap for FBMEM failed\n");
+ return -EAGAIN;
+ }
+ vaddr += dispc.fb_sram_size;
+ }
+ if (dispc.fb_sdram_size) {
+ vma.vm_start = vaddr;
+ vma.vm_end = vaddr + dispc.fb_sdram_size;
+ if (io_remap_pfn_range(&vma, vaddr,
+ dispc.fb_sdram_paddr >> PAGE_SHIFT,
+ dispc.fb_sdram_size, pgprot) < 0) {
+ pr_err("kernel mmap for FBMEM failed\n");
+ return -EAGAIN;
+ }
+ }
+
+ DBGLEAVE(1);
+
+ return 0;
+}
+
+static void unmap_kern(void)
+{
+ vunmap(dispc.fb_kern_vaddr);
+}
+
+static int alloc_palette_ram(void)
+{
+ dispc.palette_vaddr = dma_alloc_writecombine(dispc.fbdev->dev,
+ MAX_PALETTE_SIZE, &dispc.palette_paddr, GFP_KERNEL);
+ if (dispc.palette_vaddr == NULL) {
+ pr_err("failed to alloc palette memory\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void free_palette_ram(void)
+{
+ dma_free_writecombine(dispc.fbdev->dev, MAX_PALETTE_SIZE,
+ dispc.palette_vaddr, dispc.palette_paddr);
+}
+
+static int alloc_fbmem(int req_size)
+{
+ int frame_size;
+ struct lcd_panel *panel = dispc.fbdev->panel;
+
+ frame_size = PAGE_ALIGN(panel->x_res * panel->bpp / 8 * panel->y_res);
+ if (req_size > frame_size)
+ frame_size = req_size;
+ dispc.fb_sdram_size = PAGE_ALIGN(MAX_PALETTE_SIZE) + frame_size;
+ dispc.fb_kern_vaddr = dma_alloc_writecombine(dispc.fbdev->dev,
+ dispc.fb_sdram_size, &dispc.fb_sdram_paddr, GFP_KERNEL);
+
+ if (dispc.fb_kern_vaddr == 0) {
+ pr_err("unable to allocate fb DMA memory\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void free_fbmem(void)
+{
+ dma_free_writecombine(dispc.fbdev->dev, dispc.fb_sdram_size,
+ dispc.fb_kern_vaddr, dispc.fb_sdram_paddr);
+}
+
+static int setup_fbmem(int req_size)
+{
+ struct lcd_panel *panel = dispc.fbdev->panel;
+ struct omapfb_platform_data *conf;
+ unsigned long size_align;
+ int line_size;
+ int frame_size;
+ int lines;
+ int r;
+
+ conf = dispc.fbdev->dev->platform_data;
+
+ if (conf->fbmem.fb_sram_size + conf->fbmem.fb_sdram_size == 0) {
+ if ((r = alloc_fbmem(req_size)) < 0)
+ return r;
+ dispc.fbmem_allocated = 1;
+ dispc.fb_sdram_lines = panel->y_res;
+ return 0;
+ }
+
+ dispc.fb_sram_paddr = conf->fbmem.fb_sram_start;
+ dispc.fb_sram_size = conf->fbmem.fb_sram_size;
+ dispc.fb_sdram_paddr = conf->fbmem.fb_sdram_start;
+ dispc.fb_sdram_size = conf->fbmem.fb_sdram_size;
+
+ line_size = panel->x_res * panel->bpp / 8;
+ frame_size = PAGE_ALIGN(line_size * panel->y_res);
+
+ size_align = calc_lcm(line_size, PAGE_SIZE);
+
+ if (dispc.fb_sram_size + dispc.fb_sdram_size < frame_size ||
+ (dispc.fb_sdram_size && (dispc.fb_sram_size % size_align))) {
+ pr_err("Invalid FB memory configuration\n");
+ return -EINVAL;
+ }
+
+ if (dispc.fb_sram_size + dispc.fb_sdram_size < req_size) {
+ pr_err("%d vram was requested, but only %u is available\n",
+ req_size, dispc.fb_sram_size + dispc.fb_sdram_size);
+ }
+
+ lines = dispc.fb_sram_size / line_size;
+ lines = min_t(int, panel->y_res, lines);
+ dispc.fb_sram_lines = lines;
+ lines = panel->y_res - lines;
+ dispc.fb_sdram_lines = lines;
+
+ if ((r = mmap_kern()) < 0)
+ return r;
+
+ DBGPRINT(1, "fb_sram %08x size %08x fb_sdram %08x size %08x\n",
+ dispc.fb_sram_paddr, dispc.fb_sram_size,
+ dispc.fb_sdram_paddr, dispc.fb_sdram_size);
+
+ return 0;
+}
+
+static void cleanup_fbmem(void)
+{
+ if (dispc.fbmem_allocated)
+ free_fbmem();
+ else
+ unmap_kern();
+}
+
+static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
+ int req_vram_size)
+{
+ int r;
+ u32 l;
+ struct lcd_panel *panel = fbdev->panel;
+ int tmo = 10000;
+ int skip_init = 0;
+
+ DBGENTER(1);
+
+ memset(&dispc, 0, sizeof(dispc));
+
+ dispc.base = io_p2v(DISPC_BASE);
+ dispc.fbdev = fbdev;
+ dispc.ext_mode = ext_mode;
+
+ dispc.multiplane_head = -1;
+
+ if (fbdev->dev->platform_data == NULL) {
+ pr_err("missing FB configuration\n");
+ return -ENOENT;
+ }
+
+ init_completion(&dispc.frame_done);
+
+ if ((r = get_dss_clocks()) < 0)
+ return r;
+
+ enable_lcd_clocks(1);
+
+ l = dispc_read_reg(DISPC_REVISION);
+ pr_info(MODULE_NAME ": version %d.%d\n", l >> 4 & 0x0f, l & 0x0f);
+
+#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
+ l = dispc_read_reg(DISPC_CONTROL);
+ /* LCD enabled ? */
+ if (l & 1) {
+ pr_info(MODULE_NAME ": skipping hardware initialization\n");
+ skip_init = 1;
+ }
+#endif
+
+ if (!skip_init) {
+ /* Reset monitoring works only w/ the 54M clk */
+ enable_digit_clocks(1);
+
+ /* Soft reset */
+ MOD_REG_FLD(DISPC_SYSCONFIG, 1 << 1, 1 << 1);
+
+ while (!(dispc_read_reg(DISPC_SYSSTATUS) & 1)) {
+ if (!--tmo) {
+ pr_err("soft reset failed\n");
+ r = -ENODEV;
+ enable_digit_clocks(0);
+ goto fail1;
+ }
+ }
+
+ enable_digit_clocks(0);
+ }
+
+ l = dispc_read_reg(DISPC_IRQSTATUS);
+ dispc_write_reg(l, DISPC_IRQSTATUS);
+
+ /* Enable those that we handle always */
+ omap_dispc_enable_irqs(DISPC_IRQ_FRAMEMASK);
+
+ if ((r = request_irq(INT_24XX_DSS_IRQ, omap_dispc_irq_handler,
+ 0, MODULE_NAME, NULL)) < 0) {
+ pr_err("can't get DSS IRQ\n");
+ goto fail1;
+ }
+
+ /* L3 firewall setting: enable access to OCM RAM */
+ __raw_writel(0x402000b0, io_p2v(0x680050a0));
+
+ if ((r = alloc_palette_ram()) < 0)
+ goto fail2;
+
+ if ((r = setup_fbmem(req_vram_size)) < 0)
+ goto fail3;
+
+ if (!skip_init) {
+ memset(dispc.fb_kern_vaddr, 0,
+ dispc.fb_sram_size + dispc.fb_sdram_size);
+
+ /* Set logic clock to fck, pixel clock to fck/2 for now */
+ MOD_REG_FLD(DISPC_DIVISOR, FLD_MASK(16, 8), 1 << 16);
+ MOD_REG_FLD(DISPC_DIVISOR, FLD_MASK(0, 8), 2 << 0);
+
+ setup_plane_fifo(0);
+ setup_plane_fifo(1);
+ setup_plane_fifo(2);
+
+ set_lcd_tft_mode(panel->config & OMAP_LCDC_PANEL_TFT);
+ set_lcd_data_lines(panel->data_lines);
+ set_load_mode(DISPC_LOAD_FRAME_ONLY);
+
+ if (!ext_mode) {
+ omap_dispc_set_lcd_size(panel->x_res, panel->y_res);
+ set_lcd_timings();
+ }
+ enable_rfbi_mode(ext_mode);
+ }
+
+ return 0;
+fail3:
+ free_palette_ram();
+fail2:
+ free_irq(INT_24XX_DSS_IRQ, NULL);
+fail1:
+ enable_lcd_clocks(0);
+ put_dss_clocks();
+
+ return r;
+}
+
+static void omap_dispc_cleanup(void)
+{
+ cleanup_fbmem();
+ free_palette_ram();
+ free_irq(INT_24XX_DSS_IRQ, NULL);
+ enable_lcd_clocks(0);
+ put_dss_clocks();
+}
+
+static unsigned long omap_dispc_get_caps(void)
+{
+ return 0;
+}
+
+struct lcd_ctrl omap2_int_ctrl = {
+ .name = "internal",
+ .init = omap_dispc_init,
+ .cleanup = omap_dispc_cleanup,
+ .get_vram_layout = omap_dispc_get_vram_layout,
+ .mmap = omap_dispc_mmap_user,
+ .get_caps = omap_dispc_get_caps,
+ .set_update_mode = omap_dispc_set_update_mode,
+ .get_update_mode = omap_dispc_get_update_mode,
+ .update_window = omap_dispc_update_window,
+ .suspend = omap_dispc_suspend,
+ .resume = omap_dispc_resume,
+ .setup_plane = omap_dispc_setup_plane,
+ .enable_plane = omap_dispc_enable_plane,
+ .set_color_key = omap_dispc_set_color_key,
+};
+
+MODULE_DESCRIPTION("TI OMAP LCDC controller");
+MODULE_LICENSE("GPL");
--- /dev/null
+#ifndef _DISPC_H
+#define _DISPC_H
+
+#include <linux/interrupt.h>
+
+#define DISPC_PLANE_GFX 0
+#define DISPC_PLANE_VID1 1
+#define DISPC_PLANE_VID2 2
+
+#define DISPC_RGB_1_BPP 0x00
+#define DISPC_RGB_2_BPP 0x01
+#define DISPC_RGB_4_BPP 0x02
+#define DISPC_RGB_8_BPP 0x03
+#define DISPC_RGB_12_BPP 0x04
+#define DISPC_RGB_16_BPP 0x06
+#define DISPC_RGB_24_BPP 0x08
+#define DISPC_RGB_24_BPP_UNPACK_32 0x09
+#define DISPC_YUV2_422 0x0a
+#define DISPC_UYVY_422 0x0b
+
+#define DISPC_BURST_4x32 0
+#define DISPC_BURST_8x32 1
+#define DISPC_BURST_16x32 2
+
+#define DISPC_LOAD_CLUT_AND_FRAME 0x00
+#define DISPC_LOAD_CLUT_ONLY 0x01
+#define DISPC_LOAD_FRAME_ONLY 0x02
+#define DISPC_LOAD_CLUT_ONCE_FRAME 0x03
+
+#define DISPC_TFT_DATA_LINES_12 0
+#define DISPC_TFT_DATA_LINES_16 1
+#define DISPC_TFT_DATA_LINES_18 2
+#define DISPC_TFT_DATA_LINES_24 3
+
+extern void omap_dispc_set_lcd_size(int width, int height);
+
+extern void omap_dispc_enable_lcd_out(int enable);
+extern void omap_dispc_enable_digit_out(int enable);
+
+extern int omap_dispc_request_irq(void (*callback)(void *data), void *data);
+extern void omap_dispc_free_irq(void);
+
+#endif
--- /dev/null
+/*
+ * File: drivers/video/omap/hwa742.c
+ *
+ * Epson HWA742 LCD controller driver
+ *
+ * Copyright (C) 2004-2005 Nokia Corporation
+ * Authors: Juha Yrjölä <juha.yrjola@nokia.com>
+ * Imre Deak <imre.deak@nokia.com>
+ * YUV support: Jussi Laako <jussi.laako@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/config.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <asm/arch/dma.h>
+#include <asm/arch/omapfb.h>
+
+/* #define OMAPFB_DBG 1 */
+
+#include "debug.h"
+
+#define MODULE_NAME "omapfb-hwa742"
+
+#define HWA742_REV_CODE_REG 0x0
+#define HWA742_CONFIG_REG 0x2
+#define HWA742_PLL_DIV_REG 0x4
+#define HWA742_PLL_0_REG 0x6
+#define HWA742_PLL_1_REG 0x8
+#define HWA742_PLL_2_REG 0xa
+#define HWA742_PLL_3_REG 0xc
+#define HWA742_PLL_4_REG 0xe
+#define HWA742_CLK_SRC_REG 0x12
+#define HWA742_PANEL_TYPE_REG 0x14
+#define HWA742_H_DISP_REG 0x16
+#define HWA742_H_NDP_REG 0x18
+#define HWA742_V_DISP_1_REG 0x1a
+#define HWA742_V_DISP_2_REG 0x1c
+#define HWA742_V_NDP_REG 0x1e
+#define HWA742_HS_W_REG 0x20
+#define HWA742_HP_S_REG 0x22
+#define HWA742_VS_W_REG 0x24
+#define HWA742_VP_S_REG 0x26
+#define HWA742_PCLK_POL_REG 0x28
+#define HWA742_INPUT_MODE_REG 0x2a
+#define HWA742_TRANSL_MODE_REG1 0x2e
+#define HWA742_DISP_MODE_REG 0x34
+#define HWA742_WINDOW_TYPE 0x36
+#define HWA742_WINDOW_X_START_0 0x38
+#define HWA742_WINDOW_X_START_1 0x3a
+#define HWA742_WINDOW_Y_START_0 0x3c
+#define HWA742_WINDOW_Y_START_1 0x3e
+#define HWA742_WINDOW_X_END_0 0x40
+#define HWA742_WINDOW_X_END_1 0x42
+#define HWA742_WINDOW_Y_END_0 0x44
+#define HWA742_WINDOW_Y_END_1 0x46
+#define HWA742_MEMORY_WRITE_LSB 0x48
+#define HWA742_MEMORY_WRITE_MSB 0x49
+#define HWA742_MEMORY_READ_0 0x4a
+#define HWA742_MEMORY_READ_1 0x4c
+#define HWA742_MEMORY_READ_2 0x4e
+#define HWA742_POWER_SAVE 0x56
+#define HWA742_NDP_CTRL 0x58
+
+#define HWA742_AUTO_UPDATE_TIME (HZ / 20)
+
+#define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
+
+/* Reserve 4 request slots for requests in irq context */
+#define REQ_POOL_SIZE 24
+#define IRQ_REQ_POOL_SIZE 4
+
+struct update_param {
+ int x, y, width, height;
+ int color_mode;
+ int flags;
+};
+
+#define REQ_FROM_IRQ_POOL 0x01
+
+#define REQ_COMPLETE 0
+#define REQ_PENDING 1
+
+struct hwa742_request {
+ struct list_head entry;
+ unsigned int flags;
+
+ int (*handler)(struct hwa742_request *req);
+ void (*complete)(void *data);
+ void *complete_data;
+
+ union {
+ struct update_param update;
+ struct completion *sync;
+ } par;
+};
+
+struct hwa742_struct {
+ enum omapfb_update_mode update_mode;
+ enum omapfb_update_mode update_mode_before_suspend;
+
+ struct timer_list auto_update_timer;
+ int stop_auto_update;
+ struct omapfb_update_window auto_update_window;
+
+ struct hwa742_request req_pool[REQ_POOL_SIZE];
+ struct list_head pending_req_list;
+ struct list_head free_req_list;
+ struct semaphore req_sema;
+ spinlock_t req_lock;
+
+ struct clk *sys_ck;
+ struct extif_timings reg_timings, lut_timings;
+
+ int prev_color_mode;
+ int prev_flags;
+ int window_type;
+
+ u32 max_transmit_size;
+ u32 extif_clk_period;
+
+ struct omapfb_device *fbdev;
+ struct lcd_ctrl_extif *extif;
+ struct lcd_ctrl *int_ctrl;
+} hwa742;
+
+static u8 hwa742_read_reg(u8 reg)
+{
+ u8 data;
+
+ hwa742.extif->set_bits_per_cycle(8);
+ hwa742.extif->write_command(®, 1);
+ hwa742.extif->read_data(&data, 1);
+
+ return data;
+}
+
+static void hwa742_write_reg(u8 reg, u8 data)
+{
+ hwa742.extif->set_bits_per_cycle(8);
+ hwa742.extif->write_command(®, 1);
+ hwa742.extif->write_data(&data, 1);
+}
+
+static void set_window_regs(int x_start, int y_start, int x_end, int y_end)
+{
+ u8 tmp[8];
+ u8 cmd;
+
+ x_end--;
+ y_end--;
+ tmp[0] = x_start;
+ tmp[1] = x_start >> 8;
+ tmp[2] = y_start;
+ tmp[3] = y_start >> 8;
+ tmp[4] = x_end;
+ tmp[5] = x_end >> 8;
+ tmp[6] = y_end;
+ tmp[7] = y_end >> 8;
+
+ hwa742.extif->set_bits_per_cycle(8);
+ cmd = HWA742_WINDOW_X_START_0;
+
+ hwa742.extif->write_command(&cmd, 1);
+
+ hwa742.extif->write_data(tmp, 8);
+}
+
+static void set_format_regs(int conv, int transl, int flags)
+{
+ if (flags & OMAPFB_FORMAT_FLAG_DOUBLE) {
+ hwa742.window_type = ((hwa742.window_type & 0xfc) | 0x01);
+ DBGPRINT(2, "hwa742: enabled pixel doubling\n");
+ } else {
+ hwa742.window_type = (hwa742.window_type & 0xfc);
+ DBGPRINT(2, "hwa742: disabled pixel doubling\n");
+ }
+
+ hwa742_write_reg(HWA742_INPUT_MODE_REG, conv);
+ hwa742_write_reg(HWA742_TRANSL_MODE_REG1, transl);
+ hwa742_write_reg(HWA742_WINDOW_TYPE, hwa742.window_type);
+}
+
+static inline struct hwa742_request *alloc_req(void)
+{
+ unsigned long flags;
+ struct hwa742_request *req;
+ int req_flags = 0;
+
+ if (!in_interrupt())
+ down(&hwa742.req_sema);
+ else
+ req_flags = REQ_FROM_IRQ_POOL;
+
+ spin_lock_irqsave(&hwa742.req_lock, flags);
+ BUG_ON(list_empty(&hwa742.free_req_list));
+ req = list_entry(hwa742.free_req_list.next,
+ struct hwa742_request, entry);
+ list_del(&req->entry);
+ spin_unlock_irqrestore(&hwa742.req_lock, flags);
+
+ INIT_LIST_HEAD(&req->entry);
+ req->flags = req_flags;
+
+ return req;
+}
+
+static inline void free_req(struct hwa742_request *req)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&hwa742.req_lock, flags);
+
+ list_del(&req->entry);
+ list_add(&req->entry, &hwa742.free_req_list);
+ if (!(req->flags & REQ_FROM_IRQ_POOL))
+ up(&hwa742.req_sema);
+
+ spin_unlock_irqrestore(&hwa742.req_lock, flags);
+}
+
+static void process_pending_requests(void)
+{
+ unsigned long flags;
+
+ DBGENTER(2);
+
+ spin_lock_irqsave(&hwa742.req_lock, flags);
+
+ while (!list_empty(&hwa742.pending_req_list)) {
+ struct hwa742_request *req;
+ void (*complete)(void *);
+ void *complete_data;
+
+ req = list_entry(hwa742.pending_req_list.next,
+ struct hwa742_request, entry);
+ spin_unlock_irqrestore(&hwa742.req_lock, flags);
+
+ if (req->handler(req) == REQ_PENDING)
+ return;
+
+ complete = req->complete;
+ complete_data = req->complete_data;
+ free_req(req);
+
+ if (complete)
+ complete(complete_data);
+
+ spin_lock_irqsave(&hwa742.req_lock, flags);
+ }
+
+ spin_unlock_irqrestore(&hwa742.req_lock, flags);
+
+ DBGLEAVE(2);
+}
+
+static void submit_req_list(struct list_head *head)
+{
+ unsigned long flags;
+ int process = 1;
+
+ DBGENTER(2);
+
+ spin_lock_irqsave(&hwa742.req_lock, flags);
+ if (likely(!list_empty(&hwa742.pending_req_list)))
+ process = 0;
+ list_splice_init(head, hwa742.pending_req_list.prev);
+ spin_unlock_irqrestore(&hwa742.req_lock, flags);
+
+ if (process)
+ process_pending_requests();
+
+ DBGLEAVE(2);
+}
+
+static void request_complete(void *data)
+{
+ struct hwa742_request *req = (struct hwa742_request *)data;
+ void (*complete)(void *);
+ void *complete_data;
+
+ complete = req->complete;
+ complete_data = req->complete_data;
+
+ free_req(req);
+
+ if (complete)
+ complete(complete_data);
+
+ process_pending_requests();
+}
+
+static int send_frame_handler(struct hwa742_request *req)
+{
+ struct update_param *par = &req->par.update;
+ int x = par->x;
+ int y = par->y;
+ int w = par->width;
+ int h = par->height;
+ int bpp;
+ int conv, transl;
+ unsigned long offset;
+ int color_mode = par->color_mode;
+ int flags = par->flags;
+ int scr_width = 800;
+
+ DBGPRINT(2, "x %d y %d w %d h %d scr_width %d color_mode %d flags %d\n",
+ x, y, w, h, scr_width, color_mode, flags);
+
+ switch (color_mode) {
+ case OMAPFB_COLOR_YUV422:
+ bpp = 16;
+ conv = 0x08;
+ transl = 0x25;
+ break;
+ case OMAPFB_COLOR_YUV420:
+ bpp = 12;
+ conv = 0x09;
+ transl = 0x25;
+ break;
+ case OMAPFB_COLOR_RGB565:
+ bpp = 16;
+ conv = 0x01;
+ transl = 0x05;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (hwa742.prev_flags != flags ||
+ hwa742.prev_color_mode != color_mode) {
+ set_format_regs(conv, transl, flags);
+ hwa742.prev_color_mode = color_mode;
+ hwa742.prev_flags = flags;
+ }
+
+ set_window_regs(x, y, x + w, y + h);
+
+ offset = (scr_width * y + x) * bpp / 8;
+
+ hwa742.int_ctrl->setup_plane(OMAPFB_PLANE_GFX,
+ OMAPFB_CHANNEL_OUT_LCD, offset, scr_width, 0, 0, w, h,
+ color_mode);
+
+ hwa742.extif->set_bits_per_cycle(16);
+
+ hwa742.int_ctrl->enable_plane(OMAPFB_PLANE_GFX, 1);
+ hwa742.extif->transfer_area(w, h, request_complete, req);
+
+ return REQ_PENDING;
+}
+
+static void send_frame_complete(void *data)
+{
+ hwa742.int_ctrl->enable_plane(OMAPFB_PLANE_GFX, 0);
+}
+
+#define ADD_PREQ(_x, _y, _w, _h) do { \
+ req = alloc_req(); \
+ req->handler = send_frame_handler; \
+ req->complete = send_frame_complete; \
+ req->par.update.x = _x; \
+ req->par.update.y = _y; \
+ req->par.update.width = _w; \
+ req->par.update.height = _h; \
+ req->par.update.color_mode = color_mode;\
+ req->par.update.flags = flags; \
+ list_add_tail(&req->entry, req_head); \
+} while(0)
+
+static void create_req_list(struct omapfb_update_window *win,
+ struct list_head *req_head)
+{
+ struct hwa742_request *req;
+ int x = win->x;
+ int y = win->y;
+ int width = win->width;
+ int height = win->height;
+ int color_mode;
+ int flags;
+
+ flags = win->format & OMAPFB_FORMAT_FLAG_DOUBLE;
+ color_mode = win->format & OMAPFB_FORMAT_MASK;
+
+ if (x & 1) {
+ ADD_PREQ(x, y, 1, height);
+ width--;
+ x++;
+ }
+ if (width & ~1) {
+ unsigned int xspan = width & ~1;
+ unsigned int ystart = y;
+ unsigned int yspan = height;
+
+ if (xspan * height * 2 > hwa742.max_transmit_size) {
+ yspan = hwa742.max_transmit_size / (xspan * 2);
+ ADD_PREQ(x, ystart, xspan, yspan);
+ ystart += yspan;
+ yspan = height - yspan;
+ }
+
+ ADD_PREQ(x, ystart, xspan, yspan);
+ x += xspan;
+ width -= xspan;
+ }
+ if (width)
+ ADD_PREQ(x, y, 1, height);
+}
+
+static void auto_update_complete(void *data)
+{
+ DBGENTER(2);
+
+ if (!hwa742.stop_auto_update)
+ mod_timer(&hwa742.auto_update_timer,
+ jiffies + HWA742_AUTO_UPDATE_TIME);
+
+ DBGLEAVE(2);
+}
+
+static void hwa742_update_window_auto(unsigned long arg)
+{
+ LIST_HEAD(req_list);
+ struct hwa742_request *last;
+
+ DBGENTER(2);
+
+ create_req_list(&hwa742.auto_update_window, &req_list);
+ last = list_entry(req_list.prev, struct hwa742_request, entry);
+
+ last->complete = auto_update_complete;
+ last->complete_data = NULL;
+
+ submit_req_list(&req_list);
+
+ DBGLEAVE(2);
+}
+
+int hwa742_update_window_async(struct omapfb_update_window *win,
+ void (*complete_callback)(void *arg),
+ void *complete_callback_data)
+{
+ LIST_HEAD(req_list);
+ struct hwa742_request *last;
+ int r = 0;
+
+ DBGENTER(2);
+
+ if (hwa742.update_mode != OMAPFB_MANUAL_UPDATE) {
+ DBGPRINT(1, "invalid update mode\n");
+ r = -EINVAL;
+ goto out;
+ }
+ if (unlikely(win->format & ~(0x03 | OMAPFB_FORMAT_FLAG_DOUBLE))) {
+ DBGPRINT(1, "invalid window flag");
+ r = -EINVAL;
+ goto out;
+ }
+
+ create_req_list(win, &req_list);
+ last = list_entry(req_list.prev, struct hwa742_request, entry);
+
+ last->complete = complete_callback;
+ last->complete_data = (void *)complete_callback_data;
+
+ submit_req_list(&req_list);
+
+out:
+ DBGLEAVE(2);
+ return r;
+}
+EXPORT_SYMBOL(hwa742_update_window_async);
+
+static int hwa742_setup_plane(int plane, int channel_out,
+ unsigned long offset, int screen_width,
+ int pos_x, int pos_y, int width, int height,
+ int color_mode)
+{
+ if (plane != OMAPFB_PLANE_GFX ||
+ channel_out != OMAPFB_CHANNEL_OUT_LCD)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int hwa742_enable_plane(int plane, int enable)
+{
+ if (plane != 0)
+ return -EINVAL;
+
+ hwa742.int_ctrl->enable_plane(plane, enable);
+
+ return 0;
+}
+
+static int sync_handler(struct hwa742_request *req)
+{
+ complete(req->par.sync);
+ return REQ_COMPLETE;
+}
+
+static void hwa742_sync(void)
+{
+ LIST_HEAD(req_list);
+ struct hwa742_request *req;
+ struct completion comp;
+
+ DBGENTER(2);
+
+ req = alloc_req();
+
+ req->handler = sync_handler;
+ req->complete = NULL;
+ init_completion(&comp);
+ req->par.sync = ∁
+
+ list_add(&req->entry, &req_list);
+ submit_req_list(&req_list);
+
+ wait_for_completion(&comp);
+
+ DBGLEAVE(2);
+}
+
+static void hwa742_bind_client(struct omapfb_notifier_block *nb)
+{
+ DBGPRINT(1, "update_mode %d\n", hwa742.update_mode);
+ if (hwa742.update_mode == OMAPFB_MANUAL_UPDATE) {
+ omapfb_notify_clients(hwa742.fbdev, OMAPFB_EVENT_READY);
+ }
+}
+
+static int hwa742_set_update_mode(enum omapfb_update_mode mode)
+{
+ int r = 0;
+
+ DBGENTER(1);
+
+ if (mode != OMAPFB_MANUAL_UPDATE && mode != OMAPFB_AUTO_UPDATE &&
+ mode != OMAPFB_UPDATE_DISABLED) {
+ r = -EINVAL;
+ goto out;
+ }
+
+ if (mode == hwa742.update_mode)
+ goto out;
+
+ printk(KERN_INFO "hwa742: setting update mode to %s\n",
+ mode == OMAPFB_UPDATE_DISABLED ? "disabled" :
+ (mode == OMAPFB_AUTO_UPDATE ? "auto" : "manual"));
+
+ switch (hwa742.update_mode) {
+ case OMAPFB_MANUAL_UPDATE:
+ omapfb_notify_clients(hwa742.fbdev, OMAPFB_EVENT_DISABLED);
+ break;
+ case OMAPFB_AUTO_UPDATE:
+ hwa742.stop_auto_update = 1;
+ del_timer_sync(&hwa742.auto_update_timer);
+ break;
+ case OMAPFB_UPDATE_DISABLED:
+ break;
+ }
+
+ hwa742.update_mode = mode;
+ hwa742_sync();
+ hwa742.stop_auto_update = 0;
+
+ switch (mode) {
+ case OMAPFB_MANUAL_UPDATE:
+ omapfb_notify_clients(hwa742.fbdev, OMAPFB_EVENT_READY);
+ break;
+ case OMAPFB_AUTO_UPDATE:
+ hwa742_update_window_auto(0);
+ break;
+ case OMAPFB_UPDATE_DISABLED:
+ break;
+ }
+out:
+
+ DBGLEAVE(1);
+ return r;
+}
+
+static enum omapfb_update_mode hwa742_get_update_mode(void)
+{
+ return hwa742.update_mode;
+}
+
+static unsigned long round_to_extif_ticks(unsigned long ps, int div)
+{
+ int bus_tick = hwa742.extif_clk_period * div;
+ return (ps + bus_tick - 1) / bus_tick * bus_tick;
+}
+
+static int calc_reg_timing(unsigned long sysclk, int div)
+{
+ struct extif_timings *t;
+ unsigned long systim;
+
+ /* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns,
+ * AccessTime 2 ns + 12.2 ns (regs),
+ * WEOffTime = WEOnTime + 1 ns,
+ * REOffTime = REOnTime + 16 ns (regs),
+ * CSOffTime = REOffTime + 1 ns
+ * ReadCycle = 2ns + 2*SYSCLK (regs),
+ * WriteCycle = 2*SYSCLK + 2 ns,
+ * CSPulseWidth = 10 ns */
+ systim = 1000000000 / (sysclk / 1000);
+ DBGPRINT(1, "HWA742 systim %lu ps extif_clk_period %u ps"
+ "extif_clk_div %d\n", systim, hwa742.extif_clk_period, div);
+
+ t = &hwa742.reg_timings;
+ memset(t, 0, sizeof(*t));
+ t->clk_div = div;
+ t->cs_on_time = 0;
+ t->we_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div);
+ t->re_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div);
+ t->access_time = round_to_extif_ticks(t->re_on_time + 12200, div);
+ t->we_off_time = round_to_extif_ticks(t->we_on_time + 1000, div);
+ t->re_off_time = round_to_extif_ticks(t->re_on_time + 16000, div);
+ t->cs_off_time = round_to_extif_ticks(t->re_off_time + 1000, div);
+ t->we_cycle_time = round_to_extif_ticks(2 * systim + 2000, div);
+ if (t->we_cycle_time < t->we_off_time)
+ t->we_cycle_time = t->we_off_time;
+ t->re_cycle_time = round_to_extif_ticks(2 * systim + 2000, div);
+ if (t->re_cycle_time < t->re_off_time)
+ t->re_cycle_time = t->re_off_time;
+ t->cs_pulse_width = 0;
+
+ DBGPRINT(1, "[reg]cson %d csoff %d reon %d reoff %d\n",
+ t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time);
+ DBGPRINT(1, "[reg]weon %d weoff %d recyc %d wecyc %d\n",
+ t->we_on_time, t->we_off_time, t->re_cycle_time,
+ t->we_cycle_time);
+ DBGPRINT(1, "[reg]rdaccess %d cspulse %d\n",
+ t->access_time, t->cs_pulse_width);
+
+ return hwa742.extif->convert_timings(t);
+}
+
+static int calc_lut_timing(unsigned long sysclk, int div)
+{
+ struct extif_timings *t;
+ unsigned long systim;
+
+ /* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns,
+ * AccessTime 2 ns + 4 * SYSCLK + 26 (lut),
+ * WEOffTime = WEOnTime + 1 ns,
+ * REOffTime = REOnTime + 4*SYSCLK + 26 ns (lut),
+ * CSOffTime = REOffTime + 1 ns
+ * ReadCycle = 2ns + 4*SYSCLK + 26 ns (lut),
+ * WriteCycle = 2*SYSCLK + 2 ns,
+ * CSPulseWidth = 10 ns
+ */
+ systim = 1000000000 / (sysclk / 1000);
+ DBGPRINT(1, "HWA742 systim %lu ps extif_clk_period %u ps"
+ "extif_clk_div %d\n", systim, hwa742.extif_clk_period, div);
+
+ t = &hwa742.lut_timings;
+ memset(t, 0, sizeof(*t));
+
+ t->clk_div = div;
+
+ t->cs_on_time = 0;
+ t->we_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div);
+ t->re_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div);
+ t->access_time = round_to_extif_ticks(t->re_on_time + 4 * systim +
+ 26000, div);
+ t->we_off_time = round_to_extif_ticks(t->we_on_time + 1000, div);
+ t->re_off_time = round_to_extif_ticks(t->re_on_time + 4 * systim +
+ 26000, div);
+ t->cs_off_time = round_to_extif_ticks(t->re_off_time + 1000, div);
+ t->we_cycle_time = round_to_extif_ticks(2 * systim + 2000, div);
+ if (t->we_cycle_time < t->we_off_time)
+ t->we_cycle_time = t->we_off_time;
+ t->re_cycle_time = round_to_extif_ticks(2000 + 4 * systim + 26000, div);
+ if (t->re_cycle_time < t->re_off_time)
+ t->re_cycle_time = t->re_off_time;
+ t->cs_pulse_width = 0;
+
+ DBGPRINT(1, "[lut]cson %d csoff %d reon %d reoff %d\n",
+ t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time);
+ DBGPRINT(1, "[lut]weon %d weoff %d recyc %d wecyc %d\n",
+ t->we_on_time, t->we_off_time, t->re_cycle_time,
+ t->we_cycle_time);
+ DBGPRINT(1, "[lut]rdaccess %d cspulse %d\n",
+ t->access_time, t->cs_pulse_width);
+
+ return hwa742.extif->convert_timings(t);
+}
+
+static int calc_extif_timings(unsigned long sysclk)
+{
+ int max_clk_div;
+ int div;
+
+ hwa742.extif->get_clk_info(&hwa742.extif_clk_period, &max_clk_div);
+ for (div = 1; div < max_clk_div; div++) {
+ if (calc_reg_timing(sysclk, div) == 0)
+ break;
+ }
+ if (div == max_clk_div)
+ goto err;
+
+ for (div = 1; div < max_clk_div; div++) {
+ if (calc_lut_timing(sysclk, div) == 0)
+ break;
+ }
+
+ if (div < max_clk_div)
+ return 0;
+
+err:
+ pr_err("can't setup timings\n");
+ return -1;
+}
+
+static unsigned long hwa742_get_caps(void)
+{
+ return OMAPFB_CAPS_MANUAL_UPDATE;
+}
+
+static void hwa742_suspend(void)
+{
+ hwa742.update_mode_before_suspend = hwa742.update_mode;
+ hwa742_set_update_mode(OMAPFB_UPDATE_DISABLED);
+ /* Enable sleep mode */
+ hwa742_write_reg(HWA742_POWER_SAVE, 1 << 1);
+ clk_disable(hwa742.sys_ck);
+}
+
+static void hwa742_resume(void)
+{
+ if (clk_enable(hwa742.sys_ck) != 0)
+ pr_err("failed to enable SYS clock\n");
+ /* Disable sleep mode */
+ hwa742_write_reg(HWA742_POWER_SAVE, 0);
+ while (1) {
+ /* Loop until PLL output is stabilized */
+ if (hwa742_read_reg(HWA742_PLL_DIV_REG) & (1 << 7))
+ break;
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(msecs_to_jiffies(5));
+ }
+ hwa742_set_update_mode(hwa742.update_mode_before_suspend);
+}
+
+struct lcd_ctrl hwa742_ctrl;
+
+static int hwa742_init(struct omapfb_device *fbdev, int ext_mode, int req_vram_size)
+{
+ int r = 0, i;
+ u8 rev, conf;
+ unsigned long sysfreq;
+ int div, nd;
+
+ DBGENTER(1);
+
+ hwa742.sys_ck = clk_get(0, "bclk");
+ if (IS_ERR(hwa742.sys_ck)) {
+ pr_err("can't get SYS clock\n");
+ return PTR_ERR(hwa742.sys_ck);
+ }
+
+ if ((r = clk_enable(hwa742.sys_ck)) != 0) {
+ pr_err("can't enable SYS clock\n");
+ clk_put(hwa742.sys_ck);
+ return r;
+ }
+
+ BUG_ON(!fbdev->ext_if || !fbdev->int_ctrl);
+
+ hwa742.fbdev = fbdev;
+ hwa742.extif = fbdev->ext_if;
+ hwa742.int_ctrl = fbdev->int_ctrl;
+
+ spin_lock_init(&hwa742.req_lock);
+
+ if ((r = hwa742.int_ctrl->init(fbdev, 1, req_vram_size)) < 0)
+ goto err1;
+
+ if ((r = hwa742.extif->init()) < 0)
+ goto err2;
+
+ hwa742_ctrl.get_vram_layout = hwa742.int_ctrl->get_vram_layout;
+ hwa742_ctrl.mmap = hwa742.int_ctrl->mmap;
+
+ sysfreq = clk_get_rate(hwa742.sys_ck);
+ if ((r = calc_extif_timings(sysfreq)) < 0)
+ goto err3;
+ hwa742.extif->set_timings(&hwa742.reg_timings);
+
+ div = (hwa742_read_reg(HWA742_PLL_DIV_REG) & 0x3f) + 1;
+
+ nd = (hwa742_read_reg(HWA742_PLL_4_REG) & 0x7f) + 1;
+
+ if ((r = calc_extif_timings(sysfreq / div * nd)) < 0)
+ goto err3;
+ hwa742.extif->set_timings(&hwa742.reg_timings);
+
+ rev = hwa742_read_reg(HWA742_REV_CODE_REG);
+ if ((rev & 0xfc) != 0x80) {
+ pr_err("invalid revision %02x\n", rev);
+ r = -ENODEV;
+ goto err3;
+ }
+
+ conf = hwa742_read_reg(HWA742_CONFIG_REG);
+ pr_info(MODULE_NAME ": Epson HWA742 LCD controller rev. %d "
+ "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07);
+
+ if (!(hwa742_read_reg(HWA742_PLL_DIV_REG) & 0x80)) {
+ pr_err("controller not initialized by the bootloader\n");
+ r = -ENODEV;
+ goto err2;
+ }
+
+ hwa742.max_transmit_size = hwa742.extif->max_transmit_size;
+
+ hwa742.update_mode = OMAPFB_UPDATE_DISABLED;
+
+ hwa742.auto_update_window.x = 0;
+ hwa742.auto_update_window.y = 0;
+ hwa742.auto_update_window.width = fbdev->panel->x_res;
+ hwa742.auto_update_window.height = fbdev->panel->y_res;
+ hwa742.auto_update_window.format = 0;
+
+ init_timer(&hwa742.auto_update_timer);
+ hwa742.auto_update_timer.function = hwa742_update_window_auto;
+ hwa742.auto_update_timer.data = 0;
+
+ hwa742.prev_color_mode = -1;
+ hwa742.prev_flags = 0;
+
+ hwa742.fbdev = fbdev;
+
+ INIT_LIST_HEAD(&hwa742.free_req_list);
+ INIT_LIST_HEAD(&hwa742.pending_req_list);
+ for (i = 0; i < ARRAY_SIZE(hwa742.req_pool); i++)
+ list_add(&hwa742.req_pool[i].entry, &hwa742.free_req_list);
+ BUG_ON(i <= IRQ_REQ_POOL_SIZE);
+ sema_init(&hwa742.req_sema, i - IRQ_REQ_POOL_SIZE);
+
+ return 0;
+err3:
+ hwa742.extif->cleanup();
+err2:
+ hwa742.int_ctrl->cleanup();
+err1:
+ clk_disable(hwa742.sys_ck);
+ clk_put(hwa742.sys_ck);
+ return r;
+}
+
+static void hwa742_cleanup(void)
+{
+ hwa742_set_update_mode(OMAPFB_UPDATE_DISABLED);
+ hwa742.extif->cleanup();
+ hwa742.int_ctrl->cleanup();
+ clk_disable(hwa742.sys_ck);
+ clk_put(hwa742.sys_ck);
+}
+
+struct lcd_ctrl hwa742_ctrl = {
+ .name = "hwa742",
+ .init = hwa742_init,
+ .cleanup = hwa742_cleanup,
+ .bind_client = hwa742_bind_client,
+ .get_caps = hwa742_get_caps,
+ .set_update_mode = hwa742_set_update_mode,
+ .get_update_mode = hwa742_get_update_mode,
+ .setup_plane = hwa742_setup_plane,
+ .enable_plane = hwa742_enable_plane,
+ .update_window = hwa742_update_window_async,
+ .sync = hwa742_sync,
+ .suspend = hwa742_suspend,
+ .resume = hwa742_resume,
+};
+
--- /dev/null
+/*
+ * File: drivers/video/omap/lcd_apollon.c
+ *
+ * LCD panel support for the Samsung OMAP2 Apollon board
+ *
+ * Copyright (C) 2005,2006 Samsung Electronics
+ * Author: Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * Derived from drivers/video/omap/lcd-h4.c
+ *
+ * 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/platform_device.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/omapfb.h>
+
+/* #define OMAPFB_DBG 1 */
+
+/* #define USE_35INCH_LCD 1 */
+
+#include "debug.h"
+
+static int apollon_panel_init(struct omapfb_device *fbdev)
+{
+ DBGENTER(1);
+ DBGLEAVE(1);
+ return 0;
+}
+
+static void apollon_panel_cleanup(void)
+{
+ DBGENTER(1);
+ DBGLEAVE(1);
+}
+
+static int apollon_panel_enable(void)
+{
+
+ DBGENTER(1);
+
+ /* configure LCD PWR_EN */
+ omap_cfg_reg(M21_242X_GPIO11);
+
+ DBGLEAVE(1);
+ return 0;
+}
+
+static void apollon_panel_disable(void)
+{
+ DBGENTER(1);
+ DBGLEAVE(1);
+}
+
+static unsigned long apollon_panel_get_caps(void)
+{
+ return 0;
+}
+
+struct lcd_panel apollon_panel = {
+ .name = "apollon",
+ .config = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC |
+ OMAP_LCDC_INV_HSYNC,
+
+ .bpp = 16,
+ .data_lines = 18,
+#ifdef USE_35INCH_LCD
+ .x_res = 240,
+ .y_res = 320,
+ .hsw = 2,
+ .hfp = 3,
+ .hbp = 9,
+ .vsw = 4,
+ .vfp = 3,
+ .vbp = 5,
+#else
+ .x_res = 480,
+ .y_res = 272,
+ .hsw = 41,
+ .hfp = 2,
+ .hbp = 2,
+ .vsw = 10,
+ .vfp = 2,
+ .vbp = 2,
+#endif
+ .pixel_clock = 6250,
+
+ .init = apollon_panel_init,
+ .cleanup = apollon_panel_cleanup,
+ .enable = apollon_panel_enable,
+ .disable = apollon_panel_disable,
+ .get_caps = apollon_panel_get_caps,
+};
+
+static int apollon_panel_probe(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ omapfb_register_panel(&apollon_panel);
+ return 0;
+}
+
+static int apollon_panel_remove(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+static int apollon_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+static int apollon_panel_resume(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+struct platform_driver apollon_panel_driver = {
+ .probe = apollon_panel_probe,
+ .remove = apollon_panel_remove,
+ .suspend = apollon_panel_suspend,
+ .resume = apollon_panel_resume,
+ .driver = {
+ .name = "apollon_lcd",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init apollon_panel_drv_init(void)
+{
+ return platform_driver_register(&apollon_panel_driver);
+}
+
+static void __exit apollon_panel_drv_exit(void)
+{
+ platform_driver_unregister(&apollon_panel_driver);
+}
+
+module_init(apollon_panel_drv_init);
+module_exit(apollon_panel_drv_exit);
--- /dev/null
+/*
+ * File: drivers/video/omap/lcd-h2.c
+ *
+ * LCD panel support for the TI OMAP H2 board
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@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/platform_device.h>
+
+#include <asm/arch/mux.h>
+#include <asm/arch/omapfb.h>
+
+/* #define OMAPFB_DBG 1 */
+
+#include "debug.h"
+#include "../drivers/ssi/omap-uwire.h"
+
+#define MODULE_NAME "omapfb-lcd_h2"
+#define TSC2101_UWIRE_CS 1
+
+#define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
+
+static int tsc2101_write_reg(int page, int reg, u16 data)
+{
+ u16 cmd;
+ int r;
+
+ DBGENTER(1);
+
+ cmd = ((page & 3) << 11) | ((reg & 0x3f) << 5);
+ if (omap_uwire_data_transfer(TSC2101_UWIRE_CS, cmd, 16, 0, NULL, 1))
+ r = -1;
+ else
+ r = omap_uwire_data_transfer(TSC2101_UWIRE_CS, data, 16, 0,
+ NULL, 0);
+
+ DBGLEAVE(1);
+ return r;
+}
+
+static int h2_panel_init(struct omapfb_device *fbdev)
+{
+ unsigned long uwire_flags;
+ DBGENTER(1);
+
+ /* Configure N15 pin to be uWire CS1 */
+ omap_cfg_reg(N15_1610_UWIRE_CS1);
+ uwire_flags = UWIRE_READ_RISING_EDGE | UWIRE_WRITE_RISING_EDGE;
+ uwire_flags |= UWIRE_FREQ_DIV_8;
+ omap_uwire_configure_mode(TSC2101_UWIRE_CS, uwire_flags);
+
+ DBGLEAVE(1);
+ return 0;
+}
+
+static void h2_panel_cleanup(void)
+{
+ DBGENTER(1);
+ DBGLEAVE(1);
+}
+
+static int h2_panel_enable(void)
+{
+ int r;
+
+ DBGENTER(1);
+
+ /* Assert LCD_EN, BKLIGHT_EN pins on LCD panel
+ * page2, GPIO config reg, GPIO(0,1) to out and asserted
+ */
+ r = tsc2101_write_reg(2, 0x23, 0xCC00) ? -1 : 0;
+
+ DBGLEAVE(1);
+ return r;
+}
+
+static void h2_panel_disable(void)
+{
+ DBGENTER(1);
+
+ /* Deassert LCD_EN and BKLIGHT_EN pins on LCD panel
+ * page2, GPIO config reg, GPIO(0,1) to out and deasserted
+ */
+ if (tsc2101_write_reg(2, 0x23, 0x8800))
+ pr_err("failed to disable LCD panel\n");
+
+ DBGLEAVE(1);
+}
+
+static unsigned long h2_panel_get_caps(void)
+{
+ return 0;
+}
+
+struct lcd_panel h2_panel = {
+ .name = "h2",
+ .config = OMAP_LCDC_PANEL_TFT,
+
+ .bpp = 16,
+ .data_lines = 16,
+ .x_res = 240,
+ .y_res = 320,
+ .pixel_clock = 5000,
+ .hsw = 12,
+ .hfp = 12,
+ .hbp = 46,
+ .vsw = 1,
+ .vfp = 1,
+ .vbp = 0,
+
+ .init = h2_panel_init,
+ .cleanup = h2_panel_cleanup,
+ .enable = h2_panel_enable,
+ .disable = h2_panel_disable,
+ .get_caps = h2_panel_get_caps,
+};
+
+static int h2_panel_probe(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ omapfb_register_panel(&h2_panel);
+ return 0;
+}
+
+static int h2_panel_remove(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+static int h2_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+static int h2_panel_resume(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+struct platform_driver h2_panel_driver = {
+ .probe = h2_panel_probe,
+ .remove = h2_panel_remove,
+ .suspend = h2_panel_suspend,
+ .resume = h2_panel_resume,
+ .driver = {
+ .name = "lcd_h2",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int h2_panel_drv_init(void)
+{
+ return platform_driver_register(&h2_panel_driver);
+}
+
+static void h2_panel_drv_cleanup(void)
+{
+ platform_driver_unregister(&h2_panel_driver);
+}
+
+module_init(h2_panel_drv_init);
+module_exit(h2_panel_drv_cleanup);
+
--- /dev/null
+/*
+ * File: drivers/video/omap/lcd-h3.c
+ *
+ * LCD panel support for the TI OMAP H3 board
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@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/platform_device.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/tps65010.h>
+#include <asm/arch/omapfb.h>
+
+/* #define OMAPFB_DBG 1 */
+
+#include "debug.h"
+
+#define MODULE_NAME "omapfb-lcd_h3"
+
+#define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
+
+static int h3_panel_init(struct omapfb_device *fbdev)
+{
+ DBGENTER(1);
+ DBGLEAVE(1);
+ return 0;
+}
+
+static void h3_panel_cleanup(void)
+{
+ DBGENTER(1);
+ DBGLEAVE(1);
+}
+
+static int h3_panel_enable(void)
+{
+ int r = 0;
+
+ DBGENTER(1);
+
+ /* GPIO1 and GPIO2 of TPS65010 send LCD_ENBKL and LCD_ENVDD signals */
+ r = tps65010_set_gpio_out_value(GPIO1, HIGH);
+ if (!r)
+ r = tps65010_set_gpio_out_value(GPIO2, HIGH);
+ if (r)
+ pr_err("Unable to turn on LCD panel\n");
+
+ DBGLEAVE(1);
+ return r;
+}
+
+static void h3_panel_disable(void)
+{
+ int r = 0;
+
+ DBGENTER(1);
+
+ /* GPIO1 and GPIO2 of TPS65010 send LCD_ENBKL and LCD_ENVDD signals */
+ r = tps65010_set_gpio_out_value(GPIO1, LOW);
+ if (!r)
+ tps65010_set_gpio_out_value(GPIO2, LOW);
+ if (r)
+ pr_err("Unable to turn off LCD panel\n");
+
+ DBGLEAVE(1);
+}
+
+static unsigned long h3_panel_get_caps(void)
+{
+ return 0;
+}
+
+struct lcd_panel h3_panel = {
+ .name = "h3",
+ .config = OMAP_LCDC_PANEL_TFT,
+
+ .data_lines = 16,
+ .bpp = 16,
+ .x_res = 240,
+ .y_res = 320,
+ .pixel_clock = 12000,
+ .hsw = 12,
+ .hfp = 14,
+ .hbp = 72 - 12,
+ .vsw = 1,
+ .vfp = 1,
+ .vbp = 0,
+ .pcd = 0,
+
+ .init = h3_panel_init,
+ .cleanup = h3_panel_cleanup,
+ .enable = h3_panel_enable,
+ .disable = h3_panel_disable,
+ .get_caps = h3_panel_get_caps,
+};
+
+static int h3_panel_probe(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ omapfb_register_panel(&h3_panel);
+ return 0;
+}
+
+static int h3_panel_remove(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+static int h3_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+static int h3_panel_resume(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+struct platform_driver h3_panel_driver = {
+ .probe = h3_panel_probe,
+ .remove = h3_panel_remove,
+ .suspend = h3_panel_suspend,
+ .resume = h3_panel_resume,
+ .driver = {
+ .name = "lcd_h3",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int h3_panel_drv_init(void)
+{
+ return platform_driver_register(&h3_panel_driver);
+}
+
+static void h3_panel_drv_cleanup(void)
+{
+ platform_driver_unregister(&h3_panel_driver);
+}
+
+module_init(h3_panel_drv_init);
+module_exit(h3_panel_drv_cleanup);
+
--- /dev/null
+/*
+ * File: drivers/video/omap/lcd-h4.c
+ *
+ * LCD panel support for the TI OMAP H4 board
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@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/platform_device.h>
+
+#include <asm/arch/omapfb.h>
+
+/* #define OMAPFB_DBG 1 */
+
+#include "debug.h"
+
+static int h4_panel_init(struct omapfb_device *fbdev)
+{
+ DBGENTER(1);
+ DBGLEAVE(1);
+ return 0;
+}
+
+static void h4_panel_cleanup(void)
+{
+ DBGENTER(1);
+ DBGLEAVE(1);
+}
+
+static int h4_panel_enable(void)
+{
+
+ DBGENTER(1);
+ DBGLEAVE(1);
+ return 0;
+}
+
+static void h4_panel_disable(void)
+{
+ DBGENTER(1);
+ DBGLEAVE(1);
+}
+
+static unsigned long h4_panel_get_caps(void)
+{
+ return 0;
+}
+
+struct lcd_panel h4_panel = {
+ .name = "h4",
+ .config = OMAP_LCDC_PANEL_TFT,
+
+ .bpp = 16,
+ .data_lines = 16,
+ .x_res = 240,
+ .y_res = 320,
+ .pixel_clock = 6250,
+ .hsw = 15,
+ .hfp = 15,
+ .hbp = 60,
+ .vsw = 1,
+ .vfp = 1,
+ .vbp = 1,
+
+ .init = h4_panel_init,
+ .cleanup = h4_panel_cleanup,
+ .enable = h4_panel_enable,
+ .disable = h4_panel_disable,
+ .get_caps = h4_panel_get_caps,
+};
+
+static int h4_panel_probe(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ omapfb_register_panel(&h4_panel);
+ return 0;
+}
+
+static int h4_panel_remove(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+static int h4_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+static int h4_panel_resume(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+struct platform_driver h4_panel_driver = {
+ .probe = h4_panel_probe,
+ .remove = h4_panel_remove,
+ .suspend = h4_panel_suspend,
+ .resume = h4_panel_resume,
+ .driver = {
+ .name = "lcd_h4",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int h4_panel_drv_init(void)
+{
+ return platform_driver_register(&h4_panel_driver);
+}
+
+static void h4_panel_drv_cleanup(void)
+{
+ platform_driver_unregister(&h4_panel_driver);
+}
+
+module_init(h4_panel_drv_init);
+module_exit(h4_panel_drv_cleanup);
+
--- /dev/null
+/*
+ * File: drivers/video/omap/lcd-inn1510.c
+ *
+ * LCD panel support for the TI OMAP1510 Innovator board
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@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/platform_device.h>
+
+#include <asm/io.h>
+
+#include <asm/arch/fpga.h>
+#include <asm/arch/omapfb.h>
+
+/* #define OMAPFB_DBG 1 */
+
+#include "debug.h"
+
+static int innovator1510_panel_init(struct omapfb_device *fbdev)
+{
+ DBGENTER(1);
+ DBGLEAVE(1);
+ return 0;
+}
+
+static void innovator1510_panel_cleanup(void)
+{
+ DBGENTER(1);
+ DBGLEAVE(1);
+}
+
+static int innovator1510_panel_enable(void)
+{
+ DBGENTER(1);
+
+ fpga_write(0x7, OMAP1510_FPGA_LCD_PANEL_CONTROL);
+
+ DBGLEAVE(1);
+ return 0;
+}
+
+static void innovator1510_panel_disable(void)
+{
+ DBGENTER(1);
+
+ fpga_write(0x0, OMAP1510_FPGA_LCD_PANEL_CONTROL);
+
+ DBGLEAVE(1);
+}
+
+static unsigned long innovator1510_panel_get_caps(void)
+{
+ return 0;
+}
+
+struct lcd_panel innovator1510_panel = {
+ .name = "inn1510",
+ .config = OMAP_LCDC_PANEL_TFT,
+
+ .bpp = 16,
+ .data_lines = 16,
+ .x_res = 240,
+ .y_res = 320,
+ .pixel_clock = 12500,
+ .hsw = 40,
+ .hfp = 40,
+ .hbp = 72,
+ .vsw = 1,
+ .vfp = 1,
+ .vbp = 0,
+ .pcd = 12,
+
+ .init = innovator1510_panel_init,
+ .cleanup = innovator1510_panel_cleanup,
+ .enable = innovator1510_panel_enable,
+ .disable = innovator1510_panel_disable,
+ .get_caps = innovator1510_panel_get_caps,
+};
+
+static int innovator1510_panel_probe(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ omapfb_register_panel(&innovator1510_panel);
+ return 0;
+}
+
+static int innovator1510_panel_remove(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+static int innovator1510_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+static int innovator1510_panel_resume(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+struct platform_driver innovator1510_panel_driver = {
+ .probe = innovator1510_panel_probe,
+ .remove = innovator1510_panel_remove,
+ .suspend = innovator1510_panel_suspend,
+ .resume = innovator1510_panel_resume,
+ .driver = {
+ .name = "lcd_inn1510",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int innovator1510_panel_drv_init(void)
+{
+ return platform_driver_register(&innovator1510_panel_driver);
+}
+
+static void innovator1510_panel_drv_cleanup(void)
+{
+ platform_driver_unregister(&innovator1510_panel_driver);
+}
+
+module_init(innovator1510_panel_drv_init);
+module_exit(innovator1510_panel_drv_cleanup);
+
--- /dev/null
+/*
+ * File: drivers/video/omap/lcd-inn1610.c
+ *
+ * LCD panel support for the TI OMAP1610 Innovator board
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@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/platform_device.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/omapfb.h>
+
+/* #define OMAPFB_DBG 1 */
+
+#include "debug.h"
+
+#define MODULE_NAME "omapfb-lcd_h3"
+
+#define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
+
+static int innovator1610_panel_init(struct omapfb_device *fbdev)
+{
+ int r = 0;
+
+ DBGENTER(1);
+
+ if (omap_request_gpio(14)) {
+ pr_err("can't request GPIO 14\n");
+ r = -1;
+ goto exit;
+ }
+ if (omap_request_gpio(15)) {
+ pr_err("can't request GPIO 15\n");
+ omap_free_gpio(14);
+ r = -1;
+ goto exit;
+ }
+ /* configure GPIO(14, 15) as outputs */
+ omap_set_gpio_direction(14, 0);
+ omap_set_gpio_direction(15, 0);
+exit:
+ DBGLEAVE(1);
+ return r;
+}
+
+static void innovator1610_panel_cleanup(void)
+{
+ DBGENTER(1);
+
+ omap_free_gpio(15);
+ omap_free_gpio(14);
+
+ DBGLEAVE(1);
+}
+
+static int innovator1610_panel_enable(void)
+{
+ DBGENTER(1);
+
+ /* set GPIO14 and GPIO15 high */
+ omap_set_gpio_dataout(14, 1);
+ omap_set_gpio_dataout(15, 1);
+
+ DBGLEAVE(1);
+ return 0;
+}
+
+static void innovator1610_panel_disable(void)
+{
+ DBGENTER(1);
+
+ /* set GPIO13, GPIO14 and GPIO15 low */
+ omap_set_gpio_dataout(14, 0);
+ omap_set_gpio_dataout(15, 0);
+
+ DBGLEAVE(1);
+}
+
+static unsigned long innovator1610_panel_get_caps(void)
+{
+ return 0;
+}
+
+struct lcd_panel innovator1610_panel = {
+ .name = "inn1610",
+ .config = OMAP_LCDC_PANEL_TFT,
+
+ .bpp = 16,
+ .data_lines = 16,
+ .x_res = 320,
+ .y_res = 240,
+ .pixel_clock = 12500,
+ .hsw = 40,
+ .hfp = 40,
+ .hbp = 72,
+ .vsw = 1,
+ .vfp = 1,
+ .vbp = 0,
+ .pcd = 12,
+
+ .init = innovator1610_panel_init,
+ .cleanup = innovator1610_panel_cleanup,
+ .enable = innovator1610_panel_enable,
+ .disable = innovator1610_panel_disable,
+ .get_caps = innovator1610_panel_get_caps,
+};
+
+static int innovator1610_panel_probe(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ omapfb_register_panel(&innovator1610_panel);
+ return 0;
+}
+
+static int innovator1610_panel_remove(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+static int innovator1610_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+static int innovator1610_panel_resume(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+struct platform_driver innovator1610_panel_driver = {
+ .probe = innovator1610_panel_probe,
+ .remove = innovator1610_panel_remove,
+ .suspend = innovator1610_panel_suspend,
+ .resume = innovator1610_panel_resume,
+ .driver = {
+ .name = "lcd_inn1610",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int innovator1610_panel_drv_init(void)
+{
+ return platform_driver_register(&innovator1610_panel_driver);
+}
+
+static void innovator1610_panel_drv_cleanup(void)
+{
+ platform_driver_unregister(&innovator1610_panel_driver);
+}
+
+module_init(innovator1610_panel_drv_init);
+module_exit(innovator1610_panel_drv_cleanup);
+
--- /dev/null
+#include <linux/module.h>
+#include <linux/delay.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/board.h>
+#include <asm/arch/omapfb.h>
+#include <asm/arch/lcd_lph8923.h>
+
+#include <linux/spi/spi.h>
+#include <asm/arch/mcspi.h>
+
+#include "../../cbus/tahvo.h"
+
+/* #define OMAPFB_DBG 1 */
+
+#include "debug.h"
+
+#define LPH8923_MODULE_NAME "lcd_lph8923"
+
+#define LPH8923_VER_BUGGY 1
+#define LPH8923_VER_NON_BUGGY 3
+
+struct {
+ int enabled;
+ int version;
+
+ u8 display_id[3];
+ unsigned int saved_bklight_level;
+ unsigned long hw_guard_end; /* next value of jiffies
+ when we can issue the
+ next sleep in/out command */
+ unsigned long hw_guard_wait; /* max guard time in jiffies */
+ struct omapfb_device *fbdev;
+ struct spi_device *spi;
+} lph8923;
+
+#define LPH8923_CMD_READ_DISP_ID 0x04
+#define LPH8923_CMD_READ_RED 0x06
+#define LPH8923_CMD_READ_GREEN 0x07
+#define LPH8923_CMD_READ_BLUE 0x08
+#define LPH8923_CMD_READ_DISP_STATUS 0x09
+#define LPH8923_CMD_SLEEP_IN 0x10
+#define LPH8923_CMD_SLEEP_OUT 0x11
+#define LPH8923_CMD_DISP_OFF 0x28
+#define LPH8923_CMD_DISP_ON 0x29
+
+static struct lcd_panel lph8923_panel;
+
+#define LPH8923_SPEED_HZ 12000000
+
+static int lph8923_spi_probe(struct spi_device *spi)
+{
+ DBGENTER(1);
+
+ spi->dev.power.power_state = PMSG_ON;
+ spi->mode = SPI_MODE_0;
+ spi->bits_per_word = 9;
+ spi_setup(spi);
+
+ DBGPRINT(1, "spi %p\n", spi);
+ lph8923.spi = spi;
+
+ omapfb_register_panel(&lph8923_panel);
+
+ return 0;
+}
+
+static int lph8923_spi_remove(struct spi_device *spi)
+{
+ DBGENTER(1);
+
+ lph8923.spi = NULL;
+
+ return 0;
+}
+
+static struct spi_driver lph8923_spi_driver = {
+ .driver = {
+ .name = LPH8923_MODULE_NAME,
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = lph8923_spi_probe,
+ .remove = __devexit_p(lph8923_spi_remove),
+};
+
+static int lph8923_drv_init(void)
+{
+ spi_register_driver(&lph8923_spi_driver);
+
+ return 0;
+}
+module_init(lph8923_drv_init);
+
+static void lph8923_drv_cleanup(void)
+{
+ spi_unregister_driver(&lph8923_spi_driver);
+}
+module_exit(lph8923_drv_cleanup);
+
+static void set_spi_data_width(int width)
+{
+ if (lph8923.spi->bits_per_word != width) {
+ lph8923.spi->bits_per_word = width;
+ spi_setup(lph8923.spi);
+ }
+}
+
+static void lph8923_read(int cmd, u8 *buf, int len)
+{
+ struct spi_message m;
+ struct spi_transfer t;
+ u16 w;
+
+ BUG_ON(lph8923.spi == NULL);
+
+ spi_message_init(&m);
+ m.spi = lph8923.spi;
+
+ if (len > 1) {
+ cmd <<= 1;
+ set_spi_data_width(10);
+ } else
+ set_spi_data_width(9);
+
+ w = cmd;
+ t.cs_change = len ? 1 : 0;
+ t.tx_buf = &w;
+ t.rx_buf = NULL;
+ t.len = 2;
+
+ spi_message_add_tail(&t, &m);
+
+ spi_sync(m.spi, &m);
+
+ if (!len)
+ return;
+
+ spi_message_init(&m);
+ m.spi = lph8923.spi;
+
+ t.cs_change = 0;
+ t.tx_buf = NULL;
+ t.rx_buf = buf;
+ t.len = len;
+
+ set_spi_data_width(8);
+
+ spi_message_add_tail(&t, &m);
+
+ spi_sync(m.spi, &m);
+}
+
+static void lph8923_write(int cmd, const u8 *buf, int len)
+{
+ struct spi_message m;
+ struct spi_transfer t;
+ u16 w;
+ int i;
+
+ BUG_ON(lph8923.spi == NULL);
+
+ spi_message_init(&m);
+ m.spi = lph8923.spi;
+ set_spi_data_width(9);
+
+ t.cs_change = 0;
+ w = cmd;
+ t.tx_buf = &w;
+ t.rx_buf = NULL;
+ t.len = 2;
+
+ spi_message_add_tail(&t, &m);
+ spi_sync(m.spi, &m);
+
+ if (!len)
+ return;
+
+ t.tx_buf = &w;
+ for (i = 0; i < len; i++) {
+ spi_message_init(&m);
+ m.spi = lph8923.spi;
+ spi_message_add_tail(&t, &m);
+ w = buf[i] | (1 << 8);
+ spi_sync(m.spi, &m);
+ }
+}
+
+static inline void lph8923_cmd(int cmd)
+{
+ lph8923_write(cmd, NULL, 0);
+}
+
+struct cmd_data {
+ u8 cmd;
+ u8 len;
+ const u8 *data;
+} __attribute__ ((packed));;
+
+static const struct cmd_data init_cmds_buggy_lph8923[] = {
+ { 0xb0, 1, "\x08" },
+ { 0xb1, 2, "\x0b\x1c" },
+ { 0xb2, 4, "\x00\x00\x00\x00" },
+ { 0xb3, 4, "\x00\x00\x00\x00" },
+ { 0xb4, 1, "\x87" },
+ { 0xb5, 4, "\x37\x07\x37\x07" },
+ { 0xb6, 2, "\x64\x24" },
+ { 0xb7, 1, "\x90" },
+ { 0xb8, 3, "\x10\x11\x20" },
+ { 0xb9, 2, "\x31\x02" },
+ { 0xba, 3, "\x04\xa3\x9d" },
+ { 0xbb, 4, "\x15\xb2\x8c\x00" },
+ { 0xc2, 3, "\x02\x00\x00" },
+};
+
+static const struct cmd_data init_cmds_non_buggy_lph8923[] = {
+ { 0xc2, 3, "\x02\x00\x00" },
+};
+
+static inline void lph8923_set_16bit_mode(void)
+{
+ lph8923_write(0x3a, "\x50", 1);
+}
+
+static void lph8923_send_init_string(void)
+{
+ int c;
+ const struct cmd_data *cd;
+
+ switch (lph8923.version) {
+ case LPH8923_VER_BUGGY:
+ c = sizeof(init_cmds_buggy_lph8923)/sizeof(init_cmds_buggy_lph8923[0]);
+ cd = init_cmds_buggy_lph8923;
+ break;
+ case LPH8923_VER_NON_BUGGY:
+ default:
+ c = sizeof(init_cmds_non_buggy_lph8923)/sizeof(init_cmds_non_buggy_lph8923[0]);
+ cd = init_cmds_non_buggy_lph8923;
+ break;
+ }
+ while (c--) {
+ lph8923_write(cd->cmd, cd->data, cd->len);
+ cd++;
+ }
+ lph8923_set_16bit_mode();
+}
+
+static void hw_guard_start(int guard_msec)
+{
+ lph8923.hw_guard_wait = msecs_to_jiffies(guard_msec);
+ lph8923.hw_guard_end = jiffies + lph8923.hw_guard_wait;
+}
+
+static void hw_guard_wait(void)
+{
+ unsigned long wait = lph8923.hw_guard_end - jiffies;
+
+ if ((long)wait > 0 && wait <= lph8923.hw_guard_wait) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(wait);
+ }
+}
+
+static void lph8923_set_sleep_mode(int on)
+{
+ int cmd, sleep_time = 5;
+
+ if (on)
+ cmd = LPH8923_CMD_SLEEP_IN;
+ else
+ cmd = LPH8923_CMD_SLEEP_OUT;
+ hw_guard_wait();
+ lph8923_cmd(cmd);
+ hw_guard_start(120);
+ /* When we enable the panel, it seems we _have_ to sleep
+ * 120 ms before sending the init string */
+ if (!on)
+ sleep_time = 120;
+ msleep(sleep_time);
+}
+
+static void lph8923_set_display_state(int enabled)
+{
+ int cmd = enabled ? LPH8923_CMD_DISP_ON : LPH8923_CMD_DISP_OFF;
+
+ lph8923_cmd(cmd);
+}
+
+static void lph8923_detect(void)
+{
+ lph8923_read(LPH8923_CMD_READ_DISP_ID, lph8923.display_id, 3);
+ printk(KERN_INFO "Moscow display id: %02x%02x%02x\n",
+ lph8923.display_id[0], lph8923.display_id[1],
+ lph8923.display_id[2]);
+
+ if (lph8923.display_id[0] == 0x45) {
+ lph8923.version = LPH8923_VER_NON_BUGGY;
+ printk(KERN_INFO "Non-buggy Moscow detected\n");
+ return;
+ } else {
+ lph8923.version = LPH8923_VER_BUGGY;
+ printk(KERN_INFO "Buggy Moscow detected\n");
+ }
+}
+
+static int lph8923_enabled(void)
+{
+ u32 disp_status;
+ int enabled;
+
+ lph8923_read(LPH8923_CMD_READ_DISP_STATUS, (u8 *)&disp_status, 4);
+ disp_status = __be32_to_cpu(disp_status);
+ enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10));
+ DBGPRINT(1, ": panel %senabled by bootloader (status 0x%04x)\n",
+ enabled ? "" : "not ", disp_status);
+ return enabled;
+}
+
+static int lph8923_panel_init(struct omapfb_device *fbdev)
+{
+ lph8923.fbdev = fbdev;
+
+ lph8923.enabled = 1;
+ lph8923_detect();
+ if (lph8923.version == LPH8923_VER_NON_BUGGY)
+ lph8923.enabled = lph8923_enabled();
+ else
+ /* We can't be sure, but assume the bootloader
+ * enabled it already */
+ lph8923.enabled = 1;
+
+ return 0;
+}
+
+static void lph8923_panel_cleanup(void)
+{
+}
+
+static int lph8923_panel_set_bklight_level(unsigned int level)
+{
+ if (level > tahvo_get_max_backlight_level())
+ return -EINVAL;
+ if (!lph8923.enabled) {
+ lph8923.saved_bklight_level = level;
+ return 0;
+ }
+ tahvo_set_backlight_level(level);
+
+ return 0;
+}
+
+static unsigned int lph8923_panel_get_bklight_level(void)
+{
+ return tahvo_get_backlight_level();
+}
+
+static unsigned int lph8923_panel_get_bklight_max(void)
+{
+ return tahvo_get_max_backlight_level();
+}
+
+static int lph8923_panel_enable(void)
+{
+ if (lph8923.enabled)
+ return 0;
+
+ lph8923_set_sleep_mode(0);
+ lph8923.enabled = 1;
+ lph8923_send_init_string();
+ lph8923_set_display_state(1);
+ lph8923_panel_set_bklight_level(lph8923.saved_bklight_level);
+
+ return 0;
+}
+
+static void lph8923_panel_disable(void)
+{
+ if (!lph8923.enabled)
+ return;
+ lph8923.saved_bklight_level = lph8923_panel_get_bklight_level();
+ lph8923_panel_set_bklight_level(0);
+ lph8923_set_display_state(0);
+ lph8923_set_sleep_mode(1);
+ lph8923.enabled = 0;
+}
+
+static unsigned long lph8923_panel_get_caps(void)
+{
+ return OMAPFB_CAPS_SET_BACKLIGHT;
+}
+
+static u16 read_first_pixel(void)
+{
+ u8 b;
+ u16 pixel;
+
+ lph8923_read(LPH8923_CMD_READ_RED, &b, 1);
+ pixel = (b >> 1) << 11;
+ lph8923_read(LPH8923_CMD_READ_GREEN, &b, 1);
+ pixel |= b << 5;
+ lph8923_read(LPH8923_CMD_READ_BLUE, &b, 1);
+ pixel |= (b >> 1);
+
+ return pixel;
+}
+
+static int lph8923_panel_test(int test_num)
+{
+ static const u16 test_values[4] = {
+ 0x0000, 0xffff, 0xaaaa, 0x5555,
+ };
+ int i;
+
+ if (test_num != LCD_LPH8923_TEST_RGB_LINES)
+ return LCD_LPH8923_TEST_INVALID;
+
+ for (i = 0; i < ARRAY_SIZE(test_values); i++) {
+ int delay;
+ unsigned long tmo;
+
+ omapfb_write_first_pixel(lph8923.fbdev, test_values[i]);
+ tmo = jiffies + msecs_to_jiffies(100);
+ delay = msecs_to_jiffies(25);
+ while (1) {
+ u16 pixel;
+
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(delay);
+ pixel = read_first_pixel();
+ if (pixel == test_values[i])
+ break;
+ if (time_after(jiffies, tmo)) {
+ printk(KERN_ERR "Moscow RGB I/F test failed: "
+ "expecting %04x, got %04x\n",
+ test_values[i], pixel);
+ return LCD_LPH8923_TEST_FAILED;
+ }
+ delay = msecs_to_jiffies(10);
+ }
+ }
+
+ return 0;
+}
+
+static struct lcd_panel lph8923_panel = {
+ .name = "lph8923",
+ .config = OMAP_LCDC_PANEL_TFT,
+
+ .bpp = 16,
+ .data_lines = 16,
+ .x_res = 800,
+ .y_res = 480,
+ .pixel_clock = 21940,
+ .hsw = 50,
+ .hfp = 20,
+ .hbp = 15,
+ .vsw = 2,
+ .vfp = 1,
+ .vbp = 3,
+
+ .init = lph8923_panel_init,
+ .cleanup = lph8923_panel_cleanup,
+ .enable = lph8923_panel_enable,
+ .disable = lph8923_panel_disable,
+ .get_caps = lph8923_panel_get_caps,
+ .set_bklight_level= lph8923_panel_set_bklight_level,
+ .get_bklight_level= lph8923_panel_get_bklight_level,
+ .get_bklight_max= lph8923_panel_get_bklight_max,
+ .run_test = lph8923_panel_test,
+};
--- /dev/null
+/*
+ * File: drivers/video/omap/lcd-osk.c
+ *
+ * LCD panel support for the TI OMAP OSK board
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ * Adapted for OSK by <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 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/platform_device.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/omapfb.h>
+
+/* #define OMAPFB_DBG 1 */
+
+#include "debug.h"
+
+static int osk_panel_init(struct omapfb_device *fbdev)
+{
+ DBGENTER(1);
+ DBGLEAVE(1);
+ return 0;
+}
+
+static void osk_panel_cleanup(void)
+{
+ DBGENTER(1);
+ DBGLEAVE(1);
+}
+
+static int osk_panel_enable(void)
+{
+ DBGENTER(1);
+
+ /* configure PWL pin */
+ omap_cfg_reg(PWL);
+
+ /* Enable PWL unit */
+ omap_writeb(0x01, OMAP16XX_PWL_CLK_ENABLE);
+
+ /* Set PWL level */
+ omap_writeb(0xFF, OMAP16XX_PWL_ENABLE);
+
+ /* configure GPIO2 as output */
+ omap_set_gpio_direction(2, 0);
+
+ /* set GPIO2 high */
+ omap_set_gpio_dataout(2, 1);
+
+ DBGLEAVE(1);
+ return 0;
+}
+
+static void osk_panel_disable(void)
+{
+ DBGENTER(1);
+
+ /* Set PWL level to zero */
+ omap_writeb(0x00, OMAP16XX_PWL_ENABLE);
+
+ /* Disable PWL unit */
+ omap_writeb(0x00, OMAP16XX_PWL_CLK_ENABLE);
+
+ /* set GPIO2 low */
+ omap_set_gpio_dataout(2, 0);
+
+ DBGLEAVE(1);
+}
+
+static unsigned long osk_panel_get_caps(void)
+{
+ return 0;
+}
+
+struct lcd_panel osk_panel = {
+ .name = "osk",
+ .config = OMAP_LCDC_PANEL_TFT,
+
+ .bpp = 16,
+ .data_lines = 16,
+ .x_res = 240,
+ .y_res = 320,
+ .pixel_clock = 12500,
+ .hsw = 40,
+ .hfp = 40,
+ .hbp = 72,
+ .vsw = 1,
+ .vfp = 1,
+ .vbp = 0,
+ .pcd = 12,
+
+ .init = osk_panel_init,
+ .cleanup = osk_panel_cleanup,
+ .enable = osk_panel_enable,
+ .disable = osk_panel_disable,
+ .get_caps = osk_panel_get_caps,
+};
+
+static int osk_panel_probe(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ omapfb_register_panel(&osk_panel);
+ return 0;
+}
+
+static int osk_panel_remove(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+static int osk_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+static int osk_panel_resume(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+struct platform_driver osk_panel_driver = {
+ .probe = osk_panel_probe,
+ .remove = osk_panel_remove,
+ .suspend = osk_panel_suspend,
+ .resume = osk_panel_resume,
+ .driver = {
+ .name = "lcd_osk",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int osk_panel_drv_init(void)
+{
+ return platform_driver_register(&osk_panel_driver);
+}
+
+static void osk_panel_drv_cleanup(void)
+{
+ platform_driver_unregister(&osk_panel_driver);
+}
+
+module_init(osk_panel_drv_init);
+module_exit(osk_panel_drv_cleanup);
+
--- /dev/null
+/*
+ * File: drivers/video/omap/lcd-p2.c
+ *
+ * LCD panel support for the TI OMAP P2 board
+ *
+ * Authors:
+ * jekyll <jekyll@mail.jekyll.idv.tw>
+ * B Jp <lastjp_fr@yahoo.fr>
+ * Brian Swetland <swetland@android.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/delay.h>
+#include <linux/platform_device.h>
+
+#include <asm/arch/mux.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/omapfb.h>
+
+/*
+ * File: epson-md-tft.h
+ *
+ * This file contains definitions for Epsons MD-TF LCD Module
+ *
+ * Copyright (C) 2004 MPC-Data Limited (http://www.mpc-data.co.uk)
+ * Author: Dave Peverley <dpeverley at mpc-data.co.uk>
+ *
+ * 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.
+ *
+ * Please report all bugs and problems to the author.
+ *
+ */
+
+/* LCD uWire commands & params
+ * All values from Epson
+ */
+#define LCD_DISON 0xAF
+#define LCD_DISOFF 0xAE
+#define LCD_DISNOR 0xA6
+#define LCD_DISINV 0xA7
+#define LCD_DISCTL 0xCA
+#define LCD_GCP64 0xCB
+#define LCD_GCP16 0xCC
+#define LCD_GSSET 0xCD
+#define LCD_SLPIN 0x95
+#define LCD_SLPOUT 0x94
+#define LCD_SD_PSET 0x75
+#define LCD_MD_PSET 0x76
+#define LCD_SD_CSET 0x15
+#define LCD_MD_CSET 0x16
+#define LCD_DATCTL 0xBC
+#define LCD_RAMWR 0x5C
+#define LCD_RAMRD 0x5D
+#define LCD_PTLIN 0xA8
+#define LCD_PTLOUT 0xA9
+#define LCD_ASCSET 0xAA
+#define LCD_SCSTART 0xAB
+#define LCD_VOLCTL 0xC6
+#define LCD_NOP 0x25
+#define LCD_OSCISEL 0x7
+#define LCD_3500KSET 0xD1
+#define LCD_3500KEND 0xD2
+#define LCD_14MSET 0xD3
+#define LCD_14MEND 0xD4
+
+#define INIT_3500KSET 0x45
+#define INIT_14MSET 0x4B
+#define INIT_DATCTL 0x08 /* 6.6.6 bits for D-Sample */
+
+#define INIT_OSCISEL 0x05
+
+#define INIT_VOLCTL 0x77 /* Nominel "volume" */
+
+#define INIT_VOLCTL_Ton 0x98 /* Activate power-IC timer */
+#define INIT_GSSET 0x00
+
+const unsigned short INIT_DISCTL[11] =
+{
+ 0xDE, 0x01, 0x64, 0x00, 0x1B, 0xF4, 0x00, 0xDC, 0x00, 0x02, 0x00
+};
+
+const unsigned short INIT_GCP64[126] =
+{
+ 0x3B,0x00,0x42,0x00,0x4A,0x00,0x51,0x00,
+ 0x58,0x00,0x5F,0x00,0x66,0x00,0x6E,0x00,
+ 0x75,0x00,0x7C,0x00,0x83,0x00,0x8A,0x00,
+ 0x92,0x00,0x99,0x00,0xA0,0x00,0xA7,0x00,
+ 0xAE,0x00,0xB6,0x00,0xBD,0x00,0xC4,0x00,
+ 0xCB,0x00,0xD2,0x00,0xDA,0x00,0xE1,0x00,
+ 0xE8,0x00,0xEF,0x00,0xF6,0x00,0xFE,0x00,
+ 0x05,0x01,0x0C,0x01,0x13,0x01,0x1A,0x01,
+ 0x22,0x01,0x29,0x01,0x30,0x01,0x37,0x01,
+ 0x3E,0x01,0x46,0x01,0x4D,0x01,0x54,0x01,
+ 0x5B,0x01,0x62,0x01,0x6A,0x01,0x71,0x01,
+ 0x78,0x01,0x7F,0x01,0x86,0x01,0x8E,0x01,
+ 0x95,0x01,0x9C,0x01,0xA3,0x01,0xAA,0x01,
+ 0xB2,0x01,0xB9,0x01,0xC0,0x01,0xC7,0x01,
+ 0xCE,0x01,0xD6,0x01,0xDD,0x01,0xE4,0x01,
+ 0xEB,0x01,0xF2,0x01,0xFA,0x01
+};
+
+const unsigned short INIT_GCP16[15] =
+{
+ 0x1A,0x31,0x48,0x54,0x5F,0x67,0x70,0x76,0x7C,0x80,0x83,0x84,0x85,0x87,0x96
+};
+
+const unsigned short INIT_MD_PSET[4] = { 0, 0, 219, 0 };
+const unsigned short INIT_MD_CSET[4] = { 2, 0, 177, 0 };
+
+const unsigned short INIT_SD_PSET[4] = { 0x00, 0x01, 0x00, 0x01 };
+const unsigned short INIT_SD_CSET[4] = { 0x00, 0x02, 0x00, 0x02 };
+
+const unsigned short INIT_ASCSET[7] = { 0x00, 0x00, 0xDB, 0x00, 0xDC, 0x00, 0x01 };
+const unsigned short INIT_SCSTART[2] = { 0x00, 0x00 };
+
+/* ----- end of epson_md_tft.h ----- */
+
+
+#include "debug.h"
+#include "../drivers/ssi/omap-uwire.h"
+
+#define LCD_UWIRE_CS 0
+
+static int p2_panel_init(struct omapfb_device *fbdev)
+{
+ DBGENTER(1);
+ DBGLEAVE(1);
+ return 0;
+}
+
+static void p2_panel_cleanup(void)
+{
+ DBGENTER(1);
+ DBGLEAVE(1);
+}
+
+static int p2_panel_enable(void)
+{
+ int i;
+ unsigned long value;
+ DBGENTER(1);
+
+ /* thwack the reset line */
+ omap_set_gpio_direction(19, 0);
+ omap_set_gpio_dataout(19, 0);
+ mdelay(2);
+ omap_set_gpio_dataout(19, 1);
+
+ /* bits 31:28 -> 0 LCD_PXL_15 .. 12 */
+ value = omap_readl(OMAP730_IO_CONF_3) & 0x0FFFFFFF;
+ omap_writel(value, OMAP730_IO_CONF_3);
+
+ /* bits 19:0 -> 0 LCD_VSYNC, AC, PXL_0, PCLK, HSYNC,
+ ** PXL_9..1, PXL_10, PXL_11
+ */
+ value = omap_readl(OMAP730_IO_CONF_4) & 0xFFF00000;
+ omap_writel(value, OMAP730_IO_CONF_4);
+
+ omap_uwire_configure_mode(0,16);
+
+ omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_DISOFF, 9, 0,NULL,1);
+ omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_SLPIN, 9, 0,NULL,1);
+ omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_DISNOR, 9, 0,NULL,1);
+ omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_GSSET, 9, 0,NULL,1);
+ omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_GSSET | 0x100), 9, 0,NULL,1);
+
+ /* DISCTL */
+ omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_DISCTL, 9, 0,NULL,1);
+ for (i = 0; i < (sizeof(INIT_DISCTL)/sizeof(unsigned short)); i++)
+ omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_DISCTL[i] | 0x100), 9, 0,NULL,1);
+
+ /* GCP64 */
+ omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_GCP64, 9, 0,NULL,1);
+ for (i = 0; i < (sizeof(INIT_GCP64)/sizeof(unsigned short)); i++)
+ omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_GCP64[i] | 0x100), 9, 0,NULL,1);
+
+ /* GCP16 */
+ omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_GCP16, 9, 0,NULL,1);
+ for (i = 0; i < (sizeof(INIT_GCP16)/sizeof(unsigned short)); i++)
+ omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_GCP16[i] | 0x100), 9, 0,NULL,1);
+
+ /* MD_CSET */
+ omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_MD_CSET, 9, 0,NULL,1);
+ for (i = 0; i < (sizeof(INIT_MD_CSET)/sizeof(unsigned short)); i++)
+ omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_MD_CSET[i] | 0x100), 9, 0,NULL,1);
+
+ /* MD_PSET */
+ omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_MD_PSET, 9, 0,NULL,1);
+ for (i = 0; i < (sizeof(INIT_MD_PSET)/sizeof(unsigned short)); i++)
+ omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_MD_PSET[i] | 0x100), 9, 0,NULL,1);
+
+ /* SD_CSET */
+ omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_SD_CSET, 9, 0,NULL,1);
+ for (i = 0; i < (sizeof(INIT_SD_CSET)/sizeof(unsigned short)); i++)
+ omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_SD_CSET[i] | 0x100), 9, 0,NULL,1);
+
+ /* SD_PSET */
+ omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_SD_PSET, 9, 0,NULL,1);
+ for (i = 0; i < (sizeof(INIT_SD_PSET)/sizeof(unsigned short)); i++)
+ omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_SD_PSET[i] | 0x100), 9, 0,NULL,1);
+
+ /* DATCTL */
+ omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_DATCTL, 9, 0,NULL,1);
+ omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_DATCTL | 0x100), 9, 0,NULL,1);
+
+ /* OSSISEL = d'5 */
+ omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_OSCISEL, 9, 0,NULL,1);
+ omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_OSCISEL | 0x100), 9, 0,NULL,1);
+
+ /* 14MSET = d'74 */
+ omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_14MSET, 9, 0,NULL,1);
+ omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_14MSET | 0x100), 9, 0,NULL,1);
+
+ /* 14MEND */
+ omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_14MEND, 9, 0,NULL,1);
+
+ /* 3500KSET = d'69 */
+ omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_3500KSET, 9, 0,NULL,1);
+ omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_3500KSET | 0x100), 9, 0,NULL,1);
+
+ /* 3500KEND */
+ omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_3500KEND, 9, 0,NULL,1);
+
+ omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_SLPOUT, 9, 0,NULL,1);
+
+ omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_VOLCTL, 9, 0,NULL,1);
+ omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_VOLCTL_Ton | 0x100), 9, 0,NULL,1);
+
+ omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_VOLCTL, 9, 0,NULL,1);
+
+ omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_VOLCTL | 0x100), 9, 0,NULL,1);
+
+ omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_DISON, 9, 0,NULL,1);
+
+ /* enable backlight */
+ omap_set_gpio_direction(134, 0);
+ omap_set_gpio_dataout(134, 1);
+
+ DBGLEAVE(1);
+ return 0;
+}
+
+static void p2_panel_disable(void)
+{
+ DBGENTER(1);
+ DBGLEAVE(1);
+}
+
+static unsigned long p2_panel_get_caps(void)
+{
+ return 0;
+}
+
+struct lcd_panel p2_panel = {
+ .name = "p2",
+ .config = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_PIX_CLOCK,
+
+ .bpp = 16,
+ .data_lines = 16,
+ .x_res = 176,
+ .y_res = 220,
+ .pixel_clock = 12500,
+ .hsw = 5,
+ .hfp = 1,
+ .hbp = 1,
+ .vsw = 2,
+ .vfp = 12,
+ .vbp = 1,
+
+ .init = p2_panel_init,
+ .cleanup = p2_panel_cleanup,
+ .enable = p2_panel_enable,
+ .disable = p2_panel_disable,
+ .get_caps = p2_panel_get_caps,
+};
+
+static int p2_panel_probe(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ omapfb_register_panel(&p2_panel);
+ return 0;
+}
+
+static int p2_panel_remove(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+static int p2_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+static int p2_panel_resume(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+struct platform_driver p2_panel_driver = {
+ .probe = p2_panel_probe,
+ .remove = p2_panel_remove,
+ .suspend = p2_panel_suspend,
+ .resume = p2_panel_resume,
+ .driver = {
+ .name = "lcd_p2",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int p2_panel_drv_init(void)
+{
+ return platform_driver_register(&p2_panel_driver);
+}
+
+static void p2_panel_drv_cleanup(void)
+{
+ platform_driver_unregister(&p2_panel_driver);
+}
+
+module_init(p2_panel_drv_init);
+module_exit(p2_panel_drv_cleanup);
+
--- /dev/null
+/*
+ * File: drivers/video/omap/lcd_palmte.c
+ *
+ * LCD panel support for the Palm Tungsten E
+ *
+ * Original version : Romain Goyet
+ * Current version : Laurent Gonzalez
+ *
+ * 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/platform_device.h>
+
+#include <asm/io.h>
+
+#include <asm/arch/fpga.h>
+#include <asm/arch/omapfb.h>
+
+/* #define OMAPFB_DBG 1 */
+
+#include "debug.h"
+
+static int palmte_panel_init(struct lcd_panel *panel)
+{
+ DBGENTER(1);
+ DBGLEAVE(1);
+ return 0;
+}
+
+static void palmte_panel_cleanup(struct lcd_panel *panel)
+{
+ DBGENTER(1);
+ DBGLEAVE(1);
+}
+
+static int palmte_panel_enable(struct lcd_panel *panel)
+{
+ DBGENTER(1);
+ DBGLEAVE(1);
+ return 0;
+}
+
+static void palmte_panel_disable(struct lcd_panel *panel)
+{
+ DBGENTER(1);
+ DBGLEAVE(1);
+}
+
+static unsigned long palmte_panel_get_caps(struct lcd_panel *panel)
+{
+ return 0;
+}
+
+struct lcd_panel palmte_panel = {
+ .name = "palmte",
+ .config = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC |
+ OMAP_LCDC_INV_HSYNC | OMAP_LCDC_HSVS_RISING_EDGE |
+ OMAP_LCDC_HSVS_OPPOSITE,
+
+ .data_lines = 16,
+ .bpp = 8,
+ .pixel_clock = 12000,
+ .x_res = 320,
+ .y_res = 320,
+ .hsw = 4,
+ .hfp = 8,
+ .hbp = 28,
+ .vsw = 1,
+ .vfp = 8,
+ .vbp = 7,
+ .pcd = 0,
+
+ .init = palmte_panel_init,
+ .cleanup = palmte_panel_cleanup,
+ .enable = palmte_panel_enable,
+ .disable = palmte_panel_disable,
+ .get_caps = palmte_panel_get_caps,
+};
+
+static int palmte_panel_probe(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ omapfb_register_panel(&palmte_panel);
+ return 0;
+}
+
+static int palmte_panel_remove(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+static int palmte_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+static int palmte_panel_resume(struct platform_device *pdev)
+{
+ DBGENTER(1);
+ return 0;
+}
+
+struct platform_driver palmte_panel_driver = {
+ .probe = palmte_panel_probe,
+ .remove = palmte_panel_remove,
+ .suspend = palmte_panel_suspend,
+ .resume = palmte_panel_resume,
+ .driver = {
+ .name = "lcd_palmte",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int palmte_panel_drv_init(void)
+{
+ return platform_driver_register(&palmte_panel_driver);
+}
+
+static void palmte_panel_drv_cleanup(void)
+{
+ platform_driver_unregister(&palmte_panel_driver);
+}
+
+module_init(palmte_panel_drv_init);
+module_exit(palmte_panel_drv_cleanup);
+
--- /dev/null
+/*
+ * File: drivers/video/omap/omap1/lcdc.c
+ *
+ * OMAP1 internal LCD controller
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@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/config.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
+#include <linux/clk.h>
+
+#include <asm/arch/dma.h>
+#include <asm/arch/omapfb.h>
+
+#include <asm/mach-types.h>
+
+/* #define OMAPFB_DBG 1 */
+
+#include "debug.h"
+
+#define MODULE_NAME "omapfb-lcdc"
+
+#define OMAP_LCDC_BASE 0xfffec000
+#define OMAP_LCDC_SIZE 256
+#define OMAP_LCDC_IRQ INT_LCD_CTRL
+
+#define OMAP_LCDC_CONTROL (OMAP_LCDC_BASE + 0x00)
+#define OMAP_LCDC_TIMING0 (OMAP_LCDC_BASE + 0x04)
+#define OMAP_LCDC_TIMING1 (OMAP_LCDC_BASE + 0x08)
+#define OMAP_LCDC_TIMING2 (OMAP_LCDC_BASE + 0x0c)
+#define OMAP_LCDC_STATUS (OMAP_LCDC_BASE + 0x10)
+#define OMAP_LCDC_SUBPANEL (OMAP_LCDC_BASE + 0x14)
+#define OMAP_LCDC_LINE_INT (OMAP_LCDC_BASE + 0x18)
+#define OMAP_LCDC_DISPLAY_STATUS (OMAP_LCDC_BASE + 0x1c)
+
+#define OMAP_LCDC_STAT_DONE (1 << 0)
+#define OMAP_LCDC_STAT_VSYNC (1 << 1)
+#define OMAP_LCDC_STAT_SYNC_LOST (1 << 2)
+#define OMAP_LCDC_STAT_ABC (1 << 3)
+#define OMAP_LCDC_STAT_LINE_INT (1 << 4)
+#define OMAP_LCDC_STAT_FUF (1 << 5)
+#define OMAP_LCDC_STAT_LOADED_PALETTE (1 << 6)
+
+#define OMAP_LCDC_CTRL_LCD_EN (1 << 0)
+#define OMAP_LCDC_CTRL_LCD_TFT (1 << 7)
+#define OMAP_LCDC_CTRL_LINE_IRQ_CLR_SEL (1 << 10)
+
+#define OMAP_LCDC_IRQ_VSYNC (1 << 2)
+#define OMAP_LCDC_IRQ_DONE (1 << 3)
+#define OMAP_LCDC_IRQ_LOADED_PALETTE (1 << 4)
+#define OMAP_LCDC_IRQ_LINE_NIRQ (1 << 5)
+#define OMAP_LCDC_IRQ_LINE (1 << 6)
+#define OMAP_LCDC_IRQ_MASK (((1 << 5) - 1) << 2)
+
+#define MAX_PALETTE_SIZE PAGE_SIZE
+
+#define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
+
+enum lcdc_load_mode {
+ OMAP_LCDC_LOAD_PALETTE,
+ OMAP_LCDC_LOAD_FRAME,
+ OMAP_LCDC_LOAD_PALETTE_AND_FRAME
+};
+
+static struct omap_lcd_controller {
+ enum omapfb_update_mode update_mode;
+ int ext_mode;
+
+ unsigned long frame_offset;
+ int screen_width;
+ int xres;
+ int yres;
+
+ enum omapfb_color_format color_mode;
+ int bpp;
+ void *palette_virt;
+ dma_addr_t palette_phys;
+ int palette_code;
+ int palette_size;
+
+ unsigned int irq_mask;
+ struct completion last_frame_complete;
+ struct completion palette_load_complete;
+ struct clk *lcd_ck;
+ struct omapfb_device *fbdev;
+
+ void (*dma_callback)(void *data);
+ void *dma_callback_data;
+
+ int fbmem_allocated;
+ dma_addr_t vram_phys;
+ void *vram_virt;
+ unsigned long vram_size;
+} omap_lcdc;
+
+static void inline enable_irqs(int mask)
+{
+ omap_lcdc.irq_mask |= mask;
+}
+
+static void inline disable_irqs(int mask)
+{
+ omap_lcdc.irq_mask &= ~mask;
+}
+
+static void set_load_mode(enum lcdc_load_mode mode)
+{
+ u32 l;
+
+ l = omap_readl(OMAP_LCDC_CONTROL);
+ l &= ~(3 << 20);
+ switch (mode) {
+ case OMAP_LCDC_LOAD_PALETTE:
+ l |= 1 << 20;
+ break;
+ case OMAP_LCDC_LOAD_FRAME:
+ l |= 2 << 20;
+ break;
+ case OMAP_LCDC_LOAD_PALETTE_AND_FRAME:
+ break;
+ default:
+ BUG();
+ }
+ omap_writel(l, OMAP_LCDC_CONTROL);
+}
+
+static void enable_controller(void)
+{
+ u32 l;
+
+ l = omap_readl(OMAP_LCDC_CONTROL);
+ l |= OMAP_LCDC_CTRL_LCD_EN;
+ l &= ~OMAP_LCDC_IRQ_MASK;
+ l |= omap_lcdc.irq_mask | OMAP_LCDC_IRQ_DONE; /* enabled IRQs */
+ omap_writel(l, OMAP_LCDC_CONTROL);
+}
+
+static void disable_controller_async(void)
+{
+ u32 l;
+ u32 mask;
+
+ l = omap_readl(OMAP_LCDC_CONTROL);
+ mask = OMAP_LCDC_CTRL_LCD_EN | OMAP_LCDC_IRQ_MASK;
+ /* Preserve the DONE mask, since we still want to get the
+ * final DONE irq. It will be disabled in the IRQ handler.
+ */
+ mask &= ~OMAP_LCDC_IRQ_DONE;
+ l &= ~mask;
+ omap_writel(l, OMAP_LCDC_CONTROL);
+}
+
+static void disable_controller(void)
+{
+ init_completion(&omap_lcdc.last_frame_complete);
+ disable_controller_async();
+ if (!wait_for_completion_timeout(&omap_lcdc.last_frame_complete,
+ msecs_to_jiffies(500)))
+ pr_err("timeout waiting for FRAME DONE\n");
+}
+
+static void reset_controller(u32 status)
+{
+ static unsigned long reset_count = 0;
+ static unsigned long last_jiffies = 0;
+
+ disable_controller_async();
+ reset_count++;
+ if (reset_count == 1 || time_after(jiffies, last_jiffies + HZ)) {
+ pr_err("resetting (status %#010x,reset count %lu)\n",
+ status, reset_count);
+ last_jiffies = jiffies;
+ }
+ if (reset_count < 100) {
+ enable_controller();
+ } else {
+ reset_count = 0;
+ pr_err("too many reset attempts, giving up.\n");
+ }
+}
+
+/* Configure the LCD DMA according to the current mode specified by parameters
+ * in omap_lcdc.fbdev and fbdev->var.
+ */
+static void setup_lcd_dma(void)
+{
+ static const int dma_elem_type[] = {
+ 0,
+ OMAP_DMA_DATA_TYPE_S8,
+ OMAP_DMA_DATA_TYPE_S16,
+ 0,
+ OMAP_DMA_DATA_TYPE_S32,
+ };
+ struct fb_var_screeninfo *var = &omap_lcdc.fbdev->fb_info->var;
+ unsigned long src;
+ int esize, xelem, yelem;
+
+ src = omap_lcdc.vram_phys + omap_lcdc.frame_offset;
+
+ switch (var->rotate) {
+ case 0:
+ if (omap_lcdc.fbdev->mirror || (src & 3) ||
+ omap_lcdc.color_mode == OMAPFB_COLOR_YUV420 ||
+ (omap_lcdc.xres & 1))
+ esize = 2;
+ else
+ esize = 4;
+ xelem = omap_lcdc.xres * omap_lcdc.bpp / 8 / esize;
+ yelem = omap_lcdc.yres;
+ break;
+ case 90:
+ case 180:
+ case 270:
+ if (cpu_is_omap15xx()) {
+ BUG();
+ }
+ esize = 2;
+ xelem = omap_lcdc.yres * omap_lcdc.bpp / 16;
+ yelem = omap_lcdc.xres;
+ break;
+ default:
+ BUG();
+ return;
+ }
+ DBGPRINT(2, "setup_dma: src %#010lx esize %d xelem %d yelem %d\n",
+ src, esize, xelem, yelem);
+ omap_set_lcd_dma_b1(src, xelem, yelem, dma_elem_type[esize]);
+ if (!cpu_is_omap15xx()) {
+ int bpp = omap_lcdc.bpp;
+
+ /* YUV support is only for external mode when we have the
+ * YUV window embedded in a 16bpp frame buffer.
+ */
+ if (omap_lcdc.color_mode == OMAPFB_COLOR_YUV420)
+ bpp = 16;
+ /* Set virtual xres elem size */
+ omap_set_lcd_dma_b1_vxres(
+ omap_lcdc.screen_width * bpp / 8 / esize);
+ /* Setup transformations */
+ omap_set_lcd_dma_b1_rotation(var->rotate);
+ omap_set_lcd_dma_b1_mirror(omap_lcdc.fbdev->mirror);
+ }
+ omap_setup_lcd_dma();
+}
+
+static irqreturn_t lcdc_irq_handler(int irq, void *dev_id, struct pt_regs *fp)
+{
+ u32 status;
+
+ status = omap_readl(OMAP_LCDC_STATUS);
+
+ if (status & (OMAP_LCDC_STAT_FUF | OMAP_LCDC_STAT_SYNC_LOST))
+ reset_controller(status);
+ else {
+ if (status & OMAP_LCDC_STAT_DONE) {
+ u32 l;
+
+ /* Disable IRQ_DONE. The status bit will be cleared
+ * only when the controller is reenabled and we don't
+ * want to get more interrupts.
+ */
+ l = omap_readl(OMAP_LCDC_CONTROL);
+ l &= ~OMAP_LCDC_IRQ_DONE;
+ omap_writel(l, OMAP_LCDC_CONTROL);
+ complete(&omap_lcdc.last_frame_complete);
+ }
+ if (status & OMAP_LCDC_STAT_LOADED_PALETTE) {
+ disable_controller_async();
+ complete(&omap_lcdc.palette_load_complete);
+ }
+ }
+
+ /* Clear these interrupt status bits.
+ * Sync_lost, FUF bits were cleared by disabling the LCD controller
+ * LOADED_PALETTE can be cleared this way only in palette only
+ * load mode. In other load modes it's cleared by disabling the
+ * controller.
+ */
+ status &= ~(OMAP_LCDC_STAT_VSYNC |
+ OMAP_LCDC_STAT_LOADED_PALETTE |
+ OMAP_LCDC_STAT_ABC |
+ OMAP_LCDC_STAT_LINE_INT);
+ omap_writel(status, OMAP_LCDC_STATUS);
+ return IRQ_HANDLED;
+}
+
+/* Change to a new video mode. We defer this to a later time to avoid any
+ * flicker and not to mess up the current LCD DMA context. For this we disable
+ * the LCD controler, which will generate a DONE irq after the last frame has
+ * been transferred. Then it'll be safe to reconfigure both the LCD controller
+ * as well as the LCD DMA.
+ */
+static int omap_lcdc_setup_plane(int plane, int channel_out,
+ unsigned long offset, int screen_width,
+ int pos_x, int pos_y, int width, int height,
+ int color_mode)
+{
+ struct fb_var_screeninfo *var = &omap_lcdc.fbdev->fb_info->var;
+ struct lcd_panel *panel = omap_lcdc.fbdev->panel;
+ int rot_x, rot_y;
+
+ DBGENTER(2);
+
+ if (var->rotate == 0) {
+ rot_x = panel->x_res;
+ rot_y = panel->y_res;
+ } else {
+ rot_x = panel->y_res;
+ rot_y = panel->x_res;
+ }
+ if (plane != 0 || channel_out != 0 || pos_x != 0 || pos_y != 0 ||
+ width > rot_x || height > rot_y) {
+ DBGPRINT(1, "invalid plane params plane %d pos_x %d "
+ "pos_y %d w %d h %d\n", plane, pos_x, pos_y,
+ width, height);
+ return -EINVAL;
+ }
+
+ omap_lcdc.frame_offset = offset;
+ omap_lcdc.xres = width;
+ omap_lcdc.yres = height;
+ omap_lcdc.screen_width = screen_width;
+ omap_lcdc.color_mode = color_mode;
+
+ switch (color_mode) {
+ case OMAPFB_COLOR_CLUT_8BPP:
+ omap_lcdc.bpp = 8;
+ omap_lcdc.palette_code = 0x3000;
+ omap_lcdc.palette_size = 512;
+ break;
+ case OMAPFB_COLOR_RGB565:
+ omap_lcdc.bpp = 16;
+ omap_lcdc.palette_code = 0x4000;
+ omap_lcdc.palette_size = 32;
+ break;
+ case OMAPFB_COLOR_YUV420:
+ if (omap_lcdc.ext_mode) {
+ omap_lcdc.bpp = 12;
+ break;
+ }
+ /* fallthrough */
+ case OMAPFB_COLOR_YUV422:
+ if (omap_lcdc.ext_mode) {
+ omap_lcdc.bpp = 16;
+ break;
+ }
+ /* fallthrough */
+ default:
+ /* FIXME: other BPPs.
+ * bpp1: code 0, size 256
+ * bpp2: code 0x1000 size 256
+ * bpp4: code 0x2000 size 256
+ * bpp12: code 0x4000 size 32
+ */
+ DBGPRINT(1, "invalid color mode %d\n", color_mode);
+ return -1;
+ }
+
+ if (omap_lcdc.ext_mode) {
+ setup_lcd_dma();
+ return 0;
+ }
+
+ if (omap_lcdc.update_mode == OMAPFB_AUTO_UPDATE) {
+ disable_controller();
+ omap_stop_lcd_dma();
+ setup_lcd_dma();
+ enable_controller();
+ }
+
+ DBGLEAVE(2);
+
+ return 0;
+}
+
+static int omap_lcdc_enable_plane(int plane, int enable)
+{
+ DBGPRINT(2, "plane %d enable %d update_mode %d ext_mode %d\n",
+ plane, enable, omap_lcdc.update_mode,
+ omap_lcdc.ext_mode);
+ if (plane != OMAPFB_PLANE_GFX)
+ return -EINVAL;
+
+ return 0;
+}
+
+/* Configure the LCD DMA for a palette load operation and do the palette
+ * downloading synchronously. We don't use the frame+palette load mode of
+ * the controller, since the palette can always be downloaded seperately.
+ */
+static void load_palette(void)
+{
+ u16 *palette;
+
+ DBGENTER(1);
+
+ palette = (u16 *)omap_lcdc.palette_virt;
+
+ *(u16 *)palette &= 0x0fff;
+ *(u16 *)palette |= omap_lcdc.palette_code;
+
+ omap_set_lcd_dma_b1(omap_lcdc.palette_phys,
+ omap_lcdc.palette_size / 4 + 1, 1, OMAP_DMA_DATA_TYPE_S32);
+
+ omap_set_lcd_dma_single_transfer(1);
+ omap_setup_lcd_dma();
+
+ init_completion(&omap_lcdc.palette_load_complete);
+ enable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);
+ set_load_mode(OMAP_LCDC_LOAD_PALETTE);
+ enable_controller();
+ if (!wait_for_completion_timeout(&omap_lcdc.palette_load_complete,
+ msecs_to_jiffies(500)))
+ pr_err("timeout waiting for FRAME DONE\n");
+ /* The controller gets disabled in the irq handler */
+ disable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);
+ omap_stop_lcd_dma();
+
+ omap_set_lcd_dma_single_transfer(omap_lcdc.ext_mode);
+
+ DBGLEAVE(1);
+}
+
+/* Used only in internal controller mode */
+static int omap_lcdc_setcolreg(u_int regno, u16 red, u16 green, u16 blue,
+ u16 transp, int update_hw_pal)
+{
+ u16 *palette;
+
+ if (omap_lcdc.color_mode != OMAPFB_COLOR_CLUT_8BPP || regno > 255)
+ return -EINVAL;
+
+ palette = (u16 *)omap_lcdc.palette_virt;
+
+ palette[regno] &= ~0x0fff;
+ palette[regno] |= ((red >> 12) << 8) | ((green >> 12) << 4 ) |
+ (blue >> 12);
+
+ if (update_hw_pal) {
+ disable_controller();
+ omap_stop_lcd_dma();
+ load_palette();
+ setup_lcd_dma();
+ set_load_mode(OMAP_LCDC_LOAD_FRAME);
+ enable_controller();
+ }
+
+ return 0;
+}
+
+static void calc_ck_div(int is_tft, int pck, int *pck_div)
+{
+ unsigned long lck;
+
+ pck = max(1, pck);
+ lck = clk_get_rate(omap_lcdc.lcd_ck);
+ *pck_div = (lck + pck - 1) / pck;
+ if (is_tft)
+ *pck_div = max(2, *pck_div);
+ else
+ *pck_div = max(3, *pck_div);
+ if (*pck_div > 255) {
+ /* FIXME: try to adjust logic clock divider as well */
+ *pck_div = 255;
+ printk(KERN_WARNING MODULE_NAME ": pixclock %d kHz too low.\n",
+ pck / 1000);
+ }
+}
+
+static void inline setup_regs(void)
+{
+ u32 l;
+ struct lcd_panel *panel = omap_lcdc.fbdev->panel;
+ int is_tft = panel->config & OMAP_LCDC_PANEL_TFT;
+ unsigned long lck;
+ int pcd;
+
+ l = omap_readl(OMAP_LCDC_CONTROL);
+ l &= ~OMAP_LCDC_CTRL_LCD_TFT;
+ l |= is_tft ? OMAP_LCDC_CTRL_LCD_TFT : 0;
+#ifdef CONFIG_MACH_OMAP_PALMTE
+/* FIXME:if (machine_is_omap_palmte()) { */
+ /* PalmTE uses alternate TFT setting in 8BPP mode */
+ l |= (is_tft && panel->bpp == 8) ? 0x810000 : 0;
+/* } */
+#endif
+ omap_writel(l, OMAP_LCDC_CONTROL);
+
+ l = omap_readl(OMAP_LCDC_TIMING2);
+ l &= ~(((1 << 6) - 1) << 20);
+ l |= (panel->config & OMAP_LCDC_SIGNAL_MASK) << 20;
+ omap_writel(l, OMAP_LCDC_TIMING2);
+
+ l = panel->x_res - 1;
+ l |= (panel->hsw - 1) << 10;
+ l |= (panel->hfp - 1) << 16;
+ l |= (panel->hbp - 1) << 24;
+ omap_writel(l, OMAP_LCDC_TIMING0);
+
+ l = panel->y_res - 1;
+ l |= (panel->vsw - 1) << 10;
+ l |= panel->vfp << 16;
+ l |= panel->vbp << 24;
+ omap_writel(l, OMAP_LCDC_TIMING1);
+
+ l = omap_readl(OMAP_LCDC_TIMING2);
+ l &= ~0xff;
+
+ lck = clk_get_rate(omap_lcdc.lcd_ck);
+
+ if (!panel->pcd)
+ calc_ck_div(is_tft, panel->pixel_clock * 1000, &pcd);
+ else {
+ printk(KERN_WARNING
+ MODULE_NAME ": Pixel clock divider value is obsolete.\n"
+ MODULE_NAME ": Try to set pixel_clock to %lu and pcd to 0 "
+ "in drivers/video/omap/lcd_%s.c and submit a patch.\n",
+ lck / panel->pcd / 1000, panel->name);
+
+ pcd = panel->pcd;
+ }
+ l |= pcd & 0xff;
+ l |= panel->acb << 8;
+ omap_writel(l, OMAP_LCDC_TIMING2);
+
+ /* update panel info with the exact clock */
+ panel->pixel_clock = lck / pcd / 1000;
+}
+
+/* Configure the LCD controller, download the color palette and start a looped
+ * DMA transfer of the frame image data. Called only in internal
+ * controller mode.
+ */
+static int omap_lcdc_set_update_mode(enum omapfb_update_mode mode)
+{
+ int r = 0;
+
+ DBGENTER(1);
+
+ if (mode != omap_lcdc.update_mode) {
+ switch (mode) {
+ case OMAPFB_AUTO_UPDATE:
+ setup_regs();
+ load_palette();
+
+ /* Setup and start LCD DMA */
+ setup_lcd_dma();
+
+ set_load_mode(OMAP_LCDC_LOAD_FRAME);
+ enable_irqs(OMAP_LCDC_IRQ_DONE);
+ /* This will start the actual DMA transfer */
+ enable_controller();
+ omap_lcdc.update_mode = mode;
+ break;
+ case OMAPFB_UPDATE_DISABLED:
+ disable_controller();
+ omap_stop_lcd_dma();
+ omap_lcdc.update_mode = mode;
+ break;
+ default:
+ r = -EINVAL;
+ }
+ }
+
+ DBGLEAVE(1);
+ return r;
+}
+
+static enum omapfb_update_mode omap_lcdc_get_update_mode(void)
+{
+ return omap_lcdc.update_mode;
+}
+
+/* PM code called only in internal controller mode */
+static void omap_lcdc_suspend(void)
+{
+ if (omap_lcdc.update_mode == OMAPFB_AUTO_UPDATE) {
+ disable_controller();
+ omap_stop_lcd_dma();
+ }
+}
+
+static void omap_lcdc_resume(void)
+{
+ if (omap_lcdc.update_mode == OMAPFB_AUTO_UPDATE) {
+ setup_regs();
+ load_palette();
+ setup_lcd_dma();
+ set_load_mode(OMAP_LCDC_LOAD_FRAME);
+ enable_irqs(OMAP_LCDC_IRQ_DONE);
+ enable_controller();
+ }
+}
+
+static unsigned long omap_lcdc_get_caps(void)
+{
+ return 0;
+}
+
+static void omap_lcdc_get_vram_layout(unsigned long *size, void **virt,
+ dma_addr_t *phys)
+{
+ *size = omap_lcdc.vram_size;
+ *virt = (u8 *)omap_lcdc.vram_virt;
+ *phys = omap_lcdc.vram_phys;
+}
+
+int omap_lcdc_set_dma_callback(void (*callback)(void *data), void *data)
+{
+ BUG_ON(callback == NULL);
+
+ if (omap_lcdc.dma_callback)
+ return -EBUSY;
+ else {
+ omap_lcdc.dma_callback = callback;
+ omap_lcdc.dma_callback_data = data;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(omap_lcdc_set_dma_callback);
+
+void omap_lcdc_free_dma_callback(void)
+{
+ omap_lcdc.dma_callback = NULL;
+}
+EXPORT_SYMBOL(omap_lcdc_free_dma_callback);
+
+static void lcdc_dma_handler(u16 status, void *data)
+{
+ DBGENTER(2);
+ if (omap_lcdc.dma_callback)
+ omap_lcdc.dma_callback(omap_lcdc.dma_callback_data);
+}
+
+static int mmap_kern(void)
+{
+ struct vm_struct *kvma;
+ struct vm_area_struct vma;
+ pgprot_t pgprot;
+ unsigned long vaddr;
+
+ DBGENTER(1);
+
+ kvma = get_vm_area(omap_lcdc.vram_size, VM_IOREMAP);
+ if (kvma == NULL) {
+ pr_err("can't get kernel vm area\n");
+ return -ENOMEM;
+ }
+ vma.vm_mm = &init_mm;
+
+ vaddr = (unsigned long)kvma->addr;
+ vma.vm_start = vaddr;
+ vma.vm_end = vaddr + omap_lcdc.vram_size;
+
+ pgprot = pgprot_writecombine(pgprot_kernel);
+ if (io_remap_pfn_range(&vma, vaddr,
+ omap_lcdc.vram_phys >> PAGE_SHIFT,
+ omap_lcdc.vram_size, pgprot) < 0) {
+ pr_err("kernel mmap for FB memory failed\n");
+ return -EAGAIN;
+ }
+
+ omap_lcdc.vram_virt = (void *)vaddr;
+
+ DBGLEAVE(1);
+
+ return 0;
+}
+
+static void unmap_kern(void)
+{
+ vunmap(omap_lcdc.vram_virt);
+}
+
+static int alloc_palette_ram(void)
+{
+ omap_lcdc.palette_virt = dma_alloc_writecombine(omap_lcdc.fbdev->dev,
+ MAX_PALETTE_SIZE, &omap_lcdc.palette_phys, GFP_KERNEL);
+ if (omap_lcdc.palette_virt == NULL) {
+ pr_err("failed to alloc palette memory\n");
+ return -ENOMEM;
+ }
+ memset(omap_lcdc.palette_virt, 0, MAX_PALETTE_SIZE);
+
+ return 0;
+}
+
+static void free_palette_ram(void)
+{
+ dma_free_writecombine(omap_lcdc.fbdev->dev, MAX_PALETTE_SIZE,
+ omap_lcdc.palette_virt, omap_lcdc.palette_phys);
+}
+
+static int alloc_fbmem(int req_size)
+{
+ int frame_size;
+ struct lcd_panel *panel = omap_lcdc.fbdev->panel;
+
+ frame_size = PAGE_ALIGN(panel->x_res * panel->bpp / 8 * panel->y_res);
+ if (req_size > frame_size)
+ frame_size = req_size;
+ omap_lcdc.vram_size = frame_size;
+ omap_lcdc.vram_virt = dma_alloc_writecombine(omap_lcdc.fbdev->dev,
+ omap_lcdc.vram_size, &omap_lcdc.vram_phys, GFP_KERNEL);
+
+ if (omap_lcdc.vram_virt == NULL) {
+ pr_err("unable to allocate FB DMA memory\n");
+ return -ENOMEM;
+ }
+
+ memset(omap_lcdc.vram_virt, 0, omap_lcdc.vram_size);
+
+ return 0;
+}
+
+static void free_fbmem(void)
+{
+ dma_free_writecombine(omap_lcdc.fbdev->dev, omap_lcdc.vram_size,
+ omap_lcdc.vram_virt, omap_lcdc.vram_phys);
+}
+
+static int setup_fbmem(int req_size)
+{
+ struct lcd_panel *panel = omap_lcdc.fbdev->panel;
+ struct omapfb_platform_data *conf;
+ int frame_size;
+ int r;
+
+ conf = omap_lcdc.fbdev->dev->platform_data;
+
+ if (conf->fbmem.fb_sram_size) {
+ pr_err("can't use FB SRAM in OMAP1\n");
+ return -EINVAL;
+ }
+
+ if (conf->fbmem.fb_sdram_size == 0) {
+ omap_lcdc.fbmem_allocated = 1;
+ if ((r = alloc_fbmem(req_size)) < 0)
+ return r;
+ return 0;
+ }
+
+ frame_size = PAGE_ALIGN(panel->x_res * panel->bpp / 8 * panel->y_res);
+
+ if (conf->fbmem.fb_sdram_size < frame_size) {
+ pr_err("invalid FB memory configuration\n");
+ return -EINVAL;
+ }
+
+ if (conf->fbmem.fb_sdram_size < req_size) {
+ pr_err("%d vram was requested, but only %u is available\n",
+ req_size, conf->fbmem.fb_sdram_size);
+ }
+
+ omap_lcdc.vram_phys = conf->fbmem.fb_sdram_start;
+ omap_lcdc.vram_size = conf->fbmem.fb_sdram_size;
+
+ if ((r = mmap_kern()) < 0)
+ return r;
+
+ DBGPRINT(1, "vram at %08x size %08lx mapped to 0x%p\n",
+ omap_lcdc.vram_phys, omap_lcdc.vram_size, omap_lcdc.vram_virt);
+
+ return 0;
+}
+
+static void cleanup_fbmem(void)
+{
+ if (omap_lcdc.fbmem_allocated)
+ free_fbmem();
+ else
+ unmap_kern();
+}
+
+static int omap_lcdc_init(struct omapfb_device *fbdev, int ext_mode,
+ int req_vram_size)
+{
+ int r;
+ u32 l;
+ int rate;
+ struct clk *tc_ck;
+
+ DBGENTER(1);
+
+ omap_lcdc.irq_mask = 0;
+
+ omap_lcdc.fbdev = fbdev;
+ omap_lcdc.ext_mode = ext_mode;
+
+ pr_info(MODULE_NAME ": init\n");
+
+ l = 0;
+ omap_writel(l, OMAP_LCDC_CONTROL);
+
+ /* FIXME:
+ * According to errata some platforms have a clock rate limitiation
+ */
+ omap_lcdc.lcd_ck = clk_get(NULL, "lcd_ck");
+ if (IS_ERR(omap_lcdc.lcd_ck)) {
+ pr_err("unable to access LCD clock\n");
+ r = PTR_ERR(omap_lcdc.lcd_ck);
+ goto fail0;
+ }
+
+ tc_ck = clk_get(NULL, "tc_ck");
+ if (IS_ERR(tc_ck)) {
+ pr_err("unable to access TC clock\n");
+ r = PTR_ERR(tc_ck);
+ goto fail1;
+ }
+
+ rate = clk_get_rate(tc_ck);
+ clk_put(tc_ck);
+
+ if (machine_is_omap_h3())
+ rate /= 3;
+ r = clk_set_rate(omap_lcdc.lcd_ck, rate);
+ if (r) {
+ pr_err("failed to adjust LCD rate\n");
+ goto fail1;
+ }
+ clk_enable(omap_lcdc.lcd_ck);
+
+ r = request_irq(OMAP_LCDC_IRQ, lcdc_irq_handler, 0, "omap-lcdc",
+ omap_lcdc.fbdev);
+ if (r) {
+ pr_err("unable to get IRQ\n");
+ goto fail2;
+ }
+
+ r = omap_request_lcd_dma(lcdc_dma_handler, NULL);
+ if (r) {
+ pr_err("unable to get LCD DMA\n");
+ goto fail3;
+ }
+
+ omap_set_lcd_dma_single_transfer(ext_mode);
+ omap_set_lcd_dma_ext_controller(ext_mode);
+
+ if (!ext_mode)
+ if ((r = alloc_palette_ram()) < 0)
+ goto fail4;
+
+ req_vram_size = 1024 * 1024;
+ if ((r = setup_fbmem(req_vram_size)) < 0)
+ goto fail5;
+
+
+ DBGLEAVE(1);
+ return 0;
+fail5:
+ if (!ext_mode)
+ free_palette_ram();
+fail4:
+ omap_free_lcd_dma();
+fail3:
+ free_irq(OMAP_LCDC_IRQ, omap_lcdc.fbdev);
+fail2:
+ clk_disable(omap_lcdc.lcd_ck);
+fail1:
+ clk_put(omap_lcdc.lcd_ck);
+fail0:
+ DBGLEAVE(1);
+ return r;
+}
+
+static void omap_lcdc_cleanup(void)
+{
+ if (!omap_lcdc.ext_mode)
+ free_palette_ram();
+ cleanup_fbmem();
+ omap_free_lcd_dma();
+ free_irq(OMAP_LCDC_IRQ, omap_lcdc.fbdev);
+ clk_disable(omap_lcdc.lcd_ck);
+ clk_put(omap_lcdc.lcd_ck);
+}
+
+struct lcd_ctrl omap1_int_ctrl = {
+ .name = "internal",
+ .init = omap_lcdc_init,
+ .cleanup = omap_lcdc_cleanup,
+ .get_vram_layout = omap_lcdc_get_vram_layout,
+ .get_caps = omap_lcdc_get_caps,
+ .set_update_mode = omap_lcdc_set_update_mode,
+ .get_update_mode = omap_lcdc_get_update_mode,
+ .update_window = NULL,
+ .suspend = omap_lcdc_suspend,
+ .resume = omap_lcdc_resume,
+ .setup_plane = omap_lcdc_setup_plane,
+ .enable_plane = omap_lcdc_enable_plane,
+ .setcolreg = omap_lcdc_setcolreg,
+};
+
+MODULE_DESCRIPTION("TI OMAP LCDC controller");
+MODULE_LICENSE("GPL");
--- /dev/null
+#ifndef LCDC_H
+#define LCDC_H
+
+int omap_lcdc_set_dma_callback(void (*callback)(void *data), void *data);
+void omap_lcdc_free_dma_callback(void);
+
+#endif
--- /dev/null
+/*
+ * File: drivers/video/omap/omapfb_main.c
+ *
+ * Framebuffer driver for TI OMAP boards
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * Acknowledgements:
+ * Alex McMains <aam@ridgerun.com> - Original driver
+ * Juha Yrjola <juha.yrjola@nokia.com> - Original driver and improvements
+ * Dirk Behme <dirk.behme@de.bosch.com> - changes for 2.6 kernel API
+ * Texas Instruments - H3 support
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/dma.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/board.h>
+#include <asm/arch/omapfb.h>
+
+/* #define OMAPFB_DBG 1 */
+
+#include "debug.h"
+
+#define OMAPFB_DRIVER "omapfb"
+#define MODULE_NAME "omapfb"
+
+#define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
+
+static unsigned int def_accel;
+static unsigned long def_vram;
+static unsigned long def_vxres;
+static unsigned long def_vyres;
+static unsigned int def_rotate;
+static unsigned int def_mirror;
+
+#ifdef CONFIG_FB_OMAP_MANUAL_UPDATE
+static int manual_update = 1;
+#else
+static int manual_update;
+#endif
+
+static struct platform_device *fbdev_pdev;
+static struct lcd_panel *fbdev_panel;
+static struct omapfb_device *omapfb_dev;
+
+static struct caps_table_struct {
+ unsigned long flag;
+ const char *name;
+} omapfb_caps_table[] = {
+ { OMAPFB_CAPS_MANUAL_UPDATE, "manual update" },
+ { OMAPFB_CAPS_SET_BACKLIGHT, "backlight setting" },
+};
+
+/*
+ * ---------------------------------------------------------------------------
+ * LCD panel
+ * ---------------------------------------------------------------------------
+ */
+extern struct lcd_ctrl omap1_int_ctrl;
+extern struct lcd_ctrl omap2_int_ctrl;
+extern struct lcd_ctrl hwa742_ctrl;
+extern struct lcd_ctrl blizzard_ctrl;
+
+static struct lcd_ctrl *ctrls[] = {
+#ifdef CONFIG_ARCH_OMAP1
+ &omap1_int_ctrl,
+#else
+ &omap2_int_ctrl,
+#endif
+
+#ifdef CONFIG_FB_OMAP_LCDC_HWA742
+ &hwa742_ctrl,
+#endif
+};
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+#ifdef CONFIG_ARCH_OMAP1
+extern struct lcd_ctrl_extif sossi_extif;
+#else
+extern struct lcd_ctrl_extif rfbi_extif;
+#endif
+#endif
+
+static void omapfb_rqueue_lock(struct omapfb_device *fbdev)
+{
+ down(&fbdev->rqueue_sema);
+}
+
+static void omapfb_rqueue_unlock(struct omapfb_device *fbdev)
+{
+ up(&fbdev->rqueue_sema);
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * LCD controller and LCD DMA
+ * ---------------------------------------------------------------------------
+ */
+/* Lookup table to map elem size to elem type. */
+static const int dma_elem_type[] = {
+ 0,
+ OMAP_DMA_DATA_TYPE_S8,
+ OMAP_DMA_DATA_TYPE_S16,
+ 0,
+ OMAP_DMA_DATA_TYPE_S32,
+};
+
+/* Allocate resources needed for LCD controller and LCD DMA operations. Video
+ * memory is allocated from system memory according to the virtual display
+ * size, except if a bigger memory size is specified explicitly as a kernel
+ * parameter.
+ */
+static int ctrl_init(struct omapfb_device *fbdev)
+{
+ int r;
+
+ DBGENTER(1);
+
+ r = fbdev->ctrl->init(fbdev, 0, def_vram);
+ if (r < 0) {
+ pr_err("controller initialization failed\n");
+ goto exit;
+ }
+
+ fbdev->ctrl->get_vram_layout(&fbdev->vram_size, &fbdev->vram_virt_base,
+ &fbdev->vram_phys_base);
+
+ DBGPRINT(1, "vram_phys %08x vram_virt %p vram_size=%lu\n",
+ fbdev->vram_phys_base, fbdev->vram_virt_base,
+ fbdev->vram_size);
+
+ DBGLEAVE(1);
+ return 0;
+exit:
+ DBGLEAVE(1);
+ return r;
+}
+
+static void ctrl_cleanup(struct omapfb_device *fbdev)
+{
+ fbdev->ctrl->cleanup();
+}
+
+static int ctrl_change_mode(struct omapfb_device *fbdev)
+{
+ int r;
+ unsigned long offset;
+ struct fb_var_screeninfo *var = &fbdev->fb_info->var;
+
+ DBGPRINT(1, "xoffset %d yoffset %d line_length %d bits_per_pixel %d\n",
+ var->xoffset, var->yoffset, fbdev->fb_info->fix.line_length,
+ var->bits_per_pixel);
+ offset = var->yoffset * fbdev->fb_info->fix.line_length +
+ var->xoffset * var->bits_per_pixel / 8;
+ r = fbdev->ctrl->setup_plane(OMAPFB_PLANE_GFX, OMAPFB_CHANNEL_OUT_LCD,
+ offset, var->xres_virtual, 0, 0, var->xres,
+ var->yres, fbdev->color_mode);
+ DBGLEAVE(1);
+
+ return r;
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * fbdev framework callbacks and the ioctl interface
+ * ---------------------------------------------------------------------------
+ */
+/* Called each time the omapfb device is opened */
+static int omapfb_open(struct fb_info *info, int user)
+{
+ DBGENTER(1);
+ DBGLEAVE(1);
+ return 0;
+}
+
+static void omapfb_sync(struct fb_info *info);
+
+/* Called when the omapfb device is closed. We make sure that any pending
+ * gfx DMA operations are ended, before we return. */
+static int omapfb_release(struct fb_info *info, int user)
+{
+ DBGENTER(1);
+
+ omapfb_sync(info);
+
+ DBGLEAVE(1);
+ return 0;
+}
+
+/* Store a single color palette entry into a pseudo palette or the hardware
+ * palette if one is available. For now we support only 16bpp and thus store
+ * the entry only to the pseudo palette.
+ */
+static int _setcolreg(struct fb_info *info, u_int regno, u_int red, u_int green,
+ u_int blue, u_int transp, int update_hw_pal)
+{
+ struct omapfb_device *fbdev = (struct omapfb_device *)info->par;
+ int r = 0;
+
+ switch (fbdev->color_mode) {
+ case OMAPFB_COLOR_YUV422:
+ case OMAPFB_COLOR_YUV420:
+ r = -EINVAL;
+ break;
+ case OMAPFB_COLOR_CLUT_8BPP:
+ case OMAPFB_COLOR_CLUT_4BPP:
+ case OMAPFB_COLOR_CLUT_2BPP:
+ case OMAPFB_COLOR_CLUT_1BPP:
+ if (fbdev->ctrl->setcolreg)
+ r = fbdev->ctrl->setcolreg(regno, red, green, blue,
+ transp, update_hw_pal);
+ /* Fallthrough */
+ case OMAPFB_COLOR_RGB565:
+ if (r != 0)
+ break;
+
+ if (regno < 0) {
+ r = -EINVAL;
+ break;
+ }
+
+ if (regno < 16) {
+ u16 pal;
+ pal = ((red >> 11) << 11) | ((green >> 10) << 5) |
+ (blue >> 11);
+ ((u32 *)(info->pseudo_palette))[regno] = pal;
+ }
+ break;
+ default:
+ BUG();
+ }
+ return r;
+}
+
+static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *info)
+{
+ int r = 0;
+
+ DBGENTER(2);
+
+ _setcolreg(info, regno, red, green, blue, transp, 1);
+
+ DBGLEAVE(2);
+
+ return r;
+}
+
+static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
+{
+ int count, index, r;
+ u16 *red, *green, *blue, *transp;
+ u16 trans = 0xffff;
+
+ red = cmap->red;
+ green = cmap->green;
+ blue = cmap->blue;
+ transp = cmap->transp;
+ index = cmap->start;
+
+ for (count = 0; count < cmap->len; count++) {
+ if (transp)
+ trans = *transp++;
+ r = _setcolreg(info, index++, *red++, *green++, *blue++, trans,
+ count == cmap->len - 1);
+ if (r != 0)
+ return r;
+ }
+
+ return 0;
+}
+
+static int omapfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ struct omapfb_device *fbdev = info->par;
+ int r;
+
+ omapfb_rqueue_lock(fbdev);
+ r = fbdev->ctrl->mmap(vma);
+ omapfb_rqueue_unlock(fbdev);
+
+ return r;
+}
+
+static void omapfb_update_full_screen(struct omapfb_device *fbdev);
+
+static int omapfb_blank(int blank, struct fb_info *fbi)
+{
+ struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
+ int do_update = 0;
+ int r = 0;
+
+ DBGENTER(1);
+
+ omapfb_rqueue_lock(fbdev);
+ switch (blank) {
+ case VESA_NO_BLANKING:
+ if (fbdev->state == OMAPFB_SUSPENDED) {
+ if (fbdev->ctrl->resume)
+ fbdev->ctrl->resume();
+ fbdev->panel->enable();
+ fbdev->state = OMAPFB_ACTIVE;
+ if (fbdev->ctrl->get_update_mode() ==
+ OMAPFB_MANUAL_UPDATE)
+ do_update = 1;
+ }
+ break;
+ case VESA_POWERDOWN:
+ if (fbdev->state == OMAPFB_ACTIVE) {
+ fbdev->panel->disable();
+ if (fbdev->ctrl->suspend)
+ fbdev->ctrl->suspend();
+ fbdev->state = OMAPFB_SUSPENDED;
+ }
+ break;
+ default:
+ r = -EINVAL;
+ }
+ omapfb_rqueue_unlock(fbdev);
+
+ if (do_update)
+ omapfb_update_full_screen(fbdev);
+
+ DBGLEAVE(1);
+ return r;
+}
+
+static void omapfb_sync(struct fb_info *fbi)
+{
+ struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
+
+ omapfb_rqueue_lock(fbdev);
+ if (fbdev->ctrl->sync)
+ fbdev->ctrl->sync();
+ omapfb_rqueue_unlock(fbdev);
+}
+
+/* Set fb_info.fix fields and also updates fbdev.
+ * When calling this fb_info.var must be set up already.
+ */
+static void set_fb_fix(struct omapfb_device *fbdev)
+{
+ struct fb_info *fbi = fbdev->fb_info;
+ struct fb_fix_screeninfo *fix = &fbi->fix;
+ struct fb_var_screeninfo *var = &fbi->var;
+
+ strncpy(fix->id, OMAPFB_DRIVER, sizeof(fix->id));
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ switch (var->bits_per_pixel) {
+ case 16:
+ fix->visual = FB_VISUAL_TRUECOLOR;
+ break;
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ fix->visual = FB_VISUAL_PSEUDOCOLOR;
+ break;
+ }
+ fix->accel = FB_ACCEL_OMAP1610;
+ fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
+ fix->smem_len = fbdev->vram_size;
+ fix->smem_start = fbdev->vram_phys_base;
+}
+
+/* Check the values in var against our capabilities and in case of out of
+ * bound values try to adjust them.
+ */
+static int set_fb_var(struct omapfb_device *fbdev,
+ struct fb_var_screeninfo *var)
+{
+ int bpp;
+ unsigned long max_frame_size;
+ unsigned long line_size;
+ struct lcd_panel *panel = fbdev->panel;
+
+ bpp = var->bits_per_pixel = panel->bpp;
+
+ switch (bpp) {
+ case 16:
+ fbdev->color_mode = OMAPFB_COLOR_RGB565;
+ break;
+ case 8:
+ fbdev->color_mode = OMAPFB_COLOR_CLUT_8BPP;
+ break;
+ default:
+ /* FIXME: other BPPs not yet supported */
+ return -EINVAL;
+ }
+
+ switch (var->rotate) {
+ case 0:
+ case 180:
+ var->xres = fbdev->panel->x_res;
+ var->yres = fbdev->panel->y_res;
+ break;
+ case 90:
+ case 270:
+ var->xres = fbdev->panel->y_res;
+ var->yres = fbdev->panel->x_res;
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
+ max_frame_size = fbdev->vram_size;
+ line_size = var->xres_virtual * bpp / 8;
+ if (line_size * var->yres_virtual > max_frame_size) {
+ /* Try to keep yres_virtual first */
+ line_size = max_frame_size / var->yres_virtual;
+ var->xres_virtual = line_size * 8 / bpp;
+ if (var->xres_virtual < var->xres) {
+ /* Still doesn't fit. Shrink yres_virtual too */
+ var->xres_virtual = var->xres;
+ line_size = var->xres * bpp / 8;
+ var->yres_virtual = max_frame_size / line_size;
+ }
+ }
+ if (var->xres + var->xoffset > var->xres_virtual)
+ var->xoffset = var->xres_virtual - var->xres;
+ if (var->yres + var->yoffset > var->yres_virtual)
+ var->yoffset = var->yres_virtual - var->yres;
+ line_size = var->xres * bpp / 8;
+
+ var->red.offset = 11; var->red.length = 5; var->red.msb_right = 0;
+ var->green.offset= 5; var->green.length = 6; var->green.msb_right = 0;
+ var->blue.offset = 0; var->blue.length = 5; var->blue.msb_right = 0;
+
+ var->height = -1;
+ var->width = -1;
+ var->grayscale = 0;
+ var->nonstd = 0;
+
+ /* pixclock in ps, the rest in pixclock */
+ var->pixclock = 10000000 / (panel->pixel_clock / 100);
+ var->left_margin = panel->hfp;
+ var->right_margin = panel->hbp;
+ var->upper_margin = panel->vfp;
+ var->lower_margin = panel->vbp;
+ var->hsync_len = panel->hsw;
+ var->vsync_len = panel->vsw;
+
+ /* TODO: get these from panel->config */
+ var->vmode = FB_VMODE_NONINTERLACED;
+ var->sync = 0;
+
+ return 0;
+}
+
+static struct fb_var_screeninfo new_var;
+
+/* Set rotation (0, 90, 180, 270 degree), and switch to the new mode. */
+static void omapfb_rotate(struct fb_info *fbi, int rotate)
+{
+ struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
+
+ DBGENTER(1);
+
+ if (cpu_is_omap1510() && rotate != fbdev->fb_info->var.rotate) {
+ memcpy(&new_var, &fbi->var, sizeof(new_var));
+ new_var.rotate = rotate;
+ if (set_fb_var(fbdev, &new_var) == 0 &&
+ memcmp(&new_var, &fbi->var, sizeof(new_var))) {
+ memcpy(&fbi->var, &new_var, sizeof(new_var));
+ ctrl_change_mode(fbdev);
+ }
+ }
+
+ DBGLEAVE(1);
+}
+
+/* Set new x,y offsets in the virtual display for the visible area and switch
+ * to the new mode.
+ */
+static int omapfb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *fbi)
+{
+ struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
+ int r = 0;
+
+ DBGENTER(1);
+
+ if (var->xoffset != fbi->var.xoffset ||
+ var->yoffset != fbi->var.yoffset) {
+ memcpy(&new_var, &fbi->var, sizeof(new_var));
+ new_var.xoffset = var->xoffset;
+ new_var.yoffset = var->yoffset;
+ if (set_fb_var(fbdev, &new_var))
+ r = -EINVAL;
+ else {
+ memcpy(&fbi->var, &new_var, sizeof(new_var));
+ ctrl_change_mode(fbdev);
+ }
+ }
+
+ DBGLEAVE(1);
+ return r;
+}
+
+/* Set mirror to vertical axis and switch to the new mode. */
+static int omapfb_mirror(struct omapfb_device *fbdev, int mirror)
+{
+ int r = 0;
+
+ DBGENTER(1);
+
+ mirror = mirror ? 1 : 0;
+ if (cpu_is_omap1510())
+ r = -EINVAL;
+ else if (mirror != fbdev->mirror) {
+ fbdev->mirror = mirror;
+ r = ctrl_change_mode(fbdev);
+ }
+
+ DBGLEAVE(1);
+ return r;
+}
+
+/* Check values in var, try to adjust them in case of out of bound values if
+ * possible, or return error.
+ */
+static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
+{
+ struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
+ int r;
+
+ DBGENTER(1);
+
+ r = set_fb_var(fbdev, var);
+
+ DBGLEAVE(1);
+ return r;
+}
+
+/* Switch to a new mode. The parameters for it has been check already by
+ * omapfb_check_var.
+ */
+static int omapfb_set_par(struct fb_info *fbi)
+{
+ int r;
+ struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
+
+ DBGENTER(1);
+
+ set_fb_fix(fbdev);
+ r = ctrl_change_mode(fbdev);
+
+ DBGLEAVE(1);
+ return r;
+}
+
+int omapfb_update_window_async(struct omapfb_update_window *win,
+ void (*callback)(void *),
+ void *callback_data)
+{
+ struct omapfb_device *fbdev = omapfb_dev;
+ struct fb_var_screeninfo *var;
+
+ DBGENTER(2);
+ if (fbdev == NULL) {
+ DBGPRINT(1, "no fbdev\n");
+ return -ENODEV;
+ }
+
+ var = &fbdev->fb_info->var;
+
+ if (win->x >= var->xres || win->y >= var->yres) {
+ DBGPRINT(1, "invalid x %d, y %d\n", win->x, win->y);
+ return -EINVAL;
+ }
+
+ if (!fbdev->ctrl->update_window ||
+ fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE) {
+ DBGPRINT(1, "invalid update mode\n");
+ return -ENODEV;
+ }
+
+ if (win->x + win->width >= var->xres)
+ win->width = var->xres - win->x;
+ if (win->y + win->height >= var->yres)
+ win->height = var->yres - win->y;
+ if (!win->width || !win->height) {
+ DBGPRINT(1, "zero size window\n");
+ return 0;
+ }
+
+ return fbdev->ctrl->update_window(win, callback, callback_data);
+}
+EXPORT_SYMBOL(omapfb_update_window_async);
+
+static int omapfb_update_win(struct omapfb_device *fbdev,
+ struct omapfb_update_window *win)
+{
+ int ret;
+
+ omapfb_rqueue_lock(fbdev);
+ ret = omapfb_update_window_async(win, NULL, 0);
+ omapfb_rqueue_unlock(fbdev);
+
+ return ret;
+}
+
+static void omapfb_update_full_screen(struct omapfb_device *fbdev)
+{
+ struct omapfb_update_window win;
+
+ win.x = 0;
+ win.y = 0;
+ win.width = fbdev->panel->x_res;
+ win.height = fbdev->panel->y_res;
+ win.format = 0;
+
+ omapfb_rqueue_lock(fbdev);
+ fbdev->ctrl->update_window(&win, NULL, 0);
+ omapfb_rqueue_unlock(fbdev);
+}
+
+static int omapfb_setup_plane(struct omapfb_device *fbdev,
+ struct omapfb_setup_plane *sp)
+{
+ int r;
+
+ omapfb_rqueue_lock(fbdev);
+ r = fbdev->ctrl->setup_plane(sp->plane, sp->channel_out, sp->offset,
+ sp->width, sp->pos_x, sp->pos_y, sp->width,
+ sp->height, sp->color_mode);
+ omapfb_rqueue_unlock(fbdev);
+
+ return r;
+}
+
+static int omapfb_enable_plane(struct omapfb_device *fbdev, int plane,
+ int enable)
+{
+ int r;
+
+ omapfb_rqueue_lock(fbdev);
+ r = fbdev->ctrl->enable_plane(plane, enable);
+ omapfb_rqueue_unlock(fbdev);
+
+ return r;
+}
+
+static int omapfb_set_color_key(struct omapfb_device *fbdev,
+ struct omapfb_color_key *ck)
+{
+ int r;
+
+ if (!fbdev->ctrl->set_color_key)
+ return -ENODEV;
+
+ omapfb_rqueue_lock(fbdev);
+ r = fbdev->ctrl->set_color_key(ck);
+ omapfb_rqueue_unlock(fbdev);
+
+ return r;
+}
+
+static struct notifier_block *omapfb_client_list;
+
+int omapfb_register_client(struct omapfb_notifier_block *omapfb_nb,
+ omapfb_notifier_callback_t callback,
+ void *callback_data)
+{
+ int r;
+
+ DBGENTER(1);
+
+ omapfb_nb->nb.notifier_call = (int (*)(struct notifier_block *,
+ unsigned long, void *))callback;
+ omapfb_nb->data = callback_data;
+ r = notifier_chain_register(&omapfb_client_list, &omapfb_nb->nb);
+ if (r)
+ return r;
+ if (omapfb_dev != NULL &&
+ omapfb_dev->ctrl && omapfb_dev->ctrl->bind_client) {
+ omapfb_dev->ctrl->bind_client(omapfb_nb);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(omapfb_register_client);
+
+int omapfb_unregister_client(struct omapfb_notifier_block *omapfb_nb)
+{
+ return notifier_chain_unregister(&omapfb_client_list,
+ &omapfb_nb->nb);
+}
+EXPORT_SYMBOL(omapfb_unregister_client);
+
+void omapfb_notify_clients(struct omapfb_device *fbdev, unsigned long event)
+{
+ DBGENTER(1);
+ notifier_call_chain(&omapfb_client_list, event, fbdev);
+}
+EXPORT_SYMBOL(omapfb_notify_clients);
+
+static int omapfb_set_update_mode(struct omapfb_device *fbdev,
+ enum omapfb_update_mode mode)
+{
+ int r;
+
+ omapfb_rqueue_lock(fbdev);
+ r = fbdev->ctrl->set_update_mode(mode);
+ omapfb_rqueue_unlock(fbdev);
+
+ return r;
+}
+
+static enum omapfb_update_mode omapfb_get_update_mode(struct omapfb_device *fbdev)
+{
+ int r;
+
+ omapfb_rqueue_lock(fbdev);
+ r = fbdev->ctrl->get_update_mode();
+ omapfb_rqueue_unlock(fbdev);
+
+ return r;
+}
+
+static unsigned long omapfb_get_caps(struct fb_info *fbi)
+{
+ struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
+ unsigned long caps;
+
+ caps = 0;
+ caps |= fbdev->panel->get_caps();
+ caps |= fbdev->ctrl->get_caps();
+ return caps;
+}
+
+/* For lcd testing */
+void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval)
+{
+ omapfb_rqueue_lock(fbdev);
+ *(u16 *)fbdev->vram_virt_base = pixval;
+ if (fbdev->ctrl->get_update_mode() == OMAPFB_MANUAL_UPDATE) {
+ struct omapfb_update_window win;
+
+ win.x = 0;
+ win.y = 0;
+ win.width = 1;
+ win.height = 1;
+ win.format = 0;
+ fbdev->ctrl->update_window(&win, NULL, 0);
+ }
+ omapfb_rqueue_unlock(fbdev);
+}
+EXPORT_SYMBOL(omapfb_write_first_pixel);
+
+/* Ioctl interface. Part of the kernel mode frame buffer API is duplicated
+ * here to be accessible by user mode code. In addition transparent copy
+ * graphics transformations, frame flipping support is provided through this
+ * interface.
+ */
+static int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd,
+ unsigned long arg)
+{
+ struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
+ struct fb_ops *ops = fbi->fbops;
+ union {
+ struct omapfb_update_window update_window;
+ struct omapfb_setup_plane setup_plane;
+ struct omapfb_enable_plane enable_plane;
+ struct omapfb_color_key color_key;
+ enum omapfb_update_mode update_mode;
+ unsigned long caps;
+ unsigned int mirror;
+ } p;
+ int r = 0;
+
+ BUG_ON(!ops);
+ DBGPRINT(2, "cmd=%010x\n", cmd);
+ switch (cmd)
+ {
+ case OMAPFB_MIRROR:
+ if (get_user(p.mirror, (int __user *)arg))
+ r = -EFAULT;
+ else
+ omapfb_mirror(fbdev, p.mirror);
+ break;
+ case OMAPFB_SYNC_GFX:
+ omapfb_sync(fbi);
+ break;
+ case OMAPFB_VSYNC:
+ break;
+ case OMAPFB_SET_UPDATE_MODE:
+ if (get_user(p.update_mode, (int __user *)arg))
+ r = -EFAULT;
+ else
+ r = omapfb_set_update_mode(fbdev, p.update_mode);
+ break;
+ case OMAPFB_GET_UPDATE_MODE:
+ p.update_mode = omapfb_get_update_mode(fbdev);
+ if (put_user(p.update_mode,
+ (enum omapfb_update_mode __user *)arg))
+ r = -EFAULT;
+ break;
+ case OMAPFB_UPDATE_WINDOW_OLD:
+ if (copy_from_user(&p.update_window, (void __user *)arg,
+ sizeof(struct omapfb_update_window_old)))
+ r = -EFAULT;
+ else {
+ p.update_window.format = 0;
+ r = omapfb_update_win(fbdev, &p.update_window);
+ }
+ break;
+ case OMAPFB_UPDATE_WINDOW:
+ if (copy_from_user(&p.update_window, (void __user *)arg,
+ sizeof(p.update_window)))
+ r = -EFAULT;
+ else
+ r = omapfb_update_win(fbdev, &p.update_window);
+ break;
+ case OMAPFB_SETUP_PLANE:
+ if (copy_from_user(&p.setup_plane, (void __user *)arg,
+ sizeof(p.setup_plane)))
+ r = -EFAULT;
+ else
+ r = omapfb_setup_plane(fbdev, &p.setup_plane);
+ break;
+ case OMAPFB_ENABLE_PLANE:
+ if (copy_from_user(&p.enable_plane, (void __user *)arg,
+ sizeof(p.enable_plane)))
+ r = -EFAULT;
+ else
+ r = omapfb_enable_plane(fbdev,
+ p.enable_plane.plane, p.enable_plane.enable);
+ break;
+ case OMAPFB_SET_COLOR_KEY:
+ if (copy_from_user(&p.color_key, (void __user *)arg,
+ sizeof(p.color_key)))
+ r = -EFAULT;
+ else
+ r = omapfb_set_color_key(fbdev, &p.color_key);
+ break;
+ case OMAPFB_GET_CAPS:
+ p.caps = omapfb_get_caps(fbi);
+ if (put_user(p.caps, (unsigned long __user *)arg))
+ r = -EFAULT;
+ break;
+ case OMAPFB_LCD_TEST:
+ {
+ int test_num;
+
+ if (get_user(test_num, (int __user *)arg)) {
+ r = -EFAULT;
+ break;
+ }
+ if (!fbdev->panel->run_test) {
+ r = -EINVAL;
+ break;
+ }
+ r = fbdev->panel->run_test(test_num);
+ break;
+ }
+ case OMAPFB_CTRL_TEST:
+ {
+ int test_num;
+
+ if (get_user(test_num, (int __user *)arg)) {
+ r = -EFAULT;
+ break;
+ }
+ if (!fbdev->ctrl->run_test) {
+ r = -EINVAL;
+ break;
+ }
+ r = fbdev->ctrl->run_test(test_num);
+ break;
+ }
+ default:
+ r = -EINVAL;
+ }
+
+ DBGLEAVE(2);
+ return r;
+}
+
+/* Callback table for the frame buffer framework. Some of these pointers
+ * will be changed according to the current setting of fb_info->accel_flags.
+ */
+static struct fb_ops omapfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = omapfb_open,
+ .fb_release = omapfb_release,
+ .fb_setcolreg = omapfb_setcolreg,
+ .fb_setcmap = omapfb_setcmap,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_blank = omapfb_blank,
+ .fb_ioctl = omapfb_ioctl,
+ .fb_check_var = omapfb_check_var,
+ .fb_set_par = omapfb_set_par,
+ .fb_rotate = omapfb_rotate,
+ .fb_pan_display = omapfb_pan_display,
+};
+
+/*
+ * ---------------------------------------------------------------------------
+ * Sysfs interface
+ * ---------------------------------------------------------------------------
+ */
+/* omapfbX sysfs entries */
+static ssize_t omapfb_show_caps_num(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+
+ return snprintf(buf, PAGE_SIZE, "%#010lx\n",
+ omapfb_get_caps(fbdev->fb_info));
+}
+
+static ssize_t omapfb_show_caps_text(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+ int pos = 0;
+ int i;
+ unsigned long caps;
+
+ caps = omapfb_get_caps(fbdev->fb_info);
+ for (i = 0; i < ARRAY_SIZE(omapfb_caps_table) && pos < PAGE_SIZE; i++) {
+ if (omapfb_caps_table[i].flag & caps) {
+ pos += snprintf(&buf[pos], PAGE_SIZE - pos, "%s\n",
+ omapfb_caps_table[i].name);
+ }
+ }
+ return min((int)PAGE_SIZE, pos);
+}
+
+static DEVICE_ATTR(caps_num, 0444, omapfb_show_caps_num, NULL);
+static DEVICE_ATTR(caps_text, 0444, omapfb_show_caps_text, NULL);
+
+/* panel sysfs entries */
+static ssize_t omapfb_show_panel_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->panel->name);
+}
+
+static ssize_t omapfb_show_bklight_level(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+ int r;
+
+ if (fbdev->panel->get_bklight_level) {
+ r = snprintf(buf, PAGE_SIZE, "%d\n",
+ fbdev->panel->get_bklight_level());
+ } else
+ r = -ENODEV;
+ return r;
+}
+
+static ssize_t omapfb_store_bklight_level(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+ int r;
+
+ if (fbdev->panel->set_bklight_level) {
+ unsigned int level;
+
+ if (sscanf(buf, "%10d", &level) == 1) {
+ r = fbdev->panel->set_bklight_level(level);
+ } else
+ r = -EINVAL;
+ } else
+ r = -ENODEV;
+ return r ? r : size;
+}
+
+static ssize_t omapfb_show_bklight_max(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+ int r;
+
+ if (fbdev->panel->get_bklight_level) {
+ r = snprintf(buf, PAGE_SIZE, "%d\n",
+ fbdev->panel->get_bklight_max());
+ } else
+ r = -ENODEV;
+ return r;
+}
+
+static struct device_attribute dev_attr_panel_name =
+ __ATTR(name, 0444, omapfb_show_panel_name, NULL);
+static DEVICE_ATTR(backlight_level, 0664,
+ omapfb_show_bklight_level, omapfb_store_bklight_level);
+static DEVICE_ATTR(backlight_max, 0444, omapfb_show_bklight_max, NULL);
+
+static struct attribute *panel_attrs[] = {
+ &dev_attr_panel_name.attr,
+ &dev_attr_backlight_level.attr,
+ &dev_attr_backlight_max.attr,
+ NULL,
+};
+
+static struct attribute_group panel_attr_grp = {
+ .name = "panel",
+ .attrs = panel_attrs,
+};
+
+/* ctrl sysfs entries */
+static ssize_t omapfb_show_ctrl_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->ctrl->name);
+}
+
+static struct device_attribute dev_attr_ctrl_name =
+ __ATTR(name, 0444, omapfb_show_ctrl_name, NULL);
+
+static struct attribute *ctrl_attrs[] = {
+ &dev_attr_ctrl_name.attr,
+ NULL,
+};
+
+static struct attribute_group ctrl_attr_grp = {
+ .name = "ctrl",
+ .attrs = ctrl_attrs,
+};
+
+static int omapfb_register_sysfs(struct omapfb_device *fbdev)
+{
+ int r;
+
+ if ((r = device_create_file(fbdev->dev, &dev_attr_caps_num)))
+ goto fail0;
+
+ if ((r = device_create_file(fbdev->dev, &dev_attr_caps_text)))
+ goto fail1;
+
+ if ((r = sysfs_create_group(&fbdev->dev->kobj, &panel_attr_grp)))
+ goto fail2;
+
+ if ((r = sysfs_create_group(&fbdev->dev->kobj, &ctrl_attr_grp)))
+ goto fail3;
+
+ return 0;
+fail3:
+ sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp);
+fail2:
+ device_remove_file(fbdev->dev, &dev_attr_caps_text);
+fail1:
+ device_remove_file(fbdev->dev, &dev_attr_caps_num);
+fail0:
+ pr_err("unable to register sysfs interface\n");
+ return r;
+}
+
+static void omapfb_unregister_sysfs(struct omapfb_device *fbdev)
+{
+ sysfs_remove_group(&fbdev->dev->kobj, &ctrl_attr_grp);
+ sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp);
+ device_remove_file(fbdev->dev, &dev_attr_caps_num);
+ device_remove_file(fbdev->dev, &dev_attr_caps_text);
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * LDM callbacks
+ * ---------------------------------------------------------------------------
+ */
+/* Initialize system fb_info object and set the default video mode.
+ * The frame buffer memory already allocated by lcddma_init
+ */
+static int fbinfo_init(struct omapfb_device *fbdev)
+{
+ struct fb_info *info = fbdev->fb_info;
+ struct fb_var_screeninfo *var = &info->var;
+ int r = 0;
+
+ DBGENTER(1);
+
+ BUG_ON(!fbdev->vram_virt_base);
+
+ info->fbops = &omapfb_ops;
+ info->flags = FBINFO_FLAG_DEFAULT;
+ info->screen_base = (char __iomem *)fbdev->vram_virt_base;
+
+ info->pseudo_palette = fbdev->pseudo_palette;
+
+ var->accel_flags = def_accel ? FB_ACCELF_TEXT : 0;
+ var->xres_virtual = def_vxres;
+ var->yres_virtual = def_vyres;
+ var->rotate = def_rotate;
+
+ fbdev->mirror = def_mirror;
+
+ set_fb_var(fbdev, var);
+ set_fb_fix(fbdev);
+
+ r = fb_alloc_cmap(&info->cmap, 16, 0);
+ if (r != 0)
+ pr_err("unable to allocate color map memory\n");
+
+ DBGLEAVE(1);
+ return r;
+}
+
+/* Release the fb_info object */
+static void fbinfo_cleanup(struct omapfb_device *fbdev)
+{
+ DBGENTER(1);
+
+ fb_dealloc_cmap(&fbdev->fb_info->cmap);
+
+ DBGLEAVE(1);
+}
+
+/* Free driver resources. Can be called to rollback an aborted initialization
+ * sequence.
+ */
+static void omapfb_free_resources(struct omapfb_device *fbdev, int state)
+{
+ switch (state) {
+ case OMAPFB_ACTIVE:
+ unregister_framebuffer(fbdev->fb_info);
+ case 7:
+ omapfb_unregister_sysfs(fbdev);
+ case 6:
+ fbdev->panel->disable();
+ case 5:
+ omapfb_set_update_mode(fbdev, OMAPFB_UPDATE_DISABLED);
+ case 4:
+ fbinfo_cleanup(fbdev);
+ case 3:
+ ctrl_cleanup(fbdev);
+ case 2:
+ fbdev->panel->cleanup();
+ case 1:
+ dev_set_drvdata(fbdev->dev, NULL);
+ framebuffer_release(fbdev->fb_info);
+ case 0:
+ /* nothing to free */
+ break;
+ default:
+ BUG();
+ }
+}
+
+static int omapfb_find_ctrl(struct omapfb_device *fbdev)
+{
+ struct omapfb_platform_data *conf;
+ char name[17];
+ int i;
+
+ conf = (struct omapfb_platform_data *)fbdev->dev->platform_data;
+
+ fbdev->ctrl = NULL;
+ if (conf == NULL) {
+ DBGPRINT(1, "omap_lcd_config not found\n");
+ return -1;
+ }
+
+ strncpy(name, conf->lcd.ctrl_name, sizeof(name) - 1);
+ name[sizeof(name) - 1] = '\0';
+
+ if (strcmp(name, "internal") == 0) {
+ fbdev->ctrl = fbdev->int_ctrl;
+ return 0;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(ctrls); i++) {
+ DBGPRINT(1, "ctrl %s\n", ctrls[i]->name);
+ if (strcmp(ctrls[i]->name, name) == 0) {
+ fbdev->ctrl = ctrls[i];
+ break;
+ }
+ }
+
+ if (fbdev->ctrl == NULL) {
+ DBGPRINT(1, "ctrl %s not supported\n", name);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void check_required_callbacks(struct omapfb_device *fbdev)
+{
+#define _C(x) (fbdev->ctrl->x != NULL)
+#define _P(x) (fbdev->panel->x != NULL)
+ BUG_ON(fbdev->ctrl == NULL || fbdev->panel == NULL);
+ BUG_ON(!(_C(init) && _C(cleanup) && _C(get_caps) &&
+ _C(set_update_mode) && _C(setup_plane) && _C(enable_plane) &&
+ _P(init) && _P(cleanup) && _P(enable) && _P(disable) &&
+ _P(get_caps)));
+#undef _P
+#undef _C
+}
+
+/* Called by LDM binding to probe and attach a new device.
+ * Initialization sequence:
+ * 1. allocate system fb_info structure
+ * select panel type according to machine type
+ * 2. init LCD panel
+ * 3. init LCD controller and LCD DMA
+ * 4. init system fb_info structure
+ * 5. init gfx DMA
+ * 6. enable LCD panel
+ * start LCD frame transfer
+ * 7. register system fb_info structure
+ */
+static int omapfb_do_probe(struct platform_device *pdev, struct lcd_panel *panel)
+{
+ struct omapfb_device *fbdev = NULL;
+ struct fb_info *fbi;
+ int init_state;
+ unsigned long phz, hhz, vhz;
+ int r = 0;
+
+ DBGENTER(1);
+
+ init_state = 0;
+
+ if (pdev->num_resources != 0) {
+ pr_err("probed for an unknown device\n");
+ r = -ENODEV;
+ goto cleanup;
+ }
+
+ fbi = framebuffer_alloc(sizeof(struct omapfb_device), &pdev->dev);
+ if (fbi == NULL) {
+ pr_err("unable to allocate memory for device info\n");
+ r = -ENOMEM;
+ goto cleanup;
+ }
+ init_state++;
+
+ fbdev = (struct omapfb_device *)fbi->par;
+ fbdev->fb_info = fbi;
+ fbdev->dev = &pdev->dev;
+ fbdev->panel = panel;
+ platform_set_drvdata(pdev, fbdev);
+
+ init_MUTEX(&fbdev->rqueue_sema);
+
+#ifdef CONFIG_ARCH_OMAP1
+ fbdev->int_ctrl = &omap1_int_ctrl;
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+ fbdev->ext_if = &sossi_extif;
+#endif
+#else /* OMAP2 */
+ fbdev->int_ctrl = &omap2_int_ctrl;
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+ fbdev->ext_if = &rfbi_extif;
+#endif
+#endif
+ if (omapfb_find_ctrl(fbdev) < 0) {
+ pr_err("LCD controller not found, board not supported\n");
+ r = -ENODEV;
+ goto cleanup;
+ }
+
+ pr_info(MODULE_NAME ": configured for panel %s\n", fbdev->panel->name);
+
+ r = fbdev->panel->init(fbdev);
+ if (r)
+ goto cleanup;
+ init_state++;
+
+ r = ctrl_init(fbdev);
+ if (r)
+ goto cleanup;
+ init_state++;
+
+ /* We depend on doing this after ctrl_init, since it can redefine
+ * member functions.
+ */
+ if (fbdev->ctrl->mmap)
+ omapfb_ops.fb_mmap = omapfb_mmap;
+
+ check_required_callbacks(fbdev);
+
+ r = fbinfo_init(fbdev);
+ if (r)
+ goto cleanup;
+ init_state++;
+
+#ifdef CONFIG_FB_OMAP_DMA_TUNE
+ /* Set DMA priority for EMIFF access to highest */
+ omap_set_dma_priority(OMAP_DMA_PORT_EMIFF, 15);
+#endif
+
+ r = ctrl_change_mode(fbdev);
+ if (r) {
+ pr_err("mode setting failed\n");
+ goto cleanup;
+ }
+
+ if (!manual_update)
+ omapfb_enable_plane(fbdev, OMAPFB_PLANE_GFX, 1);
+
+ omapfb_set_update_mode(fbdev, manual_update ?
+ OMAPFB_MANUAL_UPDATE : OMAPFB_AUTO_UPDATE);
+ init_state++;
+
+ r = fbdev->panel->enable();
+ if (r)
+ goto cleanup;
+ init_state++;
+
+ r = omapfb_register_sysfs(fbdev);
+ if (r)
+ goto cleanup;
+ init_state++;
+
+ r = register_framebuffer(fbdev->fb_info);
+ if (r != 0) {
+ pr_err("register_framebuffer failed\n");
+ goto cleanup;
+ }
+
+ fbdev->state = OMAPFB_ACTIVE;
+
+ panel = fbdev->panel;
+ phz = panel->pixel_clock * 1000;
+ hhz = phz * 10 / (panel->hfp + panel->x_res + panel->hbp + panel->hsw);
+ vhz = hhz / (panel->vfp + panel->y_res + panel->vbp + panel->vsw);
+
+ omapfb_dev = fbdev;
+
+ pr_info(MODULE_NAME ": initialized vram=%lu "
+ "pixclock %lu kHz hfreq %lu.%lu kHz vfreq %lu.%lu Hz\n",
+ fbdev->vram_size,
+ phz / 1000, hhz / 10000, hhz % 10, vhz / 10, vhz % 10);
+
+ DBGLEAVE(1);
+ return 0;
+
+cleanup:
+ omapfb_free_resources(fbdev, init_state);
+
+ DBGLEAVE(1);
+ return r;
+}
+
+static int omapfb_probe(struct platform_device *pdev)
+{
+ BUG_ON(fbdev_pdev != NULL);
+
+ DBGENTER(1);
+ fbdev_pdev = pdev;
+ if (fbdev_panel != NULL)
+ omapfb_do_probe(fbdev_pdev, fbdev_panel);
+ return 0;
+}
+
+void omapfb_register_panel(struct lcd_panel *panel)
+{
+ BUG_ON(fbdev_panel != NULL);
+
+ DBGENTER(1);
+ fbdev_panel = panel;
+ if (fbdev_pdev != NULL)
+ omapfb_do_probe(fbdev_pdev, fbdev_panel);
+}
+
+/* Called when the device is being detached from the driver */
+static int omapfb_remove(struct platform_device *pdev)
+{
+ struct omapfb_device *fbdev = platform_get_drvdata(pdev);
+ enum omapfb_state saved_state = fbdev->state;
+
+ DBGENTER(1);
+ /* FIXME: wait till completion of pending events */
+
+ fbdev->state = OMAPFB_DISABLED;
+ omapfb_free_resources(fbdev, saved_state);
+
+ DBGLEAVE(1);
+ return 0;
+}
+
+/* PM suspend */
+static int omapfb_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ struct omapfb_device *fbdev = platform_get_drvdata(pdev);
+
+ DBGENTER(1);
+
+ omapfb_blank(VESA_POWERDOWN, fbdev->fb_info);
+
+ DBGLEAVE(1);
+
+ return 0;
+}
+
+/* PM resume */
+static int omapfb_resume(struct platform_device *pdev)
+{
+ struct omapfb_device *fbdev = platform_get_drvdata(pdev);
+
+ DBGENTER(1);
+
+ omapfb_blank(VESA_NO_BLANKING, fbdev->fb_info);
+
+ DBGLEAVE(1);
+ return 0;
+}
+
+static struct platform_driver omapfb_driver = {
+ .probe = omapfb_probe,
+ .remove = omapfb_remove,
+ .suspend = omapfb_suspend,
+ .resume = omapfb_resume,
+ .driver = {
+ .name = OMAPFB_DRIVER,
+ .owner = THIS_MODULE,
+ },
+};
+
+#ifndef MODULE
+
+/* Process kernel command line parameters */
+static int __init omapfb_setup(char *options)
+{
+ char *this_opt = NULL;
+ int r = 0;
+
+ DBGENTER(1);
+
+ if (!options || !*options)
+ goto exit;
+
+ while (!r && (this_opt = strsep(&options, ",")) != NULL) {
+ if (!strncmp(this_opt, "accel", 5))
+ def_accel = 1;
+ else if (!strncmp(this_opt, "vram:", 5)) {
+ char *suffix;
+ def_vram = (simple_strtoul(this_opt + 5, &suffix, 0));
+ switch (suffix[0]) {
+ case '\0':
+ break;
+ case 'm':
+ case 'M':
+ def_vram *= 1024;
+ /* Fall through */
+ case 'k':
+ case 'K':
+ def_vram *= 1024;
+ break;
+ default:
+ pr_err("invalid vram suffix\n");
+ r = -1;
+ }
+ }
+ else if (!strncmp(this_opt, "vxres:", 6))
+ def_vxres = simple_strtoul(this_opt + 6, NULL, 0);
+ else if (!strncmp(this_opt, "vyres:", 6))
+ def_vyres = simple_strtoul(this_opt + 6, NULL, 0);
+ else if (!strncmp(this_opt, "rotate:", 7))
+ def_rotate = (simple_strtoul(this_opt + 7, NULL, 0));
+ else if (!strncmp(this_opt, "mirror:", 7))
+ def_mirror = (simple_strtoul(this_opt + 7, NULL, 0));
+ else if (!strncmp(this_opt, "manual_update", 13))
+ manual_update = 1;
+ else {
+ pr_err("invalid option\n");
+ r = -1;
+ }
+ }
+exit:
+ DBGLEAVE(1);
+ return r;
+}
+
+#endif
+
+/* Register both the driver and the device */
+static int __init omapfb_init(void)
+{
+ int r = 0;
+
+ DBGENTER(1);
+
+#ifndef MODULE
+ {
+ char *option;
+
+ if (fb_get_options("omapfb", &option)) {
+ r = -ENODEV;
+ goto exit;
+ }
+ omapfb_setup(option);
+ }
+#endif
+ /* Register the driver with LDM */
+ if (platform_driver_register(&omapfb_driver)) {
+ pr_err("failed to register omapfb driver\n");
+ r = -ENODEV;
+ goto exit;
+ }
+
+exit:
+ DBGLEAVE(1);
+ return r;
+}
+
+static void __exit omapfb_cleanup(void)
+{
+ DBGENTER(1);
+
+ platform_driver_unregister(&omapfb_driver);
+
+ DBGLEAVE(1);
+}
+
+module_param_named(accel, def_accel, uint, 0664);
+module_param_named(vram, def_vram, ulong, 0664);
+module_param_named(vxres, def_vxres, long, 0664);
+module_param_named(vyres, def_vyres, long, 0664);
+module_param_named(rotate, def_rotate, uint, 0664);
+module_param_named(mirror, def_mirror, uint, 0664);
+module_param_named(manual_update, manual_update, bool, 0664);
+
+module_init(omapfb_init);
+module_exit(omapfb_cleanup);
+
+MODULE_DESCRIPTION("TI OMAP framebuffer driver");
+MODULE_AUTHOR("Imre Deak <imre.deak@nokia.com>");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * File: drivers/video/omap/omap2/rfbi.c
+ *
+ * OMAP2 Remote Frame Buffer Interface support
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ * Imre Deak <imre.deak@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/delay.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+
+#include <asm/arch/omapfb.h>
+
+#include "dispc.h"
+
+/* #define OMAPFB_DBG 1 */
+
+#include "debug.h"
+
+#define MODULE_NAME "omapfb-rfbi"
+
+#define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
+
+#define RFBI_BASE 0x48050800
+#define RFBI_REVISION 0x0000
+#define RFBI_SYSCONFIG 0x0010
+#define RFBI_SYSSTATUS 0x0014
+#define RFBI_CONTROL 0x0040
+#define RFBI_PIXEL_CNT 0x0044
+#define RFBI_LINE_NUMBER 0x0048
+#define RFBI_CMD 0x004c
+#define RFBI_PARAM 0x0050
+#define RFBI_DATA 0x0054
+#define RFBI_READ 0x0058
+#define RFBI_STATUS 0x005c
+#define RFBI_CONFIG0 0x0060
+#define RFBI_ONOFF_TIME0 0x0064
+#define RFBI_CYCLE_TIME0 0x0068
+#define RFBI_DATA_CYCLE1_0 0x006c
+#define RFBI_DATA_CYCLE2_0 0x0070
+#define RFBI_DATA_CYCLE3_0 0x0074
+#define RFBI_VSYNC_WIDTH 0x0090
+#define RFBI_HSYNC_WIDTH 0x0094
+
+#define DISPC_BASE 0x48050400
+#define DISPC_CONTROL 0x0040
+
+static struct {
+ u32 base;
+ void (*lcdc_callback)(void *data);
+ void *lcdc_callback_data;
+ unsigned long l4_khz;
+ int bits_per_cycle;
+} rfbi;
+
+struct lcd_ctrl_extif rfbi_extif;
+
+static inline void rfbi_write_reg(int idx, u32 val)
+{
+ __raw_writel(val, rfbi.base + idx);
+}
+
+static inline u32 rfbi_read_reg(int idx)
+{
+ return __raw_readl(rfbi.base + idx);
+}
+
+#ifdef OMAPFB_DBG
+static void rfbi_print_timings(void)
+{
+ u32 l;
+ u32 time;
+
+ l = rfbi_read_reg(RFBI_CONFIG0);
+ time = 1000000000 / rfbi.l4_khz;
+ if (l & (1 << 4))
+ time *= 2;
+
+ DBGPRINT(1, "Tick time %u ps\n", time);
+ l = rfbi_read_reg(RFBI_ONOFF_TIME0);
+ DBGPRINT(1, "CSONTIME %d, CSOFFTIME %d, WEONTIME %d, WEOFFTIME %d, "
+ "REONTIME %d, REOFFTIME %d\n",
+ l & 0x0f, (l >> 4) & 0x3f, (l >> 10) & 0x0f, (l >> 14) & 0x3f,
+ (l >> 20) & 0x0f, (l >> 24) & 0x3f);
+ l = rfbi_read_reg(RFBI_CYCLE_TIME0);
+ DBGPRINT(1, "WECYCLETIME %d, RECYCLETIME %d, CSPULSEWIDTH %d, "
+ "ACCESSTIME %d\n",
+ (l & 0x3f), (l >> 6) & 0x3f, (l >> 12) & 0x3f, (l >> 22) & 0x3f);
+}
+#else
+static void rfbi_print_timings(void) {}
+#endif
+
+static void rfbi_set_timings(const struct extif_timings *t)
+{
+ u32 l;
+
+ BUG_ON(!t->converted);
+
+ rfbi_write_reg(RFBI_ONOFF_TIME0, t->tim[0]);
+ rfbi_write_reg(RFBI_CYCLE_TIME0, t->tim[1]);
+
+ l = rfbi_read_reg(RFBI_CONFIG0);
+ l &= ~(1 << 4);
+ l |= (t->tim[2] ? 1 : 0) << 4;
+ rfbi_write_reg(RFBI_CONFIG0, l);
+
+ rfbi_print_timings();
+}
+
+static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div)
+{
+ *clk_period = 1000000000 / rfbi.l4_khz;
+ *max_clk_div = 2;
+}
+
+static int ps_to_rfbi_ticks(int time, int div)
+{
+ unsigned long tick_ps;
+ int ret;
+
+ /* Calculate in picosecs to yield more exact results */
+ tick_ps = 1000000000 / (rfbi.l4_khz) * div;
+
+ ret = (time + tick_ps - 1) / tick_ps;
+
+ return ret;
+}
+
+static int rfbi_convert_timings(struct extif_timings *t)
+{
+ u32 l;
+ int reon, reoff, weon, weoff, cson, csoff, cs_pulse;
+ int actim, recyc, wecyc;
+ int div = t->clk_div;
+
+ if (div <= 0 || div > 2)
+ return -1;
+
+ /* Make sure that after conversion it still holds that:
+ * weoff > weon, reoff > reon, recyc >= reoff, wecyc >= weoff,
+ * csoff > cson, csoff >= max(weoff, reoff), actim > reon
+ */
+ weon = ps_to_rfbi_ticks(t->we_on_time, div);
+ weoff = ps_to_rfbi_ticks(t->we_off_time, div);
+ if (weoff <= weon)
+ weoff = weon + 1;
+ if (weon > 0x0f)
+ return -1;
+ if (weoff > 0x3f)
+ return -1;
+
+ reon = ps_to_rfbi_ticks(t->re_on_time, div);
+ reoff = ps_to_rfbi_ticks(t->re_off_time, div);
+ if (reoff <= reon)
+ reoff = reon + 1;
+ if (reon > 0x0f)
+ return -1;
+ if (reoff > 0x3f)
+ return -1;
+
+ cson = ps_to_rfbi_ticks(t->cs_on_time, div);
+ csoff = ps_to_rfbi_ticks(t->cs_off_time, div);
+ if (csoff <= cson)
+ csoff = cson + 1;
+ if (csoff < max(weoff, reoff))
+ csoff = max(weoff, reoff);
+ if (cson > 0x0f)
+ return -1;
+ if (csoff > 0x3f)
+ return -1;
+
+ l = cson;
+ l |= csoff << 4;
+ l |= weon << 10;
+ l |= weoff << 14;
+ l |= reon << 20;
+ l |= reoff << 24;
+
+ t->tim[0] = l;
+
+ actim = ps_to_rfbi_ticks(t->access_time, div);
+ if (actim <= reon)
+ actim = reon + 1;
+ if (actim > 0x3f)
+ return -1;
+
+ wecyc = ps_to_rfbi_ticks(t->we_cycle_time, div);
+ if (wecyc < weoff)
+ wecyc = weoff;
+ if (wecyc > 0x3f)
+ return -1;
+
+ recyc = ps_to_rfbi_ticks(t->re_cycle_time, div);
+ if (recyc < reoff)
+ recyc = reoff;
+ if (recyc > 0x3f)
+ return -1;
+
+ cs_pulse = ps_to_rfbi_ticks(t->cs_pulse_width, div);
+ if (cs_pulse > 0x3f)
+ return -1;
+
+ l = wecyc;
+ l |= recyc << 6;
+ l |= cs_pulse << 12;
+ l |= actim << 22;
+
+ t->tim[1] = l;
+
+ t->tim[2] = div - 1;
+
+ t->converted = 1;
+
+ return 0;
+}
+
+static void rfbi_write_command(const void *buf, unsigned int len)
+{
+ if (rfbi.bits_per_cycle == 16) {
+ const u16 *w = buf;
+ BUG_ON(len & 1);
+ for (; len; len -= 2)
+ rfbi_write_reg(RFBI_CMD, *w++);
+ } else {
+ const u8 *b = buf;
+ BUG_ON(rfbi.bits_per_cycle != 8);
+ for (; len; len--)
+ rfbi_write_reg(RFBI_CMD, *b++);
+ }
+}
+
+static void rfbi_read_data(void *buf, unsigned int len)
+{
+ if (rfbi.bits_per_cycle == 16) {
+ u16 *w = buf;
+ BUG_ON(len & ~1);
+ for (; len; len -= 2) {
+ rfbi_write_reg(RFBI_READ, 0);
+ *w++ = rfbi_read_reg(RFBI_READ);
+ }
+ } else {
+ u8 *b = buf;
+ BUG_ON(rfbi.bits_per_cycle != 8);
+ for (; len; len--) {
+ rfbi_write_reg(RFBI_READ, 0);
+ *b++ = rfbi_read_reg(RFBI_READ);
+ }
+ }
+}
+
+static void rfbi_write_data(const void *buf, unsigned int len)
+{
+ if (rfbi.bits_per_cycle == 16) {
+ const u16 *w = buf;
+ BUG_ON(len & 1);
+ for (; len; len -= 2)
+ rfbi_write_reg(RFBI_PARAM, *w++);
+ } else {
+ const u8 *b = buf;
+ BUG_ON(rfbi.bits_per_cycle != 8);
+ for (; len; len--)
+ rfbi_write_reg(RFBI_PARAM, *b++);
+ }
+}
+
+static void rfbi_transfer_area(int width, int height,
+ void (callback)(void * data), void *data)
+{
+ u32 w;
+
+ BUG_ON(callback == NULL);
+
+ omap_dispc_set_lcd_size(width, height);
+
+ rfbi.lcdc_callback = callback;
+ rfbi.lcdc_callback_data = data;
+
+ rfbi_write_reg(RFBI_PIXEL_CNT, width * height);
+
+ w = rfbi_read_reg(RFBI_CONTROL);
+ /* Enable, Internal trigger */
+ rfbi_write_reg(RFBI_CONTROL, w | (1 << 0) | (1 << 4));
+
+ omap_dispc_enable_lcd_out(1);
+}
+
+static inline void _stop_transfer(void)
+{
+ u32 w;
+
+ w = rfbi_read_reg(RFBI_CONTROL);
+ rfbi_write_reg(RFBI_CONTROL, w & ~(1 << 0));
+}
+
+static void rfbi_dma_callback(void *data)
+{
+ _stop_transfer();
+ rfbi.lcdc_callback(rfbi.lcdc_callback_data);
+}
+
+static void rfbi_set_bits_per_cycle(int bpc)
+{
+ u32 l;
+
+ l = rfbi_read_reg(RFBI_CONFIG0);
+ l &= ~(0x03 << 0);
+ switch (bpc)
+ {
+ case 8:
+ break;
+ case 16:
+ l |= 3;
+ break;
+ default:
+ BUG();
+ }
+ rfbi_write_reg(RFBI_CONFIG0, l);
+ rfbi.bits_per_cycle = bpc;
+}
+
+static int rfbi_init(void)
+{
+ u32 l;
+ int r;
+ struct clk *dss_ick;
+
+ rfbi.base = io_p2v(RFBI_BASE);
+
+ l = rfbi_read_reg(RFBI_REVISION);
+ pr_info(MODULE_NAME ": version %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
+
+ dss_ick = clk_get(NULL, "dss_ick");
+ if (IS_ERR(dss_ick)) {
+ pr_err("can't get dss_ick\n");
+ return PTR_ERR(dss_ick);
+ }
+
+ rfbi.l4_khz = clk_get_rate(dss_ick) / 1000;
+ clk_put(dss_ick);
+
+ /* Reset */
+ rfbi_write_reg(RFBI_SYSCONFIG, 1 << 1);
+ while (!(rfbi_read_reg(RFBI_SYSSTATUS) & (1 << 0)));
+
+ l = rfbi_read_reg(RFBI_SYSCONFIG);
+ /* Enable autoidle and smart-idle */
+ l |= (1 << 0) | (2 << 3);
+ rfbi_write_reg(RFBI_SYSCONFIG, l);
+
+ /* 16-bit interface, ITE trigger mode, 16-bit data */
+ l = (0x03 << 0) | (0x00 << 2) | (0x01 << 5) | (0x02 << 7);
+ l |= (0 << 9) | (1 << 20) | (1 << 21);
+ rfbi_write_reg(RFBI_CONFIG0, l);
+
+ rfbi_write_reg(RFBI_DATA_CYCLE1_0, 0x00000010);
+
+ l = rfbi_read_reg(RFBI_CONTROL);
+ /* Select CS0, clear bypass mode */
+ l = (0x01 << 2);
+ rfbi_write_reg(RFBI_CONTROL, l);
+
+ if ((r = omap_dispc_request_irq(rfbi_dma_callback, NULL)) < 0) {
+ pr_err("can't get DISPC irq\n");
+ return r;
+ }
+
+ return 0;
+}
+
+static void rfbi_cleanup(void)
+{
+ omap_dispc_free_irq();
+}
+
+struct lcd_ctrl_extif rfbi_extif = {
+ .init = rfbi_init,
+ .cleanup = rfbi_cleanup,
+ .get_clk_info = rfbi_get_clk_info,
+ .set_bits_per_cycle = rfbi_set_bits_per_cycle,
+ .convert_timings = rfbi_convert_timings,
+ .set_timings = rfbi_set_timings,
+ .write_command = rfbi_write_command,
+ .read_data = rfbi_read_data,
+ .write_data = rfbi_write_data,
+ .transfer_area = rfbi_transfer_area,
+ .max_transmit_size = (u32)~0,
+};
+
--- /dev/null
+/*
+ * File: drivers/video/omap/omap1/sossi.c
+ *
+ * OMAP1 Special OptimiSed Screen Interface support
+ *
+ * Copyright (C) 2004-2005 Nokia Corporation
+ * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+
+#include <asm/arch/dma.h>
+#include <asm/arch/omapfb.h>
+
+#include "lcdc.h"
+
+/* #define OMAPFB_DBG 1 */
+
+#include "debug.h"
+
+#define MODULE_NAME "omapfb-sossi"
+
+#define OMAP_SOSSI_BASE 0xfffbac00
+#define SOSSI_ID_REG 0x00
+#define SOSSI_INIT1_REG 0x04
+#define SOSSI_INIT2_REG 0x08
+#define SOSSI_INIT3_REG 0x0c
+#define SOSSI_FIFO_REG 0x10
+#define SOSSI_REOTABLE_REG 0x14
+#define SOSSI_TEARING_REG 0x18
+#define SOSSI_INIT1B_REG 0x1c
+#define SOSSI_FIFOB_REG 0x20
+
+#define DMA_GSCR 0xfffedc04
+#define DMA_LCD_CCR 0xfffee3c2
+#define DMA_LCD_CTRL 0xfffee3c4
+#define DMA_LCD_LCH_CTRL 0xfffee3ea
+
+#define RD_ACCESS 0
+#define WR_ACCESS 1
+
+#define SOSSI_MAX_XMIT_BYTES (512 * 1024)
+
+#define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
+
+static struct sossi {
+ int base;
+ unsigned long dpll_khz;
+ int bus_pick_width;
+ void (*lcdc_callback)(void *data);
+ void *lcdc_callback_data;
+ /* timing for read and write access */
+ int clk_div;
+ u8 clk_tw0[2];
+ u8 clk_tw1[2];
+ /* if last_access is the same as current we don't have to change
+ * the timings
+ */
+ int last_access;
+} sossi;
+
+struct lcd_ctrl_extif sossi_extif;
+
+static inline u32 sossi_read_reg(int reg)
+{
+ return readl(sossi.base + reg);
+}
+
+static inline u16 sossi_read_reg16(int reg)
+{
+ return readw(sossi.base + reg);
+}
+
+static inline u8 sossi_read_reg8(int reg)
+{
+ return readb(sossi.base + reg);
+}
+
+static inline void sossi_write_reg(int reg, u32 value)
+{
+ writel(value, sossi.base + reg);
+}
+
+static inline void sossi_write_reg16(int reg, u16 value)
+{
+ writew(value, sossi.base + reg);
+}
+
+static inline void sossi_write_reg8(int reg, u8 value)
+{
+ writeb(value, sossi.base + reg);
+}
+
+static void sossi_set_bits(int reg, u32 bits)
+{
+ sossi_write_reg(reg, sossi_read_reg(reg) | bits);
+}
+
+static void sossi_clear_bits(int reg, u32 bits)
+{
+ sossi_write_reg(reg, sossi_read_reg(reg) & ~bits);
+}
+
+#define MOD_CONF_CTRL_1 0xfffe1110
+#define CONF_SOSSI_RESET_R (1 << 23)
+#define CONF_MOD_SOSSI_CLK_EN_R (1 << 16)
+
+static void sossi_dma_callback(void *data);
+
+static int sossi_init(void)
+{
+ u32 l, k;
+ struct clk *dpll_clk;
+ int r;
+
+ sossi.base = IO_ADDRESS(OMAP_SOSSI_BASE);
+
+ dpll_clk = clk_get(NULL, "ck_dpll1");
+ if (IS_ERR(dpll_clk)) {
+ pr_err("can't get dpll1 clock\n");
+ return PTR_ERR(dpll_clk);
+ }
+
+ sossi.dpll_khz = clk_get_rate(dpll_clk) / 1000;
+ clk_put(dpll_clk);
+
+ sossi_extif.max_transmit_size = SOSSI_MAX_XMIT_BYTES;
+
+ /* Reset and enable the SoSSI module */
+ l = omap_readl(MOD_CONF_CTRL_1);
+ l |= CONF_SOSSI_RESET_R;
+ omap_writel(l, MOD_CONF_CTRL_1);
+ l &= ~CONF_SOSSI_RESET_R;
+ omap_writel(l, MOD_CONF_CTRL_1);
+
+ l |= CONF_MOD_SOSSI_CLK_EN_R;
+ omap_writel(l, MOD_CONF_CTRL_1);
+
+ omap_writel(omap_readl(ARM_IDLECT2) | (1 << 11), ARM_IDLECT2);
+ omap_writel(omap_readl(ARM_IDLECT1) | (1 << 6), ARM_IDLECT1);
+
+ l = sossi_read_reg(SOSSI_INIT2_REG);
+ /* Enable and reset the SoSSI block */
+ l |= (1 << 0) | (1 << 1);
+ sossi_write_reg(SOSSI_INIT2_REG, l);
+ /* Take SoSSI out of reset */
+ l &= ~(1 << 1);
+ sossi_write_reg(SOSSI_INIT2_REG, l);
+
+ sossi_write_reg(SOSSI_ID_REG, 0);
+ l = sossi_read_reg(SOSSI_ID_REG);
+ k = sossi_read_reg(SOSSI_ID_REG);
+
+ if (l != 0x55555555 || k != 0xaaaaaaaa) {
+ pr_err("Invalid SoSSI sync pattern: %08x, %08x\n", l, k);
+ return -ENODEV;
+ }
+
+ if ((r = omap_lcdc_set_dma_callback(sossi_dma_callback, NULL)) < 0) {
+ pr_err("can't get LCDC IRQ\n");
+ return r;
+ }
+
+ l = sossi_read_reg(SOSSI_ID_REG); /* Component code */
+ l = sossi_read_reg(SOSSI_ID_REG);
+ pr_info(KERN_INFO MODULE_NAME ": version %d.%d initialized\n",
+ l >> 16, l & 0xffff);
+
+ l = sossi_read_reg(SOSSI_INIT1_REG);
+ l |= (1 << 19); /* DMA_MODE */
+ l &= ~(1 << 31); /* REORDERING */
+ sossi_write_reg(SOSSI_INIT1_REG, l);
+
+ return 0;
+}
+
+static void sossi_cleanup(void)
+{
+ omap_lcdc_free_dma_callback();
+}
+
+#define KHZ_TO_PS(x) (1000000000 / (x))
+
+static void sossi_get_clk_info(u32 *clk_period, u32 *max_clk_div)
+{
+ *clk_period = KHZ_TO_PS(sossi.dpll_khz);
+ *max_clk_div = 8;
+}
+
+static u32 ps_to_sossi_ticks(u32 ps, int div)
+{
+ u32 clk_period = KHZ_TO_PS(sossi.dpll_khz) * div;
+ return (clk_period + ps - 1) / clk_period;
+}
+
+static int calc_rd_timings(struct extif_timings *t)
+{
+ u32 tw0, tw1;
+ int reon, reoff, recyc, actim;
+ int div = t->clk_div;
+
+ /* Make sure that after conversion it still holds that:
+ * reoff > reon, recyc >= reoff, actim > reon
+ */
+ reon = ps_to_sossi_ticks(t->re_on_time, div);
+ /* reon will be exactly one sossi tick */
+ if (reon > 1)
+ return -1;
+
+ reoff = ps_to_sossi_ticks(t->re_off_time, div);
+
+ if (reoff <= reon)
+ reoff = reon + 1;
+
+ tw0 = reoff - reon;
+ if (tw0 > 0x10)
+ return -1;
+
+ recyc = ps_to_sossi_ticks(t->re_cycle_time, div);
+ if (recyc <= reoff)
+ recyc = reoff + 1;
+
+ tw1 = recyc - reoff;
+ if (tw1 > 0x40)
+ return -1;
+
+ actim = ps_to_sossi_ticks(t->access_time, div);
+ if (actim < reoff)
+ actim++;
+ /* access time (data hold time) will be exactly one sossi
+ * tick
+ */
+ if (actim - reoff > 1)
+ return -1;
+
+ t->tim[0] = tw0 - 1;
+ t->tim[1] = tw1 - 1;
+
+ return 0;
+}
+
+static int calc_wr_timings(struct extif_timings *t)
+{
+ u32 tw0, tw1;
+ int weon, weoff, wecyc;
+ int div = t->clk_div;
+
+ /* Make sure that after conversion it still holds that:
+ * weoff > weon, wecyc >= weoff
+ */
+ weon = ps_to_sossi_ticks(t->we_on_time, div);
+ /* weon will be exactly one sossi tick */
+ if (weon > 1)
+ return -1;
+
+ weoff = ps_to_sossi_ticks(t->we_off_time, div);
+ if (weoff <= weon)
+ weoff = weon + 1;
+ tw0 = weoff - weon;
+ if (tw0 > 0x10)
+ return -1;
+
+ wecyc = ps_to_sossi_ticks(t->we_cycle_time, div);
+ if (wecyc <= weoff)
+ wecyc = weoff + 1;
+
+ tw1 = wecyc - weoff;
+ if (tw1 > 0x40)
+ return -1;
+
+ t->tim[2] = tw0 - 1;
+ t->tim[3] = tw1 - 1;
+
+ return 0;
+}
+
+static int sossi_convert_timings(struct extif_timings *t)
+{
+ int r = 0;
+ int div = t->clk_div;
+
+ t->converted = 0;
+
+ if (div <= 0 || div > 8)
+ return -1;
+
+ /* no CS on SOSSI, so ignore cson, csoff, cs_pulsewidth */
+ if ((r = calc_rd_timings(t)) < 0)
+ return r;
+
+ if ((r = calc_wr_timings(t)) < 0)
+ return r;
+
+ t->tim[4] = div - 1;
+
+ t->converted = 1;
+
+ return 0;
+}
+
+static void sossi_set_timings(const struct extif_timings *t)
+{
+ BUG_ON(!t->converted);
+
+ sossi.clk_tw0[RD_ACCESS] = t->tim[0];
+ sossi.clk_tw1[RD_ACCESS] = t->tim[1];
+
+ sossi.clk_tw0[WR_ACCESS] = t->tim[2];
+ sossi.clk_tw1[WR_ACCESS] = t->tim[3];
+
+ sossi.clk_div = t->tim[4];
+}
+
+static void _set_timing(int div, int tw0, int tw1)
+{
+ u32 l;
+
+ DBGPRINT(2, "Using TW0 = %d, TW1 = %d, div = %d\n",
+ tw0 + 1, tw1 + 1, div + 1);
+
+ l = omap_readl(MOD_CONF_CTRL_1);
+ l &= ~(7 << 17);
+ l |= div << 17;
+ omap_writel(l, MOD_CONF_CTRL_1);
+
+ l = sossi_read_reg(SOSSI_INIT1_REG);
+ l &= ~((0x0f << 20) | (0x3f << 24));
+ l |= (tw0 << 20) | (tw1 << 24);
+ sossi_write_reg(SOSSI_INIT1_REG, l);
+}
+
+static inline void set_timing(int access)
+{
+ if (access != sossi.last_access) {
+ sossi.last_access = access;
+ _set_timing(sossi.clk_div,
+ sossi.clk_tw0[access], sossi.clk_tw1[access]);
+ }
+}
+
+static void sossi_set_bits_per_cycle(int bpc)
+{
+ u32 l;
+ int bus_pick_count, bus_pick_width;
+
+ DBGPRINT(2, "bits_per_cycle %d\n", bpc);
+ /* We set explicitly the the bus_pick_count as well, although
+ * with remapping/reordering disabled it will be calculated by HW
+ * as (32 / bus_pick_width).
+ */
+ switch (bpc) {
+ case 8:
+ bus_pick_count = 4;
+ bus_pick_width = 8;
+ break;
+ case 16:
+ bus_pick_count = 2;
+ bus_pick_width = 16;
+ break;
+ default:
+ BUG();
+ return;
+ }
+ l = sossi_read_reg(SOSSI_INIT3_REG);
+ sossi.bus_pick_width = bus_pick_width;
+ l &= ~0x3ff;
+ l |= ((bus_pick_count - 1) << 5) | ((bus_pick_width - 1) & 0x1f);
+ sossi_write_reg(SOSSI_INIT3_REG, l);
+}
+
+static void sossi_start_transfer(void)
+{
+ /* WE */
+ sossi_clear_bits(SOSSI_INIT2_REG, 1 << 4);
+ /* CS active low */
+ sossi_clear_bits(SOSSI_INIT1_REG, 1 << 30);
+ /* FIXME: locking? */
+}
+
+static void sossi_stop_transfer(void)
+{
+ /* WE */
+ sossi_set_bits(SOSSI_INIT2_REG, 1 << 4);
+ /* CS active low */
+ sossi_set_bits(SOSSI_INIT1_REG, 1 << 30);
+ /* FIXME: locking? */
+}
+
+static void wait_end_of_write(void)
+{
+ /* Before reading we must check if some writings are going on */
+ while (!(sossi_read_reg(SOSSI_INIT2_REG) & (1 << 3)));
+}
+
+static void send_data(const void *data, unsigned int len)
+{
+ while (len >= 4) {
+ sossi_write_reg(SOSSI_FIFO_REG, *(const u32 *) data);
+ len -= 4;
+ data += 4;
+ }
+ while (len >= 2) {
+ sossi_write_reg16(SOSSI_FIFO_REG, *(const u16 *) data);
+ len -= 2;
+ data += 2;
+ }
+ while (len) {
+ sossi_write_reg8(SOSSI_FIFO_REG, *(const u8 *) data);
+ len--;
+ data++;
+ }
+}
+
+static void set_cycles(unsigned int len)
+{
+ unsigned long nr_cycles = len / (sossi.bus_pick_width / 8);
+
+ BUG_ON((nr_cycles - 1) & ~0x3ffff);
+
+ sossi_clear_bits(SOSSI_INIT1_REG, 0x3ffff);
+ sossi_set_bits(SOSSI_INIT1_REG, (nr_cycles - 1) & 0x3ffff);
+}
+
+static void sossi_write_command(const void *data, unsigned int len)
+{
+ set_timing(WR_ACCESS);
+ /* CMD#/DATA */
+ sossi_clear_bits(SOSSI_INIT1_REG, 1 << 18);
+ set_cycles(len);
+ sossi_start_transfer();
+ send_data(data, len);
+ sossi_stop_transfer();
+ wait_end_of_write();
+}
+
+static void sossi_write_data(const void *data, unsigned int len)
+{
+ set_timing(WR_ACCESS);
+ /* CMD#/DATA */
+ sossi_set_bits(SOSSI_INIT1_REG, 1 << 18);
+ set_cycles(len);
+ sossi_start_transfer();
+ send_data(data, len);
+ sossi_stop_transfer();
+ wait_end_of_write();
+}
+
+static void sossi_transfer_area(int width, int height,
+ void (callback)(void *data), void *data)
+{
+ BUG_ON(callback == NULL);
+
+ sossi.lcdc_callback = callback;
+ sossi.lcdc_callback_data = data;
+
+ set_timing(WR_ACCESS);
+ /* CMD#/DATA */
+ sossi_set_bits(SOSSI_INIT1_REG, 1 << 18);
+ set_cycles(width * height * sossi.bus_pick_width / 8);
+
+ DBGPRINT(2, "SOSSI_INIT1_REG %08x\n", sossi_read_reg(SOSSI_INIT1_REG));
+
+ sossi_start_transfer();
+ omap_enable_lcd_dma();
+}
+
+static void sossi_dma_callback(void *data)
+{
+ omap_stop_lcd_dma();
+ sossi_stop_transfer();
+ sossi.lcdc_callback(sossi.lcdc_callback_data);
+}
+
+static void sossi_read_data(void *data, unsigned int len)
+{
+ set_timing(RD_ACCESS);
+ /* CMD#/DATA */
+ sossi_set_bits(SOSSI_INIT1_REG, 1 << 18);
+ set_cycles(len);
+ sossi_start_transfer();
+ while (len >= 4) {
+ *(u32 *) data = sossi_read_reg(SOSSI_FIFO_REG);
+ len -= 4;
+ data += 4;
+ }
+ while (len >= 2) {
+ *(u16 *) data = sossi_read_reg16(SOSSI_FIFO_REG);
+ len -= 2;
+ data += 2;
+ }
+ while (len) {
+ *(u8 *) data = sossi_read_reg8(SOSSI_FIFO_REG);
+ len--;
+ data++;
+ }
+ sossi_stop_transfer();
+}
+
+struct lcd_ctrl_extif sossi_extif = {
+ .init = sossi_init,
+ .cleanup = sossi_cleanup,
+ .get_clk_info = sossi_get_clk_info,
+ .convert_timings = sossi_convert_timings,
+ .set_timings = sossi_set_timings,
+ .set_bits_per_cycle = sossi_set_bits_per_cycle,
+ .write_command = sossi_write_command,
+ .read_data = sossi_read_data,
+ .write_data = sossi_write_data,
+ .transfer_area = sossi_transfer_area,
+};
--- /dev/null
+arch
+asm-offsets.h
+mach-types.h
#define LHV_MIN 0x0000
// Analog audio path control register
+#define STA_REG(x) ((x)<<6)
#define STE_ENABLED 0x0020
#define DAC_SELECTED 0x0010
#define BYPASS_ON 0x0008
#define TLV320AIC23ID1 (0x1a) // cs low
#define TLV320AIC23ID2 (0x1b) // cs high
+void tlv320aic23_power_up(void);
+void tlv320aic23_power_down(void);
+
#endif /* __ASM_ARCH_AIC23_H */
--- /dev/null
+/*
+ * linux/include/asm-arm/arch-omap/board-apollon.h
+ *
+ * Hardware definitions for Samsung OMAP24XX Apollon board.
+ *
+ * Initial creation by Kyungmin Park <kyungmin.park@samsung.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.
+ */
+
+#ifndef __ASM_ARCH_OMAP_APOLLON_H
+#define __ASM_ARCH_OMAP_APOLLON_H
+
+/* Placeholder for APOLLON specific defines */
+/* GPMC CS0 */
+#define APOLLON_CS0_BASE 0x00000000
+/* GPMC CS1 */
+#define APOLLON_CS1_BASE 0x08000000
+#define APOLLON_ETHR_START (APOLLON_CS1_BASE + 0x300)
+#define APOLLON_ETHR_GPIO_IRQ 74
+/* GPMC CS2 - reserved for OneNAND */
+#define APOLLON_CS2_BASE 0x10000000
+/* GPMC CS3 - reserved for NOR or NAND */
+#define APOLLON_CS3_BASE 0x18000000
+
+#endif /* __ASM_ARCH_OMAP_APOLLON_H */
+
/* At OMAP1610 Innovator the Ethernet is directly connected to CS1 */
#define OMAP1610_ETHR_START 0x04000300
-/* Samsung NAND flash at CS2B or CS3(NAND Boot) */
-#define OMAP_NAND_FLASH_START1 0x0A000000 /* CS2B */
-#define OMAP_NAND_FLASH_START2 0x0C000000 /* CS3 */
-
#endif /* __ASM_ARCH_OMAP_H2_H */
/* In OMAP1710 H3 the Ethernet is directly connected to CS1 */
#define OMAP1710_ETHR_START 0x04000300
-/* Samsung NAND flash at CS2B or CS3(NAND Boot) */
-#define OMAP_NAND_FLASH_START1 0x0A000000 /* CS2B */
-#define OMAP_NAND_FLASH_START2 0x0C000000 /* CS3 */
-
#define MAXIRQNUM (IH_BOARD_BASE)
#define MAXFIQNUM MAXIRQNUM
#define MAXSWINUM MAXIRQNUM
/* GPMC CS1 */
#define OMAP24XX_ETHR_START 0x08000300
#define OMAP24XX_ETHR_GPIO_IRQ 92
-
-#define H4_CS0_BASE 0x04000000
-
-#define H4_CS0_BASE 0x04000000
-
-#define H4_CS0_BASE 0x04000000
-
+#define H4_CS0_BASE 0x04000000
#endif /* __ASM_ARCH_OMAP_H4_H */
+++ /dev/null
-/*
- * Copyright (C) 2004 2N Telekomunikace, Ladislav Michl <michl@2n.cz>
- *
- * Hardware definitions for OMAP5910 based NetStar board.
- *
- * 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 __ASM_ARCH_NETSTAR_H
-#define __ASM_ARCH_NETSTAR_H
-
-#include <asm/arch/tc.h>
-
-#define OMAP_NAND_FLASH_START1 OMAP_CS1_PHYS + (1 << 23)
-#define OMAP_NAND_FLASH_START2 OMAP_CS1_PHYS + (2 << 23)
-
-#endif /* __ASM_ARCH_NETSTAR_H */
--- /dev/null
+/*
+ * linux/include/asm-arm/arch-omap/board-nokia.h
+ *
+ * Information structures for Nokia-specific board config data
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ */
+
+#ifndef _OMAP_BOARD_NOKIA_H
+#define _OMAP_BOARD_NOKIA_H
+
+#include <linux/types.h>
+
+#define OMAP_TAG_NOKIA_BT 0x4e01
+#define OMAP_TAG_WLAN_CX3110X 0x4e02
+#define OMAP_TAG_CBUS 0x4e03
+#define OMAP_TAG_EM_ASIC_BB5 0x4e04
+
+
+#define BT_CHIP_CSR 1
+#define BT_CHIP_TI 2
+
+#define BT_SYSCLK_12 1
+#define BT_SYSCLK_38_4 2
+
+struct omap_bluetooth_config {
+ u8 chip_type;
+ u8 bt_wakeup_gpio;
+ u8 host_wakeup_gpio;
+ u8 reset_gpio;
+ u8 bt_uart;
+ u8 bd_addr[6];
+ u8 bt_sysclk;
+};
+
+struct omap_wlan_cx3110x_config {
+ u8 chip_type;
+ s16 power_gpio;
+ s16 irq_gpio;
+ s16 spi_cs_gpio;
+};
+
+struct omap_cbus_config {
+ s16 clk_gpio;
+ s16 dat_gpio;
+ s16 sel_gpio;
+};
+
+struct omap_em_asic_bb5_config {
+ s16 retu_irq_gpio;
+ s16 tahvo_irq_gpio;
+};
+
+#endif
#define NR_IRQS (MAXIRQNUM + 1)
-/* Samsung NAND flash at CS2B or CS3(NAND Boot) */
-#define OMAP_NAND_FLASH_START1 0x0A000000 /* CS2B */
-#define OMAP_NAND_FLASH_START2 0x0C000000 /* CS3 */
-
#endif
#define OMAP_TAG_LCD 0x4f05
#define OMAP_TAG_GPIO_SWITCH 0x4f06
#define OMAP_TAG_UART 0x4f07
+#define OMAP_TAG_FBMEM 0x4f08
+#define OMAP_TAG_STI_CONSOLE 0x4f09
#define OMAP_TAG_BOOT_REASON 0x4f80
#define OMAP_TAG_FLASH_PART 0x4f81
+#define OMAP_TAG_VERSION_STR 0x4f82
struct omap_clock_config {
/* 0 for 12 MHz, 1 for 13 MHz and 2 for 19.2 MHz */
u32 console_speed;
};
+struct omap_sti_console_config {
+ unsigned enable:1;
+ u8 channel;
+};
+
struct omap_usb_config {
/* Configure drivers according to the connectors on your board:
* - "A" connector (rectagular)
char ctrl_name[16];
};
+struct omap_fbmem_config {
+ u32 fb_sram_start;
+ u32 fb_sram_size;
+ u32 fb_sdram_start;
+ u32 fb_sdram_size;
+};
+
/* Cover:
* high -> closed
* low -> open
int key_code:24; /* Linux key code */
};
+struct omap_uart_config {
+ /* Bit field of UARTs present; bit 0 --> UART1 */
+ unsigned int enabled_uarts;
+};
+
+
struct omap_flash_part_config {
char part_table[0];
};
char reason_str[12];
};
-struct omap_uart_config {
- /* Bit field of UARTs present; bit 0 --> UART1 */
- unsigned int enabled_uarts;
+struct omap_version_config {
+ char component[12];
+ char version[12];
};
+
+#include <asm-arm/arch-omap/board-nokia.h>
+
struct omap_board_config_entry {
u16 tag;
u16 len;
struct list_head node;
struct module *owner;
const char *name;
+ int id;
struct clk *parent;
unsigned long rate;
__u32 flags;
extern void followparent_recalc(struct clk * clk);
extern void clk_allow_idle(struct clk *clk);
extern void clk_deny_idle(struct clk *clk);
+extern int clk_get_usecount(struct clk *clk);
/* Clock flags */
#define RATE_CKCTL (1 << 0) /* Main fixed ratio clocks */
#define CM_PLL_SEL1 (1 << 18)
#define CM_PLL_SEL2 (1 << 19)
#define CM_SYSCLKOUT_SEL1 (1 << 20)
-#define CLOCK_IN_OMAP730 (1 << 21)
-#define CLOCK_IN_OMAP1510 (1 << 22)
-#define CLOCK_IN_OMAP16XX (1 << 23)
-#define CLOCK_IN_OMAP242X (1 << 24)
-#define CLOCK_IN_OMAP243X (1 << 25)
+#define CLOCK_IN_OMAP310 (1 << 21)
+#define CLOCK_IN_OMAP730 (1 << 22)
+#define CLOCK_IN_OMAP1510 (1 << 23)
+#define CLOCK_IN_OMAP16XX (1 << 24)
+#define CLOCK_IN_OMAP242X (1 << 25)
+#define CLOCK_IN_OMAP243X (1 << 26)
#endif
extern void omap_setup_lcd_dma(void);
extern void omap_enable_lcd_dma(void);
extern void omap_stop_lcd_dma(void);
+extern int omap_lcd_dma_ext_running(void);
extern void omap_set_lcd_dma_ext_controller(int external);
extern void omap_set_lcd_dma_single_transfer(int single);
extern void omap_set_lcd_dma_b1(unsigned long addr, u16 fb_xres, u16 fb_yres,
void omap_dm_timer_reset_counter(struct omap_dm_timer *timer);
int omap_dm_timers_active(void);
+u32 omap_dm_timer_modify_idlect_mask(u32 inputmask);
#endif /* __ASM_ARCH_TIMER_H */
#define OMAP_DSP_MBCMD_PM_ENABLE 0x01
#define OMAP_DSP_MBCMD_KFUNC_FBCTL 0x00
+#define OMAP_DSP_MBCMD_KFUNC_AUDIO_PWR 0x01
+#define OMAP_DSP_MBCMD_FBCTL_UPD 0x0000
#define OMAP_DSP_MBCMD_FBCTL_ENABLE 0x0002
#define OMAP_DSP_MBCMD_FBCTL_DISABLE 0x0003
+#define OMAP_DSP_MBCMD_AUDIO_PWR_UP 0x0000
+#define OMAP_DSP_MBCMD_AUDIO_PWR_DOWN1 0x0001
+#define OMAP_DSP_MBCMD_AUDIO_PWR_DOWN2 0x0002
+
#define OMAP_DSP_MBCMD_TDEL_SAFE 0x0000
#define OMAP_DSP_MBCMD_TDEL_KILL 0x0001
#ifndef ASM_ARCH_DSP_COMMON_H
#define ASM_ARCH_DSP_COMMON_H
-void omap_dsp_pm_suspend(void);
-void omap_dsp_pm_resume(void);
-void omap_dsp_request_mpui(void);
-void omap_dsp_release_mpui(void);
-int omap_dsp_request_mem(void);
-int omap_dsp_release_mem(void);
+extern void omap_dsp_request_mpui(void);
+extern void omap_dsp_release_mpui(void);
+extern int omap_dsp_request_mem(void);
+extern int omap_dsp_release_mem(void);
+
+extern void (*omap_dsp_audio_pwr_up_request)(int stage);
+extern void (*omap_dsp_audio_pwr_down_request)(int stage);
#endif /* ASM_ARCH_DSP_COMMON_H */
--- /dev/null
+/*
+ * linux/include/asm-arm/arch-omap/gpioexpander.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 __ASM_ARCH_OMAP_GPIOEXPANDER_H
+#define __ASM_ARCH_OMAP_GPIOEXPANDER_H
+
+/* Function Prototypes for GPIO Expander functions */
+
+int read_gpio_expa(u8 *, int);
+int write_gpio_expa(u8 , int);
+
+#endif /* __ASM_ARCH_OMAP_GPIOEXPANDER_H */
#include "board-h4.h"
#endif
+#ifdef CONFIG_MACH_OMAP_APOLLON
+#include "board-apollon.h"
+#endif
+
#ifdef CONFIG_MACH_OMAP_OSK
#include "board-osk.h"
#endif
#include "board-voiceblue.h"
#endif
-#ifdef CONFIG_MACH_NETSTAR
-#include "board-netstar.h"
-#endif
-
#endif /* !__ASSEMBLER__ */
#endif /* __ASM_ARCH_OMAP_HARDWARE_H */
--- /dev/null
+/*
+ * linux/include/asm-arm/arch-omap/irda.h
+ *
+ * Copyright (C) 2005-2006 Komal Shah <komal_shah802003@yahoo.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 ASMARM_ARCH_IRDA_H
+#define ASMARM_ARCH_IRDA_H
+
+/* board specific transceiver capabilities */
+
+#define IR_SEL 1 /* Selects IrDA */
+#define IR_SIRMODE 2
+#define IR_FIRMODE 4
+#define IR_MIRMODE 8
+
+struct omap_irda_config {
+ int transceiver_cap;
+ int (*transceiver_mode)(struct device *dev, int mode);
+ int (*select_irda)(struct device *dev, int state);
+ /* Very specific to the needs of some platforms (h3,h4)
+ * having calls which can sleep in irda_set_speed.
+ */
+ struct work_struct gpio_expa;
+ int rx_channel;
+ int tx_channel;
+ unsigned long dest_start;
+ unsigned long src_start;
+ int tx_trigger;
+ int rx_trigger;
+};
+
+#endif
#define INT_24XX_GPIO_BANK2 30
#define INT_24XX_GPIO_BANK3 31
#define INT_24XX_GPIO_BANK4 32
+#define INT_24XX_MCBSP1_IRQ_TX 59
+#define INT_24XX_MCBSP1_IRQ_RX 60
+#define INT_24XX_MCBSP2_IRQ_TX 62
+#define INT_24XX_MCBSP2_IRQ_RX 63
+#define INT_24XX_UART3_IRQ 74
/* Max. 128 level 2 IRQs (OMAP1610), 192 GPIOs (OMAP730) and
* 16 MPUIO lines */
--- /dev/null
+/*
+ * linux/include/asm-arm/arch-omap/keypad.h
+ *
+ * Copyright (C) 2006 Komal Shah <komal_shah802003@yahoo.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 ASMARM_ARCH_KEYPAD_H
+#define ASMARM_ARCH_KEYPAD_H
+
+struct omap_kp_platform_data {
+ int rows;
+ int cols;
+ int *keymap;
+ unsigned int rep:1;
+ /* specific to OMAP242x*/
+ unsigned int *row_gpios;
+ unsigned int *col_gpios;
+};
+
+/* Group (0..3) -- when multiple keys are pressed, only the
+ * keys pressed in the same group are considered as pressed. This is
+ * in order to workaround certain crappy HW designs that produce ghost
+ * keypresses. */
+#define GROUP_0 (0 << 16)
+#define GROUP_1 (1 << 16)
+#define GROUP_2 (2 << 16)
+#define GROUP_3 (3 << 16)
+#define GROUP_MASK GROUP_3
+
+#define KEY(col, row, val) (((col) << 28) | ((row) << 24) | (val))
+
+#endif
+
--- /dev/null
+#ifndef __LCD_LPH8923_H
+#define __LCD_LPH8923_H
+
+enum lcd_lph8923_test_num {
+ LCD_LPH8923_TEST_RGB_LINES,
+};
+
+enum lcd_lph8923_test_result {
+ LCD_LPH8923_TEST_SUCCESS,
+ LCD_LPH8923_TEST_INVALID,
+ LCD_LPH8923_TEST_FAILED,
+};
+
+#endif
#define OMAP1610_MCBSP2_BASE 0xfffb1000
#define OMAP1610_MCBSP3_BASE 0xe1017000
+#define OMAP24XX_MCBSP1_BASE 0x48074000
+#define OMAP24XX_MCBSP2_BASE 0x48076000
+
+#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP730)
+
#define OMAP_MCBSP_REG_DRR2 0x00
#define OMAP_MCBSP_REG_DRR1 0x02
#define OMAP_MCBSP_REG_DXR2 0x04
#define OMAP_MAX_MCBSP_COUNT 3
+#define AUDIO_MCBSP_DATAWRITE (OMAP1510_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1)
+#define AUDIO_MCBSP_DATAREAD (OMAP1510_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1)
+
+#define AUDIO_MCBSP OMAP_MCBSP1
+#define AUDIO_DMA_TX OMAP_DMA_MCBSP1_TX
+#define AUDIO_DMA_RX OMAP_DMA_MCBSP1_RX
+
+#elif defined(CONFIG_ARCH_OMAP24XX)
+
+#define OMAP_MCBSP_REG_DRR2 0x00
+#define OMAP_MCBSP_REG_DRR1 0x04
+#define OMAP_MCBSP_REG_DXR2 0x08
+#define OMAP_MCBSP_REG_DXR1 0x0C
+#define OMAP_MCBSP_REG_SPCR2 0x10
+#define OMAP_MCBSP_REG_SPCR1 0x14
+#define OMAP_MCBSP_REG_RCR2 0x18
+#define OMAP_MCBSP_REG_RCR1 0x1C
+#define OMAP_MCBSP_REG_XCR2 0x20
+#define OMAP_MCBSP_REG_XCR1 0x24
+#define OMAP_MCBSP_REG_SRGR2 0x28
+#define OMAP_MCBSP_REG_SRGR1 0x2C
+#define OMAP_MCBSP_REG_MCR2 0x30
+#define OMAP_MCBSP_REG_MCR1 0x34
+#define OMAP_MCBSP_REG_RCERA 0x38
+#define OMAP_MCBSP_REG_RCERB 0x3C
+#define OMAP_MCBSP_REG_XCERA 0x40
+#define OMAP_MCBSP_REG_XCERB 0x44
+#define OMAP_MCBSP_REG_PCR0 0x48
+#define OMAP_MCBSP_REG_RCERC 0x4C
+#define OMAP_MCBSP_REG_RCERD 0x50
+#define OMAP_MCBSP_REG_XCERC 0x54
+#define OMAP_MCBSP_REG_XCERD 0x58
+#define OMAP_MCBSP_REG_RCERE 0x5C
+#define OMAP_MCBSP_REG_RCERF 0x60
+#define OMAP_MCBSP_REG_XCERE 0x64
+#define OMAP_MCBSP_REG_XCERF 0x68
+#define OMAP_MCBSP_REG_RCERG 0x6C
+#define OMAP_MCBSP_REG_RCERH 0x70
+#define OMAP_MCBSP_REG_XCERG 0x74
+#define OMAP_MCBSP_REG_XCERH 0x78
+
+#define OMAP_MAX_MCBSP_COUNT 2
+
+#define AUDIO_MCBSP_DATAWRITE (OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR1)
+#define AUDIO_MCBSP_DATAREAD (OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1)
+
+#define AUDIO_MCBSP OMAP_MCBSP2
+#define AUDIO_DMA_TX OMAP24XX_DMA_MCBSP2_TX
+#define AUDIO_DMA_RX OMAP24XX_DMA_MCBSP2_RX
+
+#endif
+
#define OMAP_MCBSP_READ(base, reg) __raw_readw((base) + OMAP_MCBSP_REG_##reg)
#define OMAP_MCBSP_WRITE(base, reg, val) __raw_writew((val), (base) + OMAP_MCBSP_REG_##reg)
+
/************************** McBSP SPCR1 bit definitions ***********************/
#define RRST 0x0001
#define RRDY 0x0002
OMAP_MCBSP3,
} omap_mcbsp_id;
+typedef int __bitwise omap_mcbsp_io_type_t;
+#define OMAP_MCBSP_IRQ_IO ((__force omap_mcbsp_io_type_t) 1)
+#define OMAP_MCBSP_POLL_IO ((__force omap_mcbsp_io_type_t) 2)
+
typedef enum {
OMAP_MCBSP_WORD_8 = 0,
OMAP_MCBSP_WORD_12,
int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int length);
int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int length);
+int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word);
+int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 * word);
+
/* SPI specific API */
void omap_mcbsp_set_spi_mode(unsigned int id, const struct omap_mcbsp_spi_cfg * spi_cfg);
--- /dev/null
+#ifndef _OMAP2_MCSPI_H
+#define _OMAP2_MCSPI_H
+
+struct omap2_mcspi_platform_config {
+ unsigned long base;
+ unsigned short num_cs;
+};
+
+struct omap2_mcspi_device_config {
+ unsigned turbo_mode:1;
+
+ /* Do we want one channel enabled at the same time? */
+ unsigned single_channel:1;
+};
+
+#endif
#ifndef __ASM_ARCH_MENELAUS_H
#define __ASM_ARCH_MENELAUS_H
-extern void menelaus_mmc_register(void (*callback)(u8 card_mask),
+extern void menelaus_mmc_register(void (*callback)(unsigned long data, u8 card_mask),
unsigned long data);
extern void menelaus_mmc_remove(void);
extern void menelaus_mmc_opendrain(int enable);
* as mux config
*/
#define MUX_CFG_730(desc, mux_reg, mode_offset, mode, \
- pull_reg, pull_bit, pull_status, \
- pu_pd_reg, pu_pd_status, debug_status)\
+ pull_bit, pull_status, debug_status)\
{ \
.name = desc, \
.debug = debug_status, \
MUX_REG_730(mux_reg, mode_offset, mode) \
PULL_REG_730(mux_reg, pull_bit, pull_status) \
- PU_PD_REG(pu_pd_reg, pu_pd_status) \
+ PU_PD_REG(NA, 0) \
},
#define MUX_CFG_24XX(desc, reg_offset, mode, \
E4_730_KBC2,
F4_730_KBC3,
E3_730_KBC4,
+
+ /* USB */
+ AA17_730_USB_DM,
+ W16_730_USB_PU_EN,
+ W17_730_USB_VBUSI,
};
enum omap1xxx_index {
/* 24xx Menelaus interrupt */
W19_24XX_SYS_NIRQ,
+ /* 24xx clock */
+ W14_24XX_SYS_CLKOUT,
+
+ /* 242X McBSP */
+ Y15_24XX_MCBSP2_CLKX,
+ R14_24XX_MCBSP2_FSX,
+ W15_24XX_MCBSP2_DR,
+ V15_24XX_MCBSP2_DX,
+
/* 24xx GPIO */
+ M21_242X_GPIO11,
+ AA10_242X_GPIO13,
+ AA6_242X_GPIO14,
+ AA4_242X_GPIO15,
+ Y11_242X_GPIO16,
+ AA12_242X_GPIO17,
+ AA8_242X_GPIO58,
Y20_24XX_GPIO60,
+ W4__24XX_GPIO74,
M15_24XX_GPIO92,
+ V14_24XX_GPIO117,
+
+ P20_24XX_TSC_IRQ,
+
+ /* UART3 */
+ K15_24XX_UART3_TX,
+ K14_24XX_UART3_RX,
+
+ /* Keypad GPIO*/
+ T19_24XX_KBR0,
+ R19_24XX_KBR1,
+ V18_24XX_KBR2,
+ M21_24XX_KBR3,
+ E5__24XX_KBR4,
+ M18_24XX_KBR5,
+ R20_24XX_KBC0,
+ M14_24XX_KBC1,
+ H19_24XX_KBC2,
+ V17_24XX_KBC3,
+ P21_24XX_KBC4,
+ L14_24XX_KBC5,
+ N19_24XX_KBC6,
+
+ /* 24xx Menelaus Keypad GPIO */
+ B3__24XX_KBR5,
+ AA4_24XX_KBC2,
+ B13_24XX_KBC6,
};
#ifdef CONFIG_OMAP_MUX
#define OMAPFB_MIRROR OMAP_IOW(31, int)
#define OMAPFB_SYNC_GFX OMAP_IO(37)
#define OMAPFB_VSYNC OMAP_IO(38)
-#define OMAPFB_SET_UPDATE_MODE OMAP_IOW(40, enum omapfb_update_mode)
+#define OMAPFB_SET_UPDATE_MODE OMAP_IOW(40, int)
+#define OMAPFB_UPDATE_WINDOW_OLD OMAP_IOW(41, struct omapfb_update_window_old)
#define OMAPFB_GET_CAPS OMAP_IOR(42, unsigned long)
-#define OMAPFB_GET_UPDATE_MODE OMAP_IOW(43, enum omapfb_update_mode)
+#define OMAPFB_GET_UPDATE_MODE OMAP_IOW(43, int)
#define OMAPFB_LCD_TEST OMAP_IOW(45, int)
#define OMAPFB_CTRL_TEST OMAP_IOW(46, int)
#define OMAPFB_UPDATE_WINDOW OMAP_IOW(47, struct omapfb_update_window)
};
struct omapfb_update_window {
- u32 x, y;
- u32 width, height;
- u32 format;
+ __u32 x, y;
+ __u32 width, height;
+ __u32 format;
+};
+
+struct omapfb_update_window_old {
+ __u32 x, y;
+ __u32 width, height;
};
enum omapfb_plane {
};
struct omapfb_setup_plane {
- u8 plane;
- u8 channel_out;
- u32 offset;
- u32 pos_x, pos_y;
- u32 width, height;
- u32 color_mode;
+ __u8 plane;
+ __u8 channel_out;
+ __u32 offset;
+ __u32 pos_x, pos_y;
+ __u32 width, height;
+ __u32 color_mode;
};
struct omapfb_enable_plane {
- u8 plane;
- u8 enable;
+ __u8 plane;
+ __u8 enable;
};
enum omapfb_color_key_type {
};
struct omapfb_color_key {
- u8 channel_out;
- u32 background;
- u32 trans_key;
- u8 key_type;
+ __u8 channel_out;
+ __u32 background;
+ __u32 trans_key;
+ __u8 key_type;
};
enum omapfb_update_mode {
#include <linux/interrupt.h>
#include <linux/fb.h>
+#include <asm/arch/board.h>
+
#define OMAP_LCDC_INV_VSYNC 0x0001
#define OMAP_LCDC_INV_HSYNC 0x0002
#define OMAP_LCDC_INV_PIX_CLOCK 0x0004
int re_cycle_time;
int cs_pulse_width;
int access_time;
+
+ int clk_div;
+
+ u32 tim[5]; /* set by extif->convert_timings */
+
+ int converted;
};
struct lcd_ctrl_extif {
int (*init) (void);
void (*cleanup) (void);
+ void (*get_clk_info) (u32 *clk_period, u32 *max_clk_div);
+ int (*convert_timings) (struct extif_timings *timings);
void (*set_timings) (const struct extif_timings *timings);
- void (*write_command) (u32 cmd);
- u32 (*read_data) (void);
- void (*write_data) (u32 data);
+ void (*set_bits_per_cycle)(int bpc);
+ void (*write_command) (const void *buf, unsigned int len);
+ void (*read_data) (void *buf, unsigned int len);
+ void (*write_data) (const void *buf, unsigned int len);
void (*transfer_area) (int width, int height,
void (callback)(void * data), void *data);
+ unsigned long max_transmit_size;
};
+struct omapfb_notifier_block {
+ struct notifier_block nb;
+ void *data;
+};
+
+typedef int (*omapfb_notifier_callback_t)(struct omapfb_notifier_block *,
+ unsigned long event,
+ struct omapfb_device *fbdev);
+
struct lcd_ctrl {
const char *name;
void *data;
int (*init) (struct omapfb_device *fbdev,
int ext_mode, int req_vram_size);
void (*cleanup) (void);
+ void (*bind_client) (struct omapfb_notifier_block *nb);
void (*get_vram_layout)(unsigned long *size,
void **virt_base,
dma_addr_t *phys_base);
+ int (*mmap) (struct vm_area_struct *vma);
unsigned long (*get_caps) (void);
int (*set_update_mode)(enum omapfb_update_mode mode);
enum omapfb_update_mode (*get_update_mode)(void);
struct device *dev;
};
-extern struct lcd_panel h3_panel;
-extern struct lcd_panel h2_panel;
-extern struct lcd_panel p2_panel;
-extern struct lcd_panel osk_panel;
-extern struct lcd_panel innovator1610_panel;
-extern struct lcd_panel innovator1510_panel;
+struct omapfb_platform_data {
+ struct omap_lcd_config lcd;
+ struct omap_fbmem_config fbmem;
+};
+
+#define OMAPFB_EVENT_READY 1
+#define OMAPFB_EVENT_DISABLED 2
#ifdef CONFIG_ARCH_OMAP1
extern struct lcd_ctrl omap1_lcd_ctrl;
extern struct lcd_ctrl omap2_disp_ctrl;
#endif
+extern void omapfb_register_panel(struct lcd_panel *panel);
extern void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval);
+extern void omapfb_notify_clients(struct omapfb_device *fbdev,
+ unsigned long event);
+extern int omapfb_register_client(struct omapfb_notifier_block *nb,
+ omapfb_notifier_callback_t callback,
+ void *callback_data);
+extern int omapfb_unregister_client(struct omapfb_notifier_block *nb);
+extern int omapfb_update_window_async(struct omapfb_update_window *win,
+ void (*callback)(void *),
+ void *callback_data);
+
+/* in arch/arm/plat-omap/devices.c */
+extern void omapfb_reserve_mem(void);
#endif /* __KERNEL__ */
/*
* ----------------------------------------------------------------------------
- * Powermanagement bitmasks
+ * Power management bitmasks
* ----------------------------------------------------------------------------
*/
#define IDLE_WAIT_CYCLES 0x00000fff
#endif
#ifndef __ASSEMBLER__
+
+#include <linux/clk.h>
+
+extern void prevent_idle_sleep(void);
+extern void allow_idle_sleep(void);
+
+/**
+ * clk_deny_idle - Prevents the clock from being idled during MPU idle
+ * @clk: clock signal handle
+ */
+void clk_deny_idle(struct clk *clk);
+
+/**
+ * clk_allow_idle - Counters previous clk_deny_idle
+ * @clk: clock signal handle
+ */
+void clk_deny_idle(struct clk *clk);
+
extern void omap_pm_idle(void);
extern void omap_pm_suspend(void);
extern void omap730_cpu_suspend(unsigned short, unsigned short);
extern void omap1510_cpu_suspend(unsigned short, unsigned short);
extern void omap1610_cpu_suspend(unsigned short, unsigned short);
+extern void omap24xx_cpu_suspend(u32 dll_ctrl, u32 cpu_revision);
extern void omap730_idle_loop_suspend(void);
extern void omap1510_idle_loop_suspend(void);
extern void omap1610_idle_loop_suspend(void);
+extern void omap24xx_idle_loop_suspend(void);
+
+extern unsigned int omap730_cpu_suspend_sz;
+extern unsigned int omap1510_cpu_suspend_sz;
+extern unsigned int omap1610_cpu_suspend_sz;
+extern unsigned int omap24xx_cpu_suspend_sz;
+extern unsigned int omap730_idle_loop_suspend_sz;
+extern unsigned int omap1510_idle_loop_suspend_sz;
+extern unsigned int omap1610_idle_loop_suspend_sz;
+extern unsigned int omap24xx_idle_loop_suspend_sz;
#ifdef CONFIG_OMAP_SERIAL_WAKE
extern void omap_serial_wake_trigger(int enable);
#else
+#define omap_serial_wakeup_init() {}
#define omap_serial_wake_trigger(x) {}
#endif /* CONFIG_OMAP_SERIAL_WAKE */
-extern unsigned int omap730_cpu_suspend_sz;
-extern unsigned int omap730_idle_loop_suspend_sz;
-extern unsigned int omap1510_cpu_suspend_sz;
-extern unsigned int omap1510_idle_loop_suspend_sz;
-extern unsigned int omap1610_cpu_suspend_sz;
-extern unsigned int omap1610_idle_loop_suspend_sz;
-
#define ARM_SAVE(x) arm_sleep_save[ARM_SLEEP_SAVE_##x] = omap_readl(x)
#define ARM_RESTORE(x) omap_writel((arm_sleep_save[ARM_SLEEP_SAVE_##x]), (x))
#define ARM_SHOW(x) arm_sleep_save[ARM_SLEEP_SAVE_##x]
+#define DSP_SAVE(x) dsp_sleep_save[DSP_SLEEP_SAVE_##x] = __raw_readw(x)
+#define DSP_RESTORE(x) __raw_writew((dsp_sleep_save[DSP_SLEEP_SAVE_##x]), (x))
+#define DSP_SHOW(x) dsp_sleep_save[DSP_SLEEP_SAVE_##x]
+
#define ULPD_SAVE(x) ulpd_sleep_save[ULPD_SLEEP_SAVE_##x] = omap_readw(x)
#define ULPD_RESTORE(x) omap_writew((ulpd_sleep_save[ULPD_SLEEP_SAVE_##x]), (x))
#define ULPD_SHOW(x) ulpd_sleep_save[ULPD_SLEEP_SAVE_##x]
#define MPUI1610_RESTORE(x) omap_writel((mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x]), (x))
#define MPUI1610_SHOW(x) mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x]
+#define OMAP24XX_SAVE(x) omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x] = x
+#define OMAP24XX_RESTORE(x) x = omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x]
+#define OMAP24XX_SHOW(x) omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x]
+
/*
* List of global OMAP registers to preserve.
* More ones like CP and general purpose register values are preserved
ARM_SLEEP_SAVE_SIZE
};
+enum dsp_save_state {
+ DSP_SLEEP_SAVE_START = 0,
+ /*
+ * DSP registers 16 bits
+ */
+ DSP_SLEEP_SAVE_DSP_IDLECT2,
+ DSP_SLEEP_SAVE_SIZE
+};
+
enum ulpd_save_state {
ULPD_SLEEP_SAVE_START = 0,
/*
#endif
};
+enum omap24xx_save_state {
+ OMAP24XX_SLEEP_SAVE_START = 0,
+ OMAP24XX_SLEEP_SAVE_INTC_MIR0,
+ OMAP24XX_SLEEP_SAVE_INTC_MIR1,
+ OMAP24XX_SLEEP_SAVE_INTC_MIR2,
+ OMAP24XX_SLEEP_SAVE_CM_FCLKEN1_CORE,
+ OMAP24XX_SLEEP_SAVE_CM_FCLKEN2_CORE,
+ OMAP24XX_SLEEP_SAVE_CM_ICLKEN1_CORE,
+ OMAP24XX_SLEEP_SAVE_CM_ICLKEN2_CORE,
+ OMAP24XX_SLEEP_SAVE_CM_ICLKEN4_CORE,
+ OMAP24XX_SLEEP_SAVE_GPIO1_IRQENABLE1,
+ OMAP24XX_SLEEP_SAVE_GPIO2_IRQENABLE1,
+ OMAP24XX_SLEEP_SAVE_GPIO3_IRQENABLE1,
+ OMAP24XX_SLEEP_SAVE_GPIO4_IRQENABLE1,
+ OMAP24XX_SLEEP_SAVE_GPIO3_OE,
+ OMAP24XX_SLEEP_SAVE_GPIO4_OE,
+ OMAP24XX_SLEEP_SAVE_GPIO3_RISINGDETECT,
+ OMAP24XX_SLEEP_SAVE_GPIO3_FALLINGDETECT,
+ OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SPI1_NCS2,
+ OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_MCBSP1_DX,
+ OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SSI1_FLAG_TX,
+ OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SYS_NIRQW0,
+ OMAP24XX_SLEEP_SAVE_SIZE
+};
+
#endif /* ASSEMBLER */
#endif /* __ASM_ARCH_OMAP_PM_H */
/*
- * prcm.h - Access definations for use in OMAP24XX clock and power management
+ * linux/include/asm-arm/arch-omap/prcm.h
+ *
+ * Access definations for use in OMAP24XX clock and power management
*
* Copyright (C) 2005 Texas Instruments, Inc.
*
#ifndef __ASM_ARM_ARCH_DPM_PRCM_H
#define __ASM_ARM_ARCH_DPM_PRCM_H
-/* SET_PERFORMANCE_LEVEL PARAMETERS */
-#define PRCM_HALF_SPEED 1
-#define PRCM_FULL_SPEED 2
-
-#ifndef __ASSEMBLER__
-
-#define PRCM_REG32(offset) __REG32(OMAP24XX_PRCM_BASE + (offset))
-
-#define PRCM_REVISION PRCM_REG32(0x000)
-#define PRCM_SYSCONFIG PRCM_REG32(0x010)
-#define PRCM_IRQSTATUS_MPU PRCM_REG32(0x018)
-#define PRCM_IRQENABLE_MPU PRCM_REG32(0x01C)
-#define PRCM_VOLTCTRL PRCM_REG32(0x050)
-#define PRCM_VOLTST PRCM_REG32(0x054)
-#define PRCM_CLKSRC_CTRL PRCM_REG32(0x060)
-#define PRCM_CLKOUT_CTRL PRCM_REG32(0x070)
-#define PRCM_CLKEMUL_CTRL PRCM_REG32(0x078)
-#define PRCM_CLKCFG_CTRL PRCM_REG32(0x080)
-#define PRCM_CLKCFG_STATUS PRCM_REG32(0x084)
-#define PRCM_VOLTSETUP PRCM_REG32(0x090)
-#define PRCM_CLKSSETUP PRCM_REG32(0x094)
-#define PRCM_POLCTRL PRCM_REG32(0x098)
-
-/* GENERAL PURPOSE */
-#define GENERAL_PURPOSE1 PRCM_REG32(0x0B0)
-#define GENERAL_PURPOSE2 PRCM_REG32(0x0B4)
-#define GENERAL_PURPOSE3 PRCM_REG32(0x0B8)
-#define GENERAL_PURPOSE4 PRCM_REG32(0x0BC)
-#define GENERAL_PURPOSE5 PRCM_REG32(0x0C0)
-#define GENERAL_PURPOSE6 PRCM_REG32(0x0C4)
-#define GENERAL_PURPOSE7 PRCM_REG32(0x0C8)
-#define GENERAL_PURPOSE8 PRCM_REG32(0x0CC)
-#define GENERAL_PURPOSE9 PRCM_REG32(0x0D0)
-#define GENERAL_PURPOSE10 PRCM_REG32(0x0D4)
-#define GENERAL_PURPOSE11 PRCM_REG32(0x0D8)
-#define GENERAL_PURPOSE12 PRCM_REG32(0x0DC)
-#define GENERAL_PURPOSE13 PRCM_REG32(0x0E0)
-#define GENERAL_PURPOSE14 PRCM_REG32(0x0E4)
-#define GENERAL_PURPOSE15 PRCM_REG32(0x0E8)
-#define GENERAL_PURPOSE16 PRCM_REG32(0x0EC)
-#define GENERAL_PURPOSE17 PRCM_REG32(0x0F0)
-#define GENERAL_PURPOSE18 PRCM_REG32(0x0F4)
-#define GENERAL_PURPOSE19 PRCM_REG32(0x0F8)
-#define GENERAL_PURPOSE20 PRCM_REG32(0x0FC)
-
-/* MPU */
-#define CM_CLKSEL_MPU PRCM_REG32(0x140)
-#define CM_CLKSTCTRL_MPU PRCM_REG32(0x148)
-#define RM_RSTST_MPU PRCM_REG32(0x158)
-#define PM_WKDEP_MPU PRCM_REG32(0x1C8)
-#define PM_EVGENCTRL_MPU PRCM_REG32(0x1D4)
-#define PM_EVEGENONTIM_MPU PRCM_REG32(0x1D8)
-#define PM_EVEGENOFFTIM_MPU PRCM_REG32(0x1DC)
-#define PM_PWSTCTRL_MPU PRCM_REG32(0x1E0)
-#define PM_PWSTST_MPU PRCM_REG32(0x1E4)
-
-/* CORE */
-#define CM_FCLKEN1_CORE PRCM_REG32(0x200)
-#define CM_FCLKEN2_CORE PRCM_REG32(0x204)
-#define CM_FCLKEN3_CORE PRCM_REG32(0x208)
-#define CM_ICLKEN1_CORE PRCM_REG32(0x210)
-#define CM_ICLKEN2_CORE PRCM_REG32(0x214)
-#define CM_ICLKEN3_CORE PRCM_REG32(0x218)
-#define CM_ICLKEN4_CORE PRCM_REG32(0x21C)
-#define CM_IDLEST1_CORE PRCM_REG32(0x220)
-#define CM_IDLEST2_CORE PRCM_REG32(0x224)
-#define CM_IDLEST3_CORE PRCM_REG32(0x228)
-#define CM_IDLEST4_CORE PRCM_REG32(0x22C)
-#define CM_AUTOIDLE1_CORE PRCM_REG32(0x230)
-#define CM_AUTOIDLE2_CORE PRCM_REG32(0x234)
-#define CM_AUTOIDLE3_CORE PRCM_REG32(0x238)
-#define CM_AUTOIDLE4_CORE PRCM_REG32(0x23C)
-#define CM_CLKSEL1_CORE PRCM_REG32(0x240)
-#define CM_CLKSEL2_CORE PRCM_REG32(0x244)
-#define CM_CLKSTCTRL_CORE PRCM_REG32(0x248)
-#define PM_WKEN1_CORE PRCM_REG32(0x2A0)
-#define PM_WKEN2_CORE PRCM_REG32(0x2A4)
-#define PM_WKST1_CORE PRCM_REG32(0x2B0)
-#define PM_WKST2_CORE PRCM_REG32(0x2B4)
-#define PM_WKDEP_CORE PRCM_REG32(0x2C8)
-#define PM_PWSTCTRL_CORE PRCM_REG32(0x2E0)
-#define PM_PWSTST_CORE PRCM_REG32(0x2E4)
-
-/* GFX */
-#define CM_FCLKEN_GFX PRCM_REG32(0x300)
-#define CM_ICLKEN_GFX PRCM_REG32(0x310)
-#define CM_IDLEST_GFX PRCM_REG32(0x320)
-#define CM_CLKSEL_GFX PRCM_REG32(0x340)
-#define CM_CLKSTCTRL_GFX PRCM_REG32(0x348)
-#define RM_RSTCTRL_GFX PRCM_REG32(0x350)
-#define RM_RSTST_GFX PRCM_REG32(0x358)
-#define PM_WKDEP_GFX PRCM_REG32(0x3C8)
-#define PM_PWSTCTRL_GFX PRCM_REG32(0x3E0)
-#define PM_PWSTST_GFX PRCM_REG32(0x3E4)
-
-/* WAKE-UP */
-#define CM_FCLKEN_WKUP PRCM_REG32(0x400)
-#define CM_ICLKEN_WKUP PRCM_REG32(0x410)
-#define CM_IDLEST_WKUP PRCM_REG32(0x420)
-#define CM_AUTOIDLE_WKUP PRCM_REG32(0x430)
-#define CM_CLKSEL_WKUP PRCM_REG32(0x440)
-#define RM_RSTCTRL_WKUP PRCM_REG32(0x450)
-#define RM_RSTTIME_WKUP PRCM_REG32(0x454)
-#define RM_RSTST_WKUP PRCM_REG32(0x458)
-#define PM_WKEN_WKUP PRCM_REG32(0x4A0)
-#define PM_WKST_WKUP PRCM_REG32(0x4B0)
-
-/* CLOCKS */
-#define CM_CLKEN_PLL PRCM_REG32(0x500)
-#define CM_IDLEST_CKGEN PRCM_REG32(0x520)
-#define CM_AUTOIDLE_PLL PRCM_REG32(0x530)
-#define CM_CLKSEL1_PLL PRCM_REG32(0x540)
-#define CM_CLKSEL2_PLL PRCM_REG32(0x544)
-
-/* DSP */
-#define CM_FCLKEN_DSP PRCM_REG32(0x800)
-#define CM_ICLKEN_DSP PRCM_REG32(0x810)
-#define CM_IDLEST_DSP PRCM_REG32(0x820)
-#define CM_AUTOIDLE_DSP PRCM_REG32(0x830)
-#define CM_CLKSEL_DSP PRCM_REG32(0x840)
-#define CM_CLKSTCTRL_DSP PRCM_REG32(0x848)
-#define RM_RSTCTRL_DSP PRCM_REG32(0x850)
-#define RM_RSTST_DSP PRCM_REG32(0x858)
-#define PM_WKEN_DSP PRCM_REG32(0x8A0)
-#define PM_WKDEP_DSP PRCM_REG32(0x8C8)
-#define PM_PWSTCTRL_DSP PRCM_REG32(0x8E0)
-#define PM_PWSTST_DSP PRCM_REG32(0x8E4)
-#define PRCM_IRQSTATUS_DSP PRCM_REG32(0x8F0)
-#define PRCM_IRQENABLE_DSP PRCM_REG32(0x8F4)
-
-/* IVA */
-#define PRCM_IRQSTATUS_IVA PRCM_REG32(0x8F8)
-#define PRCM_IRQENABLE_IVA PRCM_REG32(0x8FC)
-
-/* Modem on 2430 */
-#define CM_FCLKEN_MDM PRCM_REG32(0xC00)
-#define CM_ICLKEN_MDM PRCM_REG32(0xC10)
-#define CM_IDLEST_MDM PRCM_REG32(0xC20)
-#define CM_CLKSEL_MDM PRCM_REG32(0xC40)
-
-/* FIXME: Move to header for 2430 */
-#define DISP_BASE (OMAP24XX_L4_IO_BASE+0x50000)
-#define DISP_REG32(offset) __REG32(DISP_BASE + (offset))
-
-#define OMAP24XX_GPMC_BASE (L3_24XX_BASE + 0xa000)
-#define GPMC_BASE (OMAP24XX_GPMC_BASE)
-#define GPMC_REG32(offset) __REG32(GPMC_BASE + (offset))
-
-#define GPT1_BASE (OMAP24XX_GPT1)
-#define GPT1_REG32(offset) __REG32(GPT1_BASE + (offset))
-
-/* Misc sysconfig */
-#define DISPC_SYSCONFIG DISP_REG32(0x410)
-#define SPI_BASE (OMAP24XX_L4_IO_BASE+0x98000)
-#define MCSPI1_SYSCONFIG __REG32(SPI_BASE + 0x10)
-#define MCSPI2_SYSCONFIG __REG32(SPI_BASE+0x2000 + 0x10)
-
-//#define DSP_MMU_SYSCONFIG 0x5A000010
-#define CAMERA_MMU_SYSCONFIG __REG32(DISP_BASE+0x2C10)
-//#define IVA_MMU_SYSCONFIG 0x5D000010
-//#define DSP_DMA_SYSCONFIG 0x00FCC02C
-#define CAMERA_DMA_SYSCONFIG __REG32(DISP_BASE+0x282C)
-#define SYSTEM_DMA_SYSCONFIG __REG32(DISP_BASE+0x602C)
-#define GPMC_SYSCONFIG GPMC_REG32(0x010)
-#define MAILBOXES_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x94010)
-#define UART1_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x6A054)
-#define UART2_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x6C054)
-#define UART3_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x6E054)
-//#define IVA_SYSCONFIG 0x5C060010
-#define SDRC_SYSCONFIG __REG32(OMAP24XX_SDRC_BASE+0x10)
-#define SMS_SYSCONFIG __REG32(OMAP24XX_SMS_BASE+0x10)
-#define SSI_SYSCONFIG __REG32(DISP_BASE+0x8010)
-//#define VLYNQ_SYSCONFIG 0x67FFFE10
-
-/* rkw - good cannidates for PM_ to start what nm was trying */
-#define OMAP24XX_GPT2 (OMAP24XX_L4_IO_BASE+0x2A000)
-#define OMAP24XX_GPT3 (OMAP24XX_L4_IO_BASE+0x78000)
-#define OMAP24XX_GPT4 (OMAP24XX_L4_IO_BASE+0x7A000)
-#define OMAP24XX_GPT5 (OMAP24XX_L4_IO_BASE+0x7C000)
-#define OMAP24XX_GPT6 (OMAP24XX_L4_IO_BASE+0x7E000)
-#define OMAP24XX_GPT7 (OMAP24XX_L4_IO_BASE+0x80000)
-#define OMAP24XX_GPT8 (OMAP24XX_L4_IO_BASE+0x82000)
-#define OMAP24XX_GPT9 (OMAP24XX_L4_IO_BASE+0x84000)
-#define OMAP24XX_GPT10 (OMAP24XX_L4_IO_BASE+0x86000)
-#define OMAP24XX_GPT11 (OMAP24XX_L4_IO_BASE+0x88000)
-#define OMAP24XX_GPT12 (OMAP24XX_L4_IO_BASE+0x8A000)
-
-#define GPTIMER1_SYSCONFIG GPT1_REG32(0x010)
-#define GPTIMER2_SYSCONFIG __REG32(OMAP24XX_GPT2 + 0x10)
-#define GPTIMER3_SYSCONFIG __REG32(OMAP24XX_GPT3 + 0x10)
-#define GPTIMER4_SYSCONFIG __REG32(OMAP24XX_GPT4 + 0x10)
-#define GPTIMER5_SYSCONFIG __REG32(OMAP24XX_GPT5 + 0x10)
-#define GPTIMER6_SYSCONFIG __REG32(OMAP24XX_GPT6 + 0x10)
-#define GPTIMER7_SYSCONFIG __REG32(OMAP24XX_GPT7 + 0x10)
-#define GPTIMER8_SYSCONFIG __REG32(OMAP24XX_GPT8 + 0x10)
-#define GPTIMER9_SYSCONFIG __REG32(OMAP24XX_GPT9 + 0x10)
-#define GPTIMER10_SYSCONFIG __REG32(OMAP24XX_GPT10 + 0x10)
-#define GPTIMER11_SYSCONFIG __REG32(OMAP24XX_GPT11 + 0x10)
-#define GPTIMER12_SYSCONFIG __REG32(OMAP24XX_GPT12 + 0x10)
-
-#define GPIOX_BASE(X) (OMAP24XX_GPIO_BASE+(0x2000*((X)-1)))
-
-#define GPIO1_SYSCONFIG __REG32((GPIOX_BASE(1)+0x10))
-#define GPIO2_SYSCONFIG __REG32((GPIOX_BASE(2)+0x10))
-#define GPIO3_SYSCONFIG __REG32((GPIOX_BASE(3)+0x10))
-#define GPIO4_SYSCONFIG __REG32((GPIOX_BASE(4)+0x10))
-
-/* GP TIMER 1 */
-#define GPTIMER1_TISTAT GPT1_REG32(0x014)
-#define GPTIMER1_TISR GPT1_REG32(0x018)
-#define GPTIMER1_TIER GPT1_REG32(0x01C)
-#define GPTIMER1_TWER GPT1_REG32(0x020)
-#define GPTIMER1_TCLR GPT1_REG32(0x024)
-#define GPTIMER1_TCRR GPT1_REG32(0x028)
-#define GPTIMER1_TLDR GPT1_REG32(0x02C)
-#define GPTIMER1_TTGR GPT1_REG32(0x030)
-#define GPTIMER1_TWPS GPT1_REG32(0x034)
-#define GPTIMER1_TMAR GPT1_REG32(0x038)
-#define GPTIMER1_TCAR1 GPT1_REG32(0x03C)
-#define GPTIMER1_TSICR GPT1_REG32(0x040)
-#define GPTIMER1_TCAR2 GPT1_REG32(0x044)
-
-/* rkw -- base fix up please... */
-#define GPTIMER3_TISR __REG32(OMAP24XX_L4_IO_BASE+0x78018)
-
-/* SDRC */
-#define SDRC_DLLA_CTRL __REG32(OMAP24XX_SDRC_BASE+0x060)
-#define SDRC_DLLA_STATUS __REG32(OMAP24XX_SDRC_BASE+0x064)
-#define SDRC_DLLB_CTRL __REG32(OMAP24XX_SDRC_BASE+0x068)
-#define SDRC_DLLB_STATUS __REG32(OMAP24XX_SDRC_BASE+0x06C)
-#define SDRC_POWER __REG32(OMAP24XX_SDRC_BASE+0x070)
-#define SDRC_MR_0 __REG32(OMAP24XX_SDRC_BASE+0x084)
-
-/* GPIO 1 */
-#define GPIO1_BASE GPIOX_BASE(1)
-#define GPIO1_REG32(offset) __REG32(GPIO1_BASE + (offset))
-#define GPIO1_IRQENABLE1 GPIO1_REG32(0x01C)
-#define GPIO1_IRQSTATUS1 GPIO1_REG32(0x018)
-#define GPIO1_IRQENABLE2 GPIO1_REG32(0x02C)
-#define GPIO1_IRQSTATUS2 GPIO1_REG32(0x028)
-#define GPIO1_WAKEUPENABLE GPIO1_REG32(0x020)
-#define GPIO1_RISINGDETECT GPIO1_REG32(0x048)
-#define GPIO1_DATAIN GPIO1_REG32(0x038)
-#define GPIO1_OE GPIO1_REG32(0x034)
-#define GPIO1_DATAOUT GPIO1_REG32(0x03C)
-
-/* GPIO2 */
-#define GPIO2_BASE GPIOX_BASE(2)
-#define GPIO2_REG32(offset) __REG32(GPIO2_BASE + (offset))
-#define GPIO2_IRQENABLE1 GPIO2_REG32(0x01C)
-#define GPIO2_IRQSTATUS1 GPIO2_REG32(0x018)
-#define GPIO2_IRQENABLE2 GPIO2_REG32(0x02C)
-#define GPIO2_IRQSTATUS2 GPIO2_REG32(0x028)
-#define GPIO2_WAKEUPENABLE GPIO2_REG32(0x020)
-#define GPIO2_RISINGDETECT GPIO2_REG32(0x048)
-#define GPIO2_DATAIN GPIO2_REG32(0x038)
-#define GPIO2_OE GPIO2_REG32(0x034)
-#define GPIO2_DATAOUT GPIO2_REG32(0x03C)
-
-/* GPIO 3 */
-#define GPIO3_BASE GPIOX_BASE(3)
-#define GPIO3_REG32(offset) __REG32(GPIO3_BASE + (offset))
-#define GPIO3_IRQENABLE1 GPIO3_REG32(0x01C)
-#define GPIO3_IRQSTATUS1 GPIO3_REG32(0x018)
-#define GPIO3_IRQENABLE2 GPIO3_REG32(0x02C)
-#define GPIO3_IRQSTATUS2 GPIO3_REG32(0x028)
-#define GPIO3_WAKEUPENABLE GPIO3_REG32(0x020)
-#define GPIO3_RISINGDETECT GPIO3_REG32(0x048)
-#define GPIO3_FALLINGDETECT GPIO3_REG32(0x04C)
-#define GPIO3_DATAIN GPIO3_REG32(0x038)
-#define GPIO3_OE GPIO3_REG32(0x034)
-#define GPIO3_DATAOUT GPIO3_REG32(0x03C)
-#define GPIO3_DEBOUNCENABLE GPIO3_REG32(0x050)
-#define GPIO3_DEBOUNCINGTIME GPIO3_REG32(0x054)
-
-/* GPIO 4 */
-#define GPIO4_BASE GPIOX_BASE(4)
-#define GPIO4_REG32(offset) __REG32(GPIO4_BASE + (offset))
-#define GPIO4_IRQENABLE1 GPIO4_REG32(0x01C)
-#define GPIO4_IRQSTATUS1 GPIO4_REG32(0x018)
-#define GPIO4_IRQENABLE2 GPIO4_REG32(0x02C)
-#define GPIO4_IRQSTATUS2 GPIO4_REG32(0x028)
-#define GPIO4_WAKEUPENABLE GPIO4_REG32(0x020)
-#define GPIO4_RISINGDETECT GPIO4_REG32(0x048)
-#define GPIO4_FALLINGDETECT GPIO4_REG32(0x04C)
-#define GPIO4_DATAIN GPIO4_REG32(0x038)
-#define GPIO4_OE GPIO4_REG32(0x034)
-#define GPIO4_DATAOUT GPIO4_REG32(0x03C)
-#define GPIO4_DEBOUNCENABLE GPIO4_REG32(0x050)
-#define GPIO4_DEBOUNCINGTIME GPIO4_REG32(0x054)
-
-
-/* IO CONFIG */
-#define CONTROL_BASE (OMAP24XX_CTRL_BASE)
-#define CONTROL_REG32(offset) __REG32(CONTROL_BASE + (offset))
-
-#define CONTROL_PADCONF_SPI1_NCS2 CONTROL_REG32(0x104)
-#define CONTROL_PADCONF_SYS_XTALOUT CONTROL_REG32(0x134)
-#define CONTROL_PADCONF_UART1_RX CONTROL_REG32(0x0C8)
-#define CONTROL_PADCONF_MCBSP1_DX CONTROL_REG32(0x10C)
-#define CONTROL_PADCONF_GPMC_NCS4 CONTROL_REG32(0x090)
-#define CONTROL_PADCONF_DSS_D5 CONTROL_REG32(0x0B8)
-#define CONTROL_PADCONF_DSS_D9 CONTROL_REG32(0x0BC)
-#define CONTROL_PADCONF_DSS_D13 CONTROL_REG32(0x0C0)
-#define CONTROL_PADCONF_DSS_VSYNC CONTROL_REG32(0x0CC)
-
-/* CONTROL */
-#define CONTROL_DEVCONF CONTROL_REG32(0x274)
-
-/* INTERRUPT CONTROLLER */
-#define INTC_BASE (OMAP24XX_L4_IO_BASE+0xfe000)
-#define INTC_REG32(offset) __REG32(INTC_BASE + (offset))
-
-#define INTC1_U_BASE INTC_REG32(0x000)
-#define INTC_MIR0 INTC_REG32(0x084)
-#define INTC_MIR_SET0 INTC_REG32(0x08C)
-#define INTC_MIR_CLEAR0 INTC_REG32(0x088)
-#define INTC_ISR_CLEAR0 INTC_REG32(0x094)
-#define INTC_MIR1 INTC_REG32(0x0A4)
-#define INTC_MIR_SET1 INTC_REG32(0x0AC)
-#define INTC_MIR_CLEAR1 INTC_REG32(0x0A8)
-#define INTC_ISR_CLEAR1 INTC_REG32(0x0B4)
-#define INTC_MIR2 INTC_REG32(0x0C4)
-#define INTC_MIR_SET2 INTC_REG32(0x0CC)
-#define INTC_MIR_CLEAR2 INTC_REG32(0x0C8)
-#define INTC_ISR_CLEAR2 INTC_REG32(0x0D4)
-#define INTC_SIR_IRQ INTC_REG32(0x040)
-#define INTC_CONTROL INTC_REG32(0x048)
-#define INTC_ILR11 INTC_REG32(0x12C)
-#define INTC_ILR32 INTC_REG32(0x180)
-#define INTC_ILR37 INTC_REG32(0x194)
-#define INTC_SYSCONFIG INTC_REG32(0x010)
-
-/* RAM FIREWALL */
-#define RAMFW_BASE (0x68005000)
-#define RAMFW_REG32(offset) __REG32(RAMFW_BASE + (offset))
-
-#define RAMFW_REQINFOPERM0 RAMFW_REG32(0x048)
-#define RAMFW_READPERM0 RAMFW_REG32(0x050)
-#define RAMFW_WRITEPERM0 RAMFW_REG32(0x058)
-
-/* GPMC CS1 FPGA ON USER INTERFACE MODULE */
-//#define DEBUG_BOARD_LED_REGISTER 0x04000014
-
-/* GPMC CS0 */
-#define GPMC_CONFIG1_0 GPMC_REG32(0x060)
-#define GPMC_CONFIG2_0 GPMC_REG32(0x064)
-#define GPMC_CONFIG3_0 GPMC_REG32(0x068)
-#define GPMC_CONFIG4_0 GPMC_REG32(0x06C)
-#define GPMC_CONFIG5_0 GPMC_REG32(0x070)
-#define GPMC_CONFIG6_0 GPMC_REG32(0x074)
-#define GPMC_CONFIG7_0 GPMC_REG32(0x078)
-
-/* GPMC CS1 */
-#define GPMC_CONFIG1_1 GPMC_REG32(0x090)
-#define GPMC_CONFIG2_1 GPMC_REG32(0x094)
-#define GPMC_CONFIG3_1 GPMC_REG32(0x098)
-#define GPMC_CONFIG4_1 GPMC_REG32(0x09C)
-#define GPMC_CONFIG5_1 GPMC_REG32(0x0a0)
-#define GPMC_CONFIG6_1 GPMC_REG32(0x0a4)
-#define GPMC_CONFIG7_1 GPMC_REG32(0x0a8)
-
-/* DSS */
-#define DSS_CONTROL DISP_REG32(0x040)
-#define DISPC_CONTROL DISP_REG32(0x440)
-#define DISPC_SYSSTATUS DISP_REG32(0x414)
-#define DISPC_IRQSTATUS DISP_REG32(0x418)
-#define DISPC_IRQENABLE DISP_REG32(0x41C)
-#define DISPC_CONFIG DISP_REG32(0x444)
-#define DISPC_DEFAULT_COLOR0 DISP_REG32(0x44C)
-#define DISPC_DEFAULT_COLOR1 DISP_REG32(0x450)
-#define DISPC_TRANS_COLOR0 DISP_REG32(0x454)
-#define DISPC_TRANS_COLOR1 DISP_REG32(0x458)
-#define DISPC_LINE_NUMBER DISP_REG32(0x460)
-#define DISPC_TIMING_H DISP_REG32(0x464)
-#define DISPC_TIMING_V DISP_REG32(0x468)
-#define DISPC_POL_FREQ DISP_REG32(0x46C)
-#define DISPC_DIVISOR DISP_REG32(0x470)
-#define DISPC_SIZE_DIG DISP_REG32(0x478)
-#define DISPC_SIZE_LCD DISP_REG32(0x47C)
-#define DISPC_GFX_BA0 DISP_REG32(0x480)
-#define DISPC_GFX_BA1 DISP_REG32(0x484)
-#define DISPC_GFX_POSITION DISP_REG32(0x488)
-#define DISPC_GFX_SIZE DISP_REG32(0x48C)
-#define DISPC_GFX_ATTRIBUTES DISP_REG32(0x4A0)
-#define DISPC_GFX_FIFO_THRESHOLD DISP_REG32(0x4A4)
-#define DISPC_GFX_ROW_INC DISP_REG32(0x4AC)
-#define DISPC_GFX_PIXEL_INC DISP_REG32(0x4B0)
-#define DISPC_GFX_WINDOW_SKIP DISP_REG32(0x4B4)
-#define DISPC_GFX_TABLE_BA DISP_REG32(0x4B8)
-#define DISPC_DATA_CYCLE1 DISP_REG32(0x5D4)
-#define DISPC_DATA_CYCLE2 DISP_REG32(0x5D8)
-#define DISPC_DATA_CYCLE3 DISP_REG32(0x5DC)
-
-/* Wake up define for board */
-#define GPIO97 (1 << 1)
-#define GPIO88 (1 << 24)
-
-#endif /* __ASSEMBLER__ */
+u32 omap_prcm_get_reset_sources(void);
#endif
u32 mem_type);
extern u32 omap2_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass);
+extern unsigned long omap_fb_sram_start;
+extern unsigned long omap_fb_sram_size;
/* Do not use these */
extern void sram_reprogram_clock(u32 ckctl, u32 dpllctl);
--- /dev/null
+#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 */
#include <asm/mach-types.h>
#include <asm/hardware.h>
-#include <asm/arch/prcm.h>
#ifndef CONFIG_MACH_VOICEBLUE
#define voiceblue_reset() do {} while (0)
#endif
+extern void omap_prcm_arch_reset(char mode);
+
static inline void arch_idle(void)
{
cpu_do_idle();
omap_writew(1, ARM_RSTCT1);
}
-static inline void omap2_arch_reset(char mode)
-{
- u32 rate;
- struct clk *vclk, *sclk;
-
- vclk = clk_get(NULL, "virt_prcm_set");
- sclk = clk_get(NULL, "sys_ck");
- rate = clk_get_rate(sclk);
- clk_set_rate(vclk, rate); /* go to bypass for OMAP limitation */
- RM_RSTCTRL_WKUP |= 2;
-}
-
static inline void arch_reset(char mode)
{
if (!cpu_is_omap24xx())
omap1_arch_reset(mode);
else
- omap2_arch_reset(mode);
+ omap_prcm_arch_reset(mode);
}
#endif
#include <linux/config.h>
#include <linux/mm.h> /* need struct page */
+#include <linux/device.h>
#include <asm/scatterlist.h>
--- /dev/null
+/*
+ *
+ * TI TSC2101 Audio CODEC and TS control registers definition
+ *
+ *
+ * Copyright 2003 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * source@mvista.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.
+ */
+
+#ifndef __ASM_HARDWARE_TSC2101_H
+#define __ASM_HARDWARE_TSC2101_H
+
+/* Page 0 Touch Screen Data Registers */
+#define TSC2101_TS_X (0x00)
+#define TSC2101_TS_Y (0x01)
+#define TSC2101_TS_Z1 (0x02)
+#define TSC2101_TS_Z2 (0x03)
+#define TSC2101_TS_BAT (0x05)
+#define TSC2101_TS_AUX1 (0x07)
+#define TSC2101_TS_AUX2 (0x08)
+#define TSC2101_TS_TEMP1 (0x09)
+#define TSC2101_TS_TEMP2 (0x0A)
+
+/* Page 1 Touch Screen Control registers */
+#define TSC2101_TS_ADC_CTRL (0x00)
+#define TSC2101_TS_STATUS (0x01)
+#define TSC2101_TS_BUFFER_CTRL (0x02)
+#define TSC2101_TS_REF_CTRL (0x03)
+#define TSC2101_TS_RESET_CTRL (0x04)
+#define TSC2101_TS_CONFIG_CTRL (0x05)
+#define TSC2101_TS_TEMP_MAX_THRESHOLD (0x06)
+#define TSC2101_TS_TEMP_MIN_THRESHOLD (0x07)
+#define TSC2101_TS_AUX1_MAX_THRESHOLD (0x08)
+#define TSC2101_TS_AUX1_MIN_THRESHOLD (0x09)
+#define TSC2101_TS_AUX2_MAX_THRESHOLD (0x0A)
+#define TSC2101_TS_AUX2_MIN_THRESHOLD (0x0B)
+#define TSC2101_TS_MEASURE_CONFIG (0x0C)
+#define TSC2101_TS_PROG_DELAY (0x0D)
+
+/* Page 2 Audio codec Control registers */
+#define TSC2101_AUDIO_CTRL_1 (0x00)
+#define TSC2101_HEADSET_GAIN_CTRL (0x01)
+#define TSC2101_DAC_GAIN_CTRL (0x02)
+#define TSC2101_MIXER_PGA_CTRL (0x03)
+#define TSC2101_AUDIO_CTRL_2 (0x04)
+#define TSC2101_CODEC_POWER_CTRL (0x05)
+#define TSC2101_AUDIO_CTRL_3 (0x06)
+#define TSC2101_LCH_BASS_BOOST_N0 (0x07)
+#define TSC2101_LCH_BASS_BOOST_N1 (0x08)
+#define TSC2101_LCH_BASS_BOOST_N2 (0x09)
+#define TSC2101_LCH_BASS_BOOST_N3 (0x0A)
+#define TSC2101_LCH_BASS_BOOST_N4 (0x0B)
+#define TSC2101_LCH_BASS_BOOST_N5 (0x0C)
+#define TSC2101_LCH_BASS_BOOST_D1 (0x0D)
+#define TSC2101_LCH_BASS_BOOST_D2 (0x0E)
+#define TSC2101_LCH_BASS_BOOST_D4 (0x0F)
+#define TSC2101_LCH_BASS_BOOST_D5 (0x10)
+#define TSC2101_RCH_BASS_BOOST_N0 (0x11)
+#define TSC2101_RCH_BASS_BOOST_N1 (0x12)
+#define TSC2101_RCH_BASS_BOOST_N2 (0x13)
+#define TSC2101_RCH_BASS_BOOST_N3 (0x14)
+#define TSC2101_RCH_BASS_BOOST_N4 (0x15)
+#define TSC2101_RCH_BASS_BOOST_N5 (0x16)
+#define TSC2101_RCH_BASS_BOOST_D1 (0x17)
+#define TSC2101_RCH_BASS_BOOST_D2 (0x18)
+#define TSC2101_RCH_BASS_BOOST_D4 (0x19)
+#define TSC2101_RCH_BASS_BOOST_D5 (0x1A)
+#define TSC2101_PLL_PROG_1 (0x1B)
+#define TSC2101_PLL_PROG_2 (0x1C)
+#define TSC2101_AUDIO_CTRL_4 (0x1D)
+#define TSC2101_HANDSET_GAIN_CTRL (0x1E)
+#define TSC2101_BUZZER_GAIN_CTRL (0x1F)
+#define TSC2101_AUDIO_CTRL_5 (0x20)
+#define TSC2101_AUDIO_CTRL_6 (0x21)
+#define TSC2101_AUDIO_CTRL_7 (0x22)
+#define TSC2101_GPIO_CTRL (0x23)
+#define TSC2101_AGC_CTRL (0x24)
+#define TSC2101_POWERDOWN_STS (0x25)
+#define TSC2101_MIC_AGC_CONTROL (0x26)
+#define TSC2101_CELL_AGC_CONTROL (0x27)
+
+/* Bit field definitions for TS Control */
+#define TSC2101_DATA_AVAILABLE 0x4000
+#define TSC2101_BUFFERMODE_DISABLE 0x0
+#define TSC2101_REF_POWERUP 0x16
+#define TSC2101_ENABLE_TOUCHDETECT 0x08
+#define TSC2101_PRG_DELAY 0x0900
+#define TSC2101_ADC_CONTROL 0x8874
+#define TSC2101_ADC_POWERDOWN 0x4000
+
+/* Bit position */
+#define TSC2101_BIT(ARG) ((0x01)<<(ARG))
+
+/* Field masks for Audio Control 1 */
+#define AC1_ADCHPF(ARG) (((ARG) & 0x03) << 14)
+#define AC1_WLEN(ARG) (((ARG) & 0x03) << 10)
+#define AC1_DATFM(ARG) (((ARG) & 0x03) << 8)
+#define AC1_DACFS(ARG) (((ARG) & 0x07) << 3)
+#define AC1_ADCFS(ARG) (((ARG) & 0x07))
+
+/* Field masks for TSC2101_HEADSET_GAIN_CTRL */
+#define HGC_ADMUT_HED TSC2101_BIT(15)
+#define HGC_ADPGA_HED(ARG) (((ARG) & 0x7F) << 8)
+#define HGC_AGCTG_HED(ARG) (((ARG) & 0x07) << 5)
+#define HGC_AGCTC_HED(ARG) (((ARG) & 0x0F) << 1)
+#define HGC_AGCEN_HED (0x01)
+
+/* Field masks for TSC2101_DAC_GAIN_CTRL */
+#define DGC_DALMU TSC2101_BIT(15)
+#define DGC_DALVL(ARG) (((ARG) & 0x7F) << 8)
+#define DGC_DARMU TSC2101_BIT(7)
+#define DGC_DARVL(ARG) (((ARG) & 0x7F))
+
+/* Field masks for TSC2101_MIXER_PGA_CTRL */
+#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)
+
+/* Field formats for TSC2101_AUDIO_CTRL_2 */
+#define AC2_KCLEN TSC2101_BIT(15)
+#define AC2_KCLAC(ARG) (((ARG) & 0x07) << 12)
+#define AC2_APGASS TSC2101_BIT(11)
+#define AC2_KCLFRQ(ARG) (((ARG) & 0x07) << 8)
+#define AC2_KCLLN(ARG) (((ARG) & 0x0F) << 4)
+#define AC2_DLGAF TSC2101_BIT(3)
+#define AC2_DRGAF TSC2101_BIT(2)
+#define AC2_DASTC TSC2101_BIT(1)
+#define AC2_ADGAF (0x01)
+
+/* Field masks for TSC2101_CODEC_POWER_CTRL */
+#define CPC_MBIAS_HND TSC2101_BIT(15)
+#define CPC_MBIAS_HED TSC2101_BIT(14)
+#define CPC_ASTPWD TSC2101_BIT(13)
+#define CPC_SP1PWDN TSC2101_BIT(12)
+#define CPC_SP2PWDN TSC2101_BIT(11)
+#define CPC_DAPWDN TSC2101_BIT(10)
+#define CPC_ADPWDN TSC2101_BIT(9)
+#define CPC_VGPWDN TSC2101_BIT(8)
+#define CPC_COPWDN TSC2101_BIT(7)
+#define CPC_LSPWDN TSC2101_BIT(6)
+#define CPC_ADPWDF TSC2101_BIT(5)
+#define CPC_LDAPWDF TSC2101_BIT(4)
+#define CPC_RDAPWDF TSC2101_BIT(3)
+#define CPC_ASTPWF TSC2101_BIT(2)
+#define CPC_BASSBC TSC2101_BIT(1)
+#define CPC_DEEMPF (0x01)
+
+/* Field masks for TSC2101_AUDIO_CTRL_3 */
+#define AC3_DMSVOL(ARG) (((ARG) & 0x03) << 14)
+#define AC3_REFFS TSC2101_BIT(13)
+#define AC3_DAXFM TSC2101_BIT(12)
+#define AC3_SLVMS TSC2101_BIT(11)
+#define AC3_ADCOVF TSC2101_BIT(8)
+#define AC3_DALOVF TSC2101_BIT(7)
+#define AC3_DAROVF TSC2101_BIT(6)
+#define AC3_CLPST TSC2101_BIT(3)
+#define AC3_REVID(ARG) (((ARG) & 0x07))
+
+/* Field masks for TSC2101_PLL_PROG_1 */
+#define PLL1_PLLSEL TSC2101_BIT(15)
+#define PLL1_QVAL(ARG) (((ARG) & 0x0F) << 11)
+#define PLL1_PVAL(ARG) (((ARG) & 0x07) << 8)
+#define PLL1_I_VAL(ARG) (((ARG) & 0x3F) << 2)
+
+/* Field masks of TSC2101_PLL_PROG_2 */
+#define PLL2_D_VAL(ARG) (((ARG) & 0x3FFF) << 2)
+
+/* Field masks for TSC2101_AUDIO_CTRL_4 */
+#define AC4_ADSTPD TSC2101_BIT(15)
+#define AC4_DASTPD TSC2101_BIT(14)
+#define AC4_ASSTPD TSC2101_BIT(13)
+#define AC4_CISTPD TSC2101_BIT(12)
+#define AC4_BISTPD TSC2101_BIT(11)
+#define AC4_AGCHYS(ARG) (((ARG) & 0x03) << 9)
+#define AC4_MB_HED(ARG) (((ARG) & 0x03) << 7)
+#define AC4_MB_HND TSC2101_BIT(6)
+#define AC4_SCPFL TSC2101_BIT(1)
+
+/* Field masks settings for TSC2101_HANDSET_GAIN_CTRL */
+#define HNGC_ADMUT_HND TSC2101_BIT(15)
+#define HNGC_ADPGA_HND(ARG) (((ARG) & 0x7F) << 8)
+#define HNGC_AGCTG_HND(ARG) (((ARG) & 0x07) << 5)
+#define HNGC_AGCTC_HND(ARG) (((ARG) & 0x0F) << 1)
+#define HNGC_AGCEN_HND (0x01)
+
+/* Field masks settings for TSC2101_BUZZER_GAIN_CTRL */
+#define BGC_MUT_CP TSC2101_BIT(15)
+#define BGC_CPGA(ARG) (((ARG) & 0x7F) << 8)
+#define BGC_CPGF TSC2101_BIT(7)
+#define BGC_MUT_BU TSC2101_BIT(6)
+#define BGC_BPGA(ARG) (((ARG) & 0x0F) << 2)
+#define BGC_BUGF TSC2101_BIT(1)
+
+/* Field masks settings for TSC2101_AUDIO_CTRL_5 */
+#define AC5_DIFFIN TSC2101_BIT(15)
+#define AC5_DAC2SPK1(ARG) (((ARG) & 0x03) << 13)
+#define AC5_AST2SPK1 TSC2101_BIT(12)
+#define AC5_BUZ2SPK1 TSC2101_BIT(11)
+#define AC5_KCL2SPK1 TSC2101_BIT(10)
+#define AC5_CPI2SPK1 TSC2101_BIT(9)
+#define AC5_DAC2SPK2(ARG) (((ARG) & 0x03) << 7)
+#define AC5_AST2SPK2 TSC2101_BIT(6)
+#define AC5_BUZ2SPK2 TSC2101_BIT(5)
+#define AC5_KCL2SPK2 TSC2101_BIT(4)
+#define AC5_CPI2SPK2 TSC2101_BIT(3)
+#define AC5_MUTSPK1 TSC2101_BIT(2)
+#define AC5_MUTSPK2 TSC2101_BIT(1)
+#define AC5_HDSCPTC (0x01)
+
+/* Field masks settings for TSC2101_AUDIO_CTRL_6 */
+#define AC6_SPL2LSK TSC2101_BIT(15)
+#define AC6_AST2LSK TSC2101_BIT(14)
+#define AC6_BUZ2LSK TSC2101_BIT(13)
+#define AC6_KCL2LSK TSC2101_BIT(12)
+#define AC6_CPI2LSK TSC2101_BIT(11)
+#define AC6_MIC2CPO TSC2101_BIT(10)
+#define AC6_SPL2CPO TSC2101_BIT(9)
+#define AC6_SPR2CPO TSC2101_BIT(8)
+#define AC6_MUTLSPK TSC2101_BIT(7)
+#define AC6_MUTSPK2 TSC2101_BIT(6)
+#define AC6_LDSCPTC TSC2101_BIT(5)
+#define AC6_VGNDSCPTC TSC2101_BIT(4)
+#define AC6_CAPINTF TSC2101_BIT(3)
+
+/* Field masks settings for TSC2101_AUDIO_CTRL_7 */
+#define AC7_DETECT TSC2101_BIT(15)
+#define AC7_HESTYPE(ARG) (((ARG) & 0x03) << 13)
+#define AC7_HDDETFL TSC2101_BIT(12)
+#define AC7_BDETFL TSC2101_BIT(11)
+#define AC7_HDDEBNPG(ARG) (((ARG) & 0x03) << 9)
+#define AC7_BDEBNPG(ARG) (((ARG) & 0x03) << 6)
+#define AC7_DGPIO2 TSC2101_BIT(4)
+#define AC7_DGPIO1 TSC2101_BIT(3)
+#define AC7_CLKGPIO2 TSC2101_BIT(2)
+#define AC7_ADWSF(ARG) (((ARG) & 0x03))
+
+/* Field masks settings for TSC2101_GPIO_CTRL */
+#define GC_GPO2EN TSC2101_BIT(15)
+#define GC_GPO2SG TSC2101_BIT(14)
+#define GC_GPI2EN TSC2101_BIT(13)
+#define GC_GPI2SGF TSC2101_BIT(12)
+#define GC_GPO1EN TSC2101_BIT(11)
+#define GC_GPO1SG TSC2101_BIT(10)
+#define GC_GPI1EN TSC2101_BIT(9)
+#define GC_GPI1SGF TSC2101_BIT(8)
+
+/* Field masks for TSC2101_AGC_CTRL */
+#define AC_AGCNF_CELL TSC2101_BIT(14)
+#define AC_AGCNL(ARG) (((ARG) & 0x07) << 11)
+#define AC_AGCHYS_CELL(ARG) (((ARG) & 0x03) << 9)
+#define AC_CLPST_CELL TSC2101_BIT(8)
+#define AC_AGCTG_CELL(ARG) (((ARG) & 0x07) << 5)
+#define AC_AGCTC_CELL(ARG) (((ARG) & 0x0F) << 1)
+#define AC_AGCEN_CELL (0x01)
+
+/* Field masks for TSC2101_POWERDOWN_STS */
+#define PS_SPK1FL TSC2101_BIT(15)
+#define PS_SPK2FL TSC2101_BIT(14)
+#define PS_HNDFL TSC2101_BIT(13)
+#define PS_VGNDFL TSC2101_BIT(12)
+#define PS_LSPKFL TSC2101_BIT(11)
+#define PS_CELLFL TSC2101_BIT(10)
+#define PS_PSEQ TSC2101_BIT(5)
+#define PS_PSTIME TSC2101_BIT(4)
+
+/* Field masks for Register Mic AGC Control */
+#define MAC_MMPGA(ARG) (((ARG) & 0x7F) << 9)
+#define MAC_MDEBNS(ARG) (((ARG) & 0x07) << 6)
+#define MAC_MDEBSN(ARG) (((ARG) & 0x07) << 3)
+
+/* Field masks for Register Cellphone AGC Control */
+#define CAC_CMPGA(ARG) (((ARG) & 0x7F) << 9)
+#define CAC_CDEBNS(ARG) (((ARG) & 0x07) << 6)
+#define CAC_CDEBSN(ARG) (((ARG) & 0x07) << 3)
+
+#endif /* __ASM_HARDWARE_TSC2101_H */
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
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
*/
struct tag_acorn acorn;
+ /*
+ * OMAP specific
+ */
+ struct tag_omap omap;
+
/*
* DC21285 specific
*/
#define FB_ACCEL_NV_40 46 /* nVidia Arch 40 */
#define FB_ACCEL_XGI_VOLARI_V 47 /* XGI Volari V3XT, V5, V8 */
#define FB_ACCEL_XGI_VOLARI_Z 48 /* XGI Volari Z7 */
+#define FB_ACCEL_OMAP1610 49 /* TI OMAP16xx */
#define FB_ACCEL_NEOMAGIC_NM2070 90 /* NeoMagic NM2070 */
#define FB_ACCEL_NEOMAGIC_NM2090 91 /* NeoMagic NM2090 */
#define FB_ACCEL_NEOMAGIC_NM2093 92 /* NeoMagic NM2093 */
#define I2C_DRIVERID_UPD64031A 79 /* upd64031a video processor */
#define I2C_DRIVERID_SAA717X 80 /* saa717x video encoder */
+#define I2C_DRIVERID_MISC 99 /* Whatever until sorted out */
+
#define I2C_DRIVERID_I2CDEV 900
#define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */
#define I2C_DRIVERID_ALERT 903 /* SMBus Alert Responder Client */
#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
--- /dev/null
+/*
+ * linux/include/linux/netfilter_ipv4/ipt_IDLETIMER.h
+ *
+ * Header file for IP tables timer target module.
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Written by Timo Teräs <ext-timo.teras@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.
+ */
+
+#ifndef _IPT_TIMER_H
+#define _IPT_TIMER_H
+
+struct ipt_idletimer_info {
+ unsigned int timeout;
+};
+
+#endif
u16 x_min, x_max;
u16 y_min, y_max;
u16 pressure_min, pressure_max;
+
+ u16 debounce_max; /* max number of readings per sample */
+ u16 debounce_tol; /* tolerance used for filtering */
};
char *fs_names = __getname();
char *p;
char b[BDEVNAME_SIZE];
+ int i = 0;
get_fs_names(fs_names);
retry:
case -EINVAL:
continue;
}
+
+ printk("VFS: No root yet, retrying to mount root on %s (%s)\n",
+ root_device_name, __bdevname(ROOT_DEV, b));
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(10 * HZ);
+ if (i++ < 5)
+ goto retry;
+
/*
* Allow the user to distinguish between failed sys_open
* and bad superblock on root device.
#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 */
/* 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
tvec_base_t *base;
struct list_head *list;
struct timer_list *nte;
- unsigned long expires;
- unsigned long hr_expires = MAX_JIFFY_OFFSET;
+ unsigned long expires, hr_expires = MAX_JIFFY_OFFSET;
ktime_t hr_delta;
tvec_t *varray[4];
int i, j;
void do_timer(struct pt_regs *regs)
{
jiffies_64++;
- /* prevent loading jiffies before storing new jiffies_64 value. */
- barrier();
update_times();
softlockup_tick(regs);
}
#ifdef CONFIG_TIME_INTERPOLATION
-struct time_interpolator *time_interpolator __read_mostly;
-static struct time_interpolator *time_interpolator_list __read_mostly;
+struct time_interpolator *time_interpolator;
+static struct time_interpolator *time_interpolator_list;
static DEFINE_SPINLOCK(time_interpolator_lock);
static inline u64 time_interpolator_get_cycles(unsigned int src)
return x();
case TIME_SOURCE_MMIO64 :
- return readq_relaxed((void __iomem *)time_interpolator->addr);
+ return readq((void __iomem *) time_interpolator->addr);
case TIME_SOURCE_MMIO32 :
- return readl_relaxed((void __iomem *)time_interpolator->addr);
+ return readl((void __iomem *) time_interpolator->addr);
default: return get_cycles();
}
To compile it as a module, choose M here. If unsure, say N.
+config IP_NF_TARGET_IDLETIMER
+ tristate "IDLETIMER target support"
+ depends on IP_NF_IPTABLES
+ help
+ This option adds a `IDLETIMER' target. Each matching packet resets
+ the timer associated with input and/or output interfaces. Timer
+ expiry causes kobject uevent. Idle timer can be read via sysfs.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config IP_NF_NAT_SNMP_BASIC
tristate "Basic SNMP-ALG support (EXPERIMENTAL)"
depends on EXPERIMENTAL && IP_NF_NAT
obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o
+obj-$(CONFIG_IP_NF_TARGET_IDLETIMER) += ipt_IDLETIMER.o
obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
--- /dev/null
+/*
+ * linux/net/ipv4/netfilter/ipt_IDLETIMER.c
+ *
+ * Netfilter module to trigger a timer when packet matches.
+ * After timer expires a kevent will be sent.
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Written by Timo Teräs <ext-timo.teras@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.
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/notifier.h>
+#include <linux/netfilter.h>
+#include <linux/rtnetlink.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_IDLETIMER.h>
+#include <linux/kobject.h>
+
+#if 0
+#define DEBUGP(format, args...) printk("%s:%s:" format, \
+ __FILE__, __FUNCTION__ , ## args)
+#else
+#define DEBUGP(format, args...)
+#endif
+
+/*
+ * Internal timer management.
+ */
+static ssize_t utimer_attr_show(struct class_device *, char *buf);
+static ssize_t utimer_attr_store(struct class_device *,
+ const char *buf, size_t count);
+
+struct utimer_t {
+ char name[IFNAMSIZ];
+ struct list_head entry;
+ struct timer_list timer;
+};
+
+static LIST_HEAD(active_utimer_head);
+static DEFINE_SPINLOCK(list_lock);
+static CLASS_DEVICE_ATTR(idletimer, 0644, utimer_attr_show, utimer_attr_store);
+
+static void utimer_delete(struct utimer_t *timer)
+{
+ DEBUGP("Deleting timer '%s'\n", timer->name);
+
+ list_del(&timer->entry);
+ del_timer_sync(&timer->timer);
+ kfree(timer);
+}
+
+static void utimer_expired(unsigned long data)
+{
+ struct utimer_t *timer = (struct utimer_t *) data;
+ struct net_device *netdev;
+
+ DEBUGP("Timer '%s' expired\n", timer->name);
+ netdev = dev_get_by_name(timer->name);
+
+ spin_lock_bh(&list_lock);
+ utimer_delete(timer);
+ spin_unlock_bh(&list_lock);
+
+ if (netdev != NULL) {
+ kobject_uevent(&netdev->class_dev.kobj,
+ KOBJ_CHANGE);
+ dev_put(netdev);
+ }
+}
+
+static struct utimer_t *utimer_create(const char *name)
+{
+ struct utimer_t *timer;
+
+ timer = kmalloc(sizeof(struct utimer_t), GFP_ATOMIC);
+ if (timer == NULL)
+ return NULL;
+
+ list_add(&timer->entry, &active_utimer_head);
+ strlcpy(timer->name, name, sizeof(timer->name));
+
+ init_timer(&timer->timer);
+ timer->timer.function = utimer_expired;
+ timer->timer.data = (unsigned long) timer;
+
+ DEBUGP("Created timer '%s'\n", timer->name);
+
+ return timer;
+}
+
+static struct utimer_t *__utimer_find(const char *name)
+{
+ struct utimer_t *entry;
+
+ list_for_each_entry(entry, &active_utimer_head, entry) {
+ if (strcmp(name, entry->name) == 0) {
+ return entry;
+ }
+ }
+
+ return NULL;
+}
+
+static void utimer_modify(const char *name,
+ unsigned long expires)
+{
+ struct utimer_t *timer;
+
+ DEBUGP("Modifying timer '%s'\n", name);
+ spin_lock_bh(&list_lock);
+ timer = __utimer_find(name);
+ if (timer == NULL)
+ timer = utimer_create(name);
+ mod_timer(&timer->timer, expires);
+ spin_unlock_bh(&list_lock);
+}
+
+static ssize_t utimer_attr_show(struct class_device *dev, char *buf)
+{
+ struct utimer_t *timer;
+ unsigned long expires = 0;
+
+ spin_lock_bh(&list_lock);
+ timer = __utimer_find(dev->class_id);
+ if (timer)
+ expires = timer->timer.expires;
+ spin_unlock_bh(&list_lock);
+
+ if (expires)
+ return sprintf(buf, "%lu\n", (expires-jiffies) / HZ);
+
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t utimer_attr_store(struct class_device *dev,
+ const char *buf, size_t count)
+{
+ int expires;
+
+ if (sscanf(buf, "%d", &expires) == 1) {
+ if (expires > 0)
+ utimer_modify(dev->class_id,
+ jiffies+HZ*(unsigned long)expires);
+ }
+
+ return count;
+}
+
+static int utimer_notifier_call(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct net_device *dev = ptr;
+
+ switch (event) {
+ case NETDEV_UP:
+ DEBUGP("NETDEV_UP: %s\n", dev->name);
+ class_device_create_file(&dev->class_dev,
+ &class_device_attr_idletimer);
+ break;
+ case NETDEV_DOWN:
+ DEBUGP("NETDEV_DOWN: %s\n", dev->name);
+ class_device_remove_file(&dev->class_dev,
+ &class_device_attr_idletimer);
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block utimer_notifier_block = {
+ .notifier_call = utimer_notifier_call,
+};
+
+
+static int utimer_init(void)
+{
+ return register_netdevice_notifier(&utimer_notifier_block);
+}
+
+static void utimer_fini(void)
+{
+ struct utimer_t *entry, *next;
+ struct net_device *dev;
+
+ list_for_each_entry_safe(entry, next, &active_utimer_head, entry)
+ utimer_delete(entry);
+
+ rtnl_lock();
+ unregister_netdevice_notifier(&utimer_notifier_block);
+ for (dev = dev_base; dev; dev = dev->next)
+ utimer_notifier_call(&utimer_notifier_block,
+ NETDEV_DOWN, dev);
+ rtnl_unlock();
+}
+
+/*
+ * The actual iptables plugin.
+ */
+static unsigned int ipt_idletimer_target(struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const void *targinfo,
+ void *userinfo)
+{
+ struct ipt_idletimer_info *target = (struct ipt_idletimer_info*) targinfo;
+ unsigned long expires;
+
+ expires = jiffies + HZ*target->timeout;
+
+ if (in != NULL)
+ utimer_modify(in->name, expires);
+
+ if (out != NULL)
+ utimer_modify(out->name, expires);
+
+ return IPT_CONTINUE;
+}
+
+static int ipt_idletimer_checkentry(const char *tablename,
+ const void *e,
+ void *targinfo,
+ unsigned int targinfosize,
+ unsigned int hookmask)
+{
+ struct ipt_idletimer_info *info =
+ (struct ipt_idletimer_info *) targinfo;
+
+ if (targinfosize != IPT_ALIGN(sizeof(struct ipt_idletimer_info))) {
+ DEBUGP("targinfosize %u != 0\n", targinfosize);
+ return 0;
+ }
+
+ if (info->timeout == 0) {
+ DEBUGP("timeout value is zero\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+static struct ipt_target ipt_idletimer = {
+ .name = "IDLETIMER",
+ .target = ipt_idletimer_target,
+ .checkentry = ipt_idletimer_checkentry,
+ .me = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+ int ret;
+
+ ret = utimer_init();
+ if (ret)
+ return ret;
+
+ if (ipt_register_target(&ipt_idletimer)) {
+ utimer_fini();
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void __exit fini(void)
+{
+ ipt_unregister_target(&ipt_idletimer);
+ utimer_fini();
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_AUTHOR("Timo Teräs <ext-timo.teras@nokia.com>");
+MODULE_DESCRIPTION("iptables idletimer target module");
+MODULE_LICENSE("GPL");
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 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.
+
endmenu
obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o
snd-pxa2xx-ac97-objs := pxa2xx-ac97.o
+
+obj-$(CONFIG_SND_OMAP_AIC23) += snd-omap-aic23.o
+snd-omap-aic23-objs := omap-aic23.o omap-alsa-dma.o omap-alsa-mixer.o
--- /dev/null
+/*
+ * sound/arm/omap-aic23.c
+ *
+ * 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
+ *
+ * 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/config.h>
+#include <sound/driver.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/aic23.h>
+#include <asm/arch/mcbsp.h>
+#include <asm/arch/clock.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/memalloc.h>
+
+#include "omap-alsa-dma.h"
+#include "omap-aic23.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define ADEBUG() printk("XXX Alsa debug f:%s, l:%d\n", __FUNCTION__, __LINE__)
+#else
+#define ADEBUG() /* nop */
+#endif
+
+/* Define to set the AIC23 as the master w.r.t McBSP */
+#define AIC23_MASTER
+
+/*
+ * AUDIO related MACROS
+ */
+#define DEFAULT_BITPERSAMPLE 16
+#define AUDIO_RATE_DEFAULT 44100
+#define AUDIO_MCBSP OMAP_MCBSP1
+#define NUMBER_SAMPLE_RATES_SUPPORTED 10
+
+
+MODULE_AUTHOR("Daniel Petrini, David Cohen, Anderson Briglia - INdT");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("OMAP AIC23 driver for ALSA");
+MODULE_SUPPORTED_DEVICE("{{AIC23,OMAP AIC23}}");
+MODULE_ALIAS("omap_mcbsp.1");
+
+static char *id = NULL;
+MODULE_PARM_DESC(id, "OMAP OSK ALSA Driver for AIC23 chip.");
+
+static struct snd_card_omap_aic23 *omap_aic23 = NULL;
+
+static struct clk *aic23_mclk = 0;
+
+struct sample_rate_rate_reg_info {
+ u8 control; /* SR3, SR2, SR1, SR0 and BOSR */
+ u8 divider; /* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */
+};
+
+/*
+ * 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 const struct sample_rate_rate_reg_info
+ rate_reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
+ {0x06, 1}, /* 4000 */
+ {0x06, 0}, /* 8000 */
+ {0x0C, 1}, /* 16000 */
+ {0x11, 1}, /* 22050 */
+ {0x00, 1}, /* 24000 */
+ {0x0C, 0}, /* 32000 */
+ {0x11, 0}, /* 44100 */
+ {0x00, 0}, /* 48000 */
+ {0x1F, 0}, /* 88200 */
+ {0x0E, 0}, /* 96000 */
+};
+
+/*
+ * mcbsp configuration structure
+ */
+static struct omap_mcbsp_reg_cfg initial_config_mcbsp = {
+ .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 snd_pcm_hw_constraint_list_t hw_constraints_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+};
+
+/*
+ * 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;
+}
+
+/*
+ * Codec/mcbsp init and configuration section
+ * codec dependent code.
+ */
+
+/*
+ * Sample rate changing
+ */
+static void omap_aic23_set_samplerate(struct snd_card_omap_aic23
+ *omap_aic23, 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 ((rates[count] != 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);
+
+ omap_aic23->samplerate = rate;
+}
+
+static 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);
+
+}
+
+static void omap_aic23_audio_init(struct snd_card_omap_aic23 *omap_aic23)
+{
+ /* Setup DMA stuff */
+ omap_aic23->s[SNDRV_PCM_STREAM_PLAYBACK].id = "Alsa AIC23 out";
+ omap_aic23->s[SNDRV_PCM_STREAM_PLAYBACK].stream_id =
+ SNDRV_PCM_STREAM_PLAYBACK;
+ omap_aic23->s[SNDRV_PCM_STREAM_PLAYBACK].dma_dev =
+ OMAP_DMA_MCBSP1_TX;
+ omap_aic23->s[SNDRV_PCM_STREAM_PLAYBACK].hw_start =
+ audio_ifc_start;
+ omap_aic23->s[SNDRV_PCM_STREAM_PLAYBACK].hw_stop =
+ audio_ifc_stop;
+
+ omap_aic23->s[SNDRV_PCM_STREAM_CAPTURE].id = "Alsa AIC23 in";
+ omap_aic23->s[SNDRV_PCM_STREAM_CAPTURE].stream_id =
+ SNDRV_PCM_STREAM_CAPTURE;
+ omap_aic23->s[SNDRV_PCM_STREAM_CAPTURE].dma_dev =
+ OMAP_DMA_MCBSP1_RX;
+ omap_aic23->s[SNDRV_PCM_STREAM_CAPTURE].hw_start =
+ audio_ifc_start;
+ omap_aic23->s[SNDRV_PCM_STREAM_CAPTURE].hw_stop =
+ audio_ifc_stop;
+
+ /* configuring the McBSP */
+ omap_mcbsp_request(AUDIO_MCBSP);
+
+ /* if configured, then stop mcbsp */
+ omap_mcbsp_stop(AUDIO_MCBSP);
+
+ omap_mcbsp_config(AUDIO_MCBSP, &initial_config_mcbsp);
+ omap_mcbsp_start(AUDIO_MCBSP);
+ aic23_configure();
+}
+
+/*
+ * DMA functions
+ * Depends on omap-aic23-dma.c functions and (omap) dma.c
+ *
+ */
+#define DMA_BUF_SIZE 1024 * 8
+
+static int audio_dma_request(struct audio_stream *s,
+ void (*callback) (void *))
+{
+ int err;
+
+ err = omap_request_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;
+
+ err = omap_free_sound_dma(s, &s->lch);
+ if (err < 0)
+ printk(KERN_ERR "Unable to free audio dma channels!\n");
+ return err;
+}
+
+/*
+ * This function should calculate the current position of the dma in the
+ * buffer. It will help alsa middle layer to continue update the buffer.
+ * Its correctness is crucial for good functioning.
+ */
+static u_int audio_get_dma_pos(struct audio_stream *s)
+{
+ snd_pcm_substream_t *substream = s->stream;
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ unsigned int offset;
+ unsigned long flags;
+ dma_addr_t count;
+ ADEBUG();
+
+ /* this must be called w/ interrupts locked as requested in dma.c */
+ spin_lock_irqsave(&s->dma_lock, flags);
+
+ /* For the current period let's see where we are */
+ count = omap_get_dma_src_addr_counter(s->lch[s->dma_q_head]);
+
+ spin_unlock_irqrestore(&s->dma_lock, flags);
+
+ /* Now, the position related to the end of that period */
+ offset = bytes_to_frames(runtime, s->offset) - bytes_to_frames(runtime, count);
+
+ if (offset >= runtime->buffer_size || offset < 0)
+ 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_audio_stop_dma(s);
+
+ omap_clear_sound_dma(s);
+
+ spin_unlock_irqrestore(&s->dma_lock, flags);
+}
+
+/*
+ * Main dma routine, requests dma according where you are in main alsa buffer
+ */
+static void audio_process_dma(struct audio_stream *s)
+{
+ snd_pcm_substream_t *substream = s->stream;
+ snd_pcm_runtime_t *runtime;
+ unsigned int dma_size;
+ unsigned int offset;
+ int ret;
+
+ 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,);
+ ret =
+ omap_start_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 audio_dma_callback(void *data)
+{
+ struct audio_stream *s = data;
+
+ /*
+ * 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_aic23_trigger(snd_pcm_substream_t * substream, int cmd)
+{
+ struct snd_card_omap_aic23 *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_aic23_prepare(snd_pcm_substream_t * substream)
+{
+ struct snd_card_omap_aic23 *chip =
+ snd_pcm_substream_chip(substream);
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ struct audio_stream *s = &chip->s[substream->pstr->stream];
+
+ /* set requested samplerate */
+ omap_aic23_set_samplerate(chip, runtime->rate);
+
+ s->period = 0;
+ s->periods = 0;
+
+ return 0;
+}
+
+static snd_pcm_uframes_t snd_omap_aic23_pointer(snd_pcm_substream_t *
+ substream)
+{
+ struct snd_card_omap_aic23 *chip =
+ snd_pcm_substream_chip(substream);
+
+ return audio_get_dma_pos(&chip->s[substream->pstr->stream]);
+}
+
+/* Hardware capabilities */
+
+static snd_pcm_hardware_t snd_omap_aic23_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,
+};
+
+static snd_pcm_hardware_t snd_omap_aic23_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 int snd_card_omap_aic23_open(snd_pcm_substream_t * substream)
+{
+ struct snd_card_omap_aic23 *chip =
+ snd_pcm_substream_chip(substream);
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ int stream_id = substream->pstr->stream;
+ int err;
+ ADEBUG();
+
+ chip->s[stream_id].stream = substream;
+
+ omap_aic23_clock_on();
+
+ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
+ runtime->hw = snd_omap_aic23_playback;
+ else
+ runtime->hw = snd_omap_aic23_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,
+ &hw_constraints_rates)) < 0)
+ return err;
+
+ return 0;
+}
+
+static int snd_card_omap_aic23_close(snd_pcm_substream_t * substream)
+{
+ struct snd_card_omap_aic23 *chip =
+ snd_pcm_substream_chip(substream);
+ ADEBUG();
+
+ omap_aic23_clock_off();
+ chip->s[substream->pstr->stream].stream = NULL;
+
+ return 0;
+}
+
+/* HW params & free */
+
+static int snd_omap_aic23_hw_params(snd_pcm_substream_t * substream,
+ snd_pcm_hw_params_t * hw_params)
+{
+ return snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+}
+
+static int snd_omap_aic23_hw_free(snd_pcm_substream_t * substream)
+{
+ return snd_pcm_lib_free_pages(substream);
+}
+
+/* pcm operations */
+
+static snd_pcm_ops_t snd_card_omap_aic23_playback_ops = {
+ .open = snd_card_omap_aic23_open,
+ .close = snd_card_omap_aic23_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_omap_aic23_hw_params,
+ .hw_free = snd_omap_aic23_hw_free,
+ .prepare = snd_omap_aic23_prepare,
+ .trigger = snd_omap_aic23_trigger,
+ .pointer = snd_omap_aic23_pointer,
+};
+
+static snd_pcm_ops_t snd_card_omap_aic23_capture_ops = {
+ .open = snd_card_omap_aic23_open,
+ .close = snd_card_omap_aic23_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_omap_aic23_hw_params,
+ .hw_free = snd_omap_aic23_hw_free,
+ .prepare = snd_omap_aic23_prepare,
+ .trigger = snd_omap_aic23_trigger,
+ .pointer = snd_omap_aic23_pointer,
+};
+
+/*
+ * Alsa init and exit section
+ *
+ * Inits pcm alsa structures, allocate the alsa buffer, suspend, resume
+ */
+static int __init snd_card_omap_aic23_pcm(struct snd_card_omap_aic23
+ *omap_aic23, int device)
+{
+ snd_pcm_t *pcm;
+ int err;
+ ADEBUG();
+
+ if ((err =
+ snd_pcm_new(omap_aic23->card, "AIC23 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_aic23_playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+ &snd_card_omap_aic23_capture_ops);
+ pcm->private_data = omap_aic23;
+ pcm->info_flags = 0;
+ strcpy(pcm->name, "omap aic23 pcm");
+
+ omap_aic23_audio_init(omap_aic23);
+
+ /* setup DMA controller */
+ audio_dma_request(&omap_aic23->s[SNDRV_PCM_STREAM_PLAYBACK],
+ audio_dma_callback);
+ audio_dma_request(&omap_aic23->s[SNDRV_PCM_STREAM_CAPTURE],
+ audio_dma_callback);
+
+ omap_aic23->pcm = pcm;
+
+ return 0;
+}
+
+
+#ifdef CONFIG_PM
+
+static int snd_omap_aic23_suspend(snd_card_t * card, pm_message_t state)
+{
+ struct snd_card_omap_aic23 *chip = card->private_data;
+ ADEBUG();
+
+ 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 */
+ omap_aic23_clock_off();
+ snd_omap_suspend_mixer();
+ }
+
+ return 0;
+}
+
+/*
+ * Prepare hardware for resume
+ */
+static int snd_omap_aic23_resume(snd_card_t * card)
+{
+ struct snd_card_omap_aic23 *chip = card->private_data;
+ ADEBUG();
+
+ if (chip->card->power_state != SNDRV_CTL_POWER_D0) {
+ snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
+ omap_aic23_clock_on();
+ snd_omap_resume_mixer();
+ }
+
+ return 0;
+}
+
+/*
+ * Driver suspend/resume - calls alsa functions. Some hints from aaci.c
+ */
+static int omap_aic23_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ snd_card_t *card = platform_get_drvdata(pdev);
+
+ if (card->power_state != SNDRV_CTL_POWER_D3hot) {
+ snd_omap_aic23_suspend(card, PMSG_SUSPEND);
+ }
+ return 0;
+}
+
+static int omap_aic23_resume(struct platform_device *pdev)
+{
+ snd_card_t *card = platform_get_drvdata(pdev);
+
+ if (card->power_state != SNDRV_CTL_POWER_D0) {
+ snd_omap_aic23_resume(card);
+ }
+ return 0;
+}
+
+#else
+#define snd_omap_aic23_suspend NULL
+#define snd_omap_aic23_resume NULL
+#define omap_aic23_suspend NULL
+#define omap_aic23_resume NULL
+
+#endif /* CONFIG_PM */
+
+/*
+ */
+void snd_omap_aic23_free(snd_card_t * card)
+{
+ struct snd_card_omap_aic23 *chip = card->private_data;
+ ADEBUG();
+
+ /*
+ * Turn off codec after it is done.
+ * Can't do it immediately, since it may still have
+ * buffered data.
+ */
+ 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);
+
+ audio_dma_free(&chip->s[SNDRV_PCM_STREAM_PLAYBACK]);
+ audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]);
+}
+
+/*
+ * Omap MCBSP clock 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.
+ */
+#define CODEC_CLOCK 12000000
+#define AUDIO_RATE_DEFAULT 44100
+
+/*
+ * Do clock framework mclk search
+ */
+static __init void omap_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 omap_aic23_clock_on(void)
+{
+ 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);
+
+ 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 omap_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;
+}
+
+/* module init & exit */
+
+/*
+ * Inits alsa soudcard structure
+ */
+static int __init snd_omap_aic23_probe(struct platform_device *pdev)
+{
+ int err = 0;
+ snd_card_t *card;
+ ADEBUG();
+
+ /* gets clock from clock framework */
+ omap_aic23_clock_setup();
+
+ /* register the soundcard */
+ card = snd_card_new(-1, id, THIS_MODULE, sizeof(omap_aic23));
+ if (card == NULL)
+ return -ENOMEM;
+
+ omap_aic23 = kcalloc(1, sizeof(*omap_aic23), GFP_KERNEL);
+ if (omap_aic23 == NULL)
+ return -ENOMEM;
+
+ card->private_data = (void *) omap_aic23;
+ card->private_free = snd_omap_aic23_free;
+
+ omap_aic23->card = card;
+ omap_aic23->samplerate = AUDIO_RATE_DEFAULT;
+
+ spin_lock_init(&omap_aic23->s[0].dma_lock);
+ spin_lock_init(&omap_aic23->s[1].dma_lock);
+
+ /* mixer */
+ if ((err = snd_omap_mixer(omap_aic23)) < 0)
+ goto nodev;
+
+ /* PCM */
+ if ((err = snd_card_omap_aic23_pcm(omap_aic23, 0)) < 0)
+ goto nodev;
+
+ strcpy(card->driver, "AIC23");
+ strcpy(card->shortname, "OSK AIC23");
+ sprintf(card->longname, "OMAP OSK with AIC23");
+
+ snd_omap_init_mixer();
+
+ snd_card_set_dev(card, &pdev->dev);
+
+ if ((err = snd_card_register(card)) == 0) {
+ printk(KERN_INFO "OSK audio support initialized\n");
+ platform_set_drvdata(pdev, card);
+ return 0;
+ }
+
+nodev:
+ snd_omap_aic23_free(card);
+
+ return err;
+}
+
+static int snd_omap_aic23_remove(struct platform_device *pdev)
+{
+ snd_card_t *card = platform_get_drvdata(pdev);
+ struct snd_card_omap_aic23 *chip = card->private_data;
+
+ snd_card_free(card);
+
+ omap_aic23 = NULL;
+ card->private_data = NULL;
+ kfree(chip);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+
+}
+
+static struct platform_driver omap_alsa_driver = {
+ .probe = snd_omap_aic23_probe,
+ .remove = snd_omap_aic23_remove,
+ .suspend = omap_aic23_suspend,
+ .resume = omap_aic23_resume,
+ .driver = {
+ .name = "omap_mcbsp",
+ },
+};
+
+static int __init omap_aic23_init(void)
+{
+ int err;
+ ADEBUG();
+
+ err = platform_driver_register(&omap_alsa_driver);
+
+ return err;
+}
+
+static void __exit omap_aic23_exit(void)
+{
+ ADEBUG();
+
+ platform_driver_unregister(&omap_alsa_driver);
+}
+
+module_init(omap_aic23_init);
+module_exit(omap_aic23_exit);
--- /dev/null
+/*
+ * sound/arm/omap-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
+ *
+ * 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/25 INdT-10LE Kernel Team - Alsa driver for omap osk,
+ * original version based in sa1100 driver
+ * and omap oss driver.
+ *
+ * 2005-12-18 Dirk Behme - Added L/R Channel Interchange fix as proposed by Ajaya Babu
+ */
+
+#ifndef __OMAP_AIC23_H
+#define __OMAP_AIC23_H
+
+#include <sound/driver.h>
+#include <asm/arch/dma.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+
+#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
+
+/*
+ * Buffer management for alsa and dma
+ */
+struct audio_stream {
+ char *id; /* identification string */
+ int stream_id; /* numeric identification */
+ int dma_dev; /* dma number of that device */
+ int *lch; /* Chain of channels this stream is linked to */
+ 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 */
+ int active:1; /* we are using this stream for transfer now */
+ int period; /* current transfer period */
+ int periods; /* current count of periods registerd in the DMA engine */
+ spinlock_t dma_lock; /* for locking in DMA operations */
+ snd_pcm_substream_t *stream; /* the pcm stream */
+ unsigned linked:1; /* dma channels linked */
+ int offset; /* store start position of the last period in the alsa buffer */
+ int (*hw_start)(void); /* interface to start HW interface, e.g. McBSP */
+ int (*hw_stop)(void); /* interface to stop HW interface, e.g. McBSP */
+};
+
+/*
+ * Alsa card structure for aic23
+ */
+struct snd_card_omap_aic23 {
+ snd_card_t *card;
+ snd_pcm_t *pcm;
+ long samplerate;
+ struct audio_stream s[2]; /* playback & capture */
+};
+
+/*********** Function Prototypes *************************/
+
+void audio_dma_callback(void *);
+int snd_omap_mixer(struct snd_card_omap_aic23 *);
+void snd_omap_init_mixer(void);
+/* Clock functions */
+int omap_aic23_clock_on(void);
+int omap_aic23_clock_off(void);
+
+#ifdef CONFIG_PM
+void snd_omap_suspend_mixer(void);
+void snd_omap_resume_mixer(void);
+#endif
+
+/* Codec AIC23 */
+#if defined(CONFIG_SENSORS_TLV320AIC23) || defined (CONFIG_SENSORS_TLV320AIC23_MODULE)
+
+extern int tlv320aic23_write_value(u8 reg, u16 value);
+
+/* TLV320AIC23 is a write only device */
+static __inline__ void audio_aic23_write(u8 address, u16 data)
+{
+ tlv320aic23_write_value(address, data);
+}
+
+#endif /* CONFIG_SENSORS_TLV320AIC23 */
+
+#endif
--- /dev/null
+/*
+ * sound/arm/omap-alsa-dma.c
+ *
+ * Common audio DMA handling for the OMAP processors
+ *
+ * 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/config.h>
+#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 "omap-aic23.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);
+
+/* 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_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_omap1510())
+ 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_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_omap1510())
+ 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_audio_stop_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_sound_dma(struct audio_stream * s)
+{
+ FN_IN;
+ omap_clear_dma(s->lch[s->dma_q_head]);
+ FN_OUT(0);
+ return;
+}
+
+/*********************************** MODULE FUNCTIONS DEFINTIONS ***********************/
+
+#ifdef OMAP1610_MCBSP1_BASE
+#undef OMAP1610_MCBSP1_BASE
+#endif
+#define OMAP1610_MCBSP1_BASE 0xE1011000
+
+/***************************************************************************************
+ *
+ * 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,
+ (OMAP1610_MCBSP1_BASE + 0x806),
+ 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,
+ (OMAP1610_MCBSP1_BASE + 0x802),
+ 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 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_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)
+ audio_dma_callback(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_sound_dma);
+EXPORT_SYMBOL(omap_clear_sound_dma);
+EXPORT_SYMBOL(omap_request_sound_dma);
+EXPORT_SYMBOL(omap_free_sound_dma);
+EXPORT_SYMBOL(omap_audio_stop_dma);
--- /dev/null
+/*
+ * linux/sound/arm/omap-alsa-dma.h
+ *
+ * Common audio DMA handling for the OMAP processors
+ *
+ * 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 "omap-aic23.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);
+
+/**************** ARCH SPECIFIC FUNCIONS *******************************************/
+
+void omap_clear_sound_dma(struct audio_stream * 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);
+
+int omap_start_sound_dma(struct audio_stream *s, dma_addr_t dma_ptr,
+ u_int dma_size);
+
+void omap_audio_stop_dma(struct audio_stream *s);
+
+#endif
--- /dev/null
+/*
+ * sound/arm/omap-alsa-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 <linux/config.h>
+#include <sound/driver.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/aic23.h>
+
+#include "omap-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 __inline__ void audio_aic23_write(u8, u16);
+
+#define MIXER_NAME "Mixer AIC23"
+#define SND_OMAP_WRITE(reg, val) audio_aic23_write(reg, val)
+
+#endif
+
+/* Callback Functions */
+#define OMAP_BOOL(xname, xindex, reg, reg_index, mask, invert) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_omap_info_bool, \
+ .get = snd_omap_get_bool, \
+ .put = snd_omap_put_bool, \
+ .private_value = reg | (reg_index << 8) | (invert << 10) | (mask << 12) \
+}
+
+#define OMAP_MUX(xname, reg, reg_index, mask) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .info = snd_omap_info_mux, \
+ .get = snd_omap_get_mux, \
+ .put = snd_omap_put_mux, \
+ .private_value = reg | (reg_index << 8) | (mask << 10) \
+}
+
+#define OMAP_SINGLE(xname, xindex, reg, reg_index, reg_val, mask) \
+{\
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_omap_info_single, \
+ .get = snd_omap_get_single, \
+ .put = snd_omap_put_single, \
+ .private_value = reg | (reg_val << 8) | (reg_index << 16) | (mask << 18) \
+}
+
+#define OMAP_DOUBLE(xname, xindex, left_reg, right_reg, reg_index, mask) \
+{\
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_omap_info_double, \
+ .get = snd_omap_get_double, \
+ .put = snd_omap_put_double, \
+ .private_value = left_reg | (right_reg << 8) | (reg_index << 16) | (mask << 18) \
+}
+
+/* Local Registers */
+enum snd_device_index {
+ PCM_INDEX = 0,
+ LINE_INDEX,
+ AAC_INDEX, /* Analog Audio Control: reg = l_reg */
+};
+
+struct {
+ u16 l_reg;
+ u16 r_reg;
+ u8 sw;
+} omap_regs[3];
+
+#ifdef CONFIG_PM
+struct {
+ u16 l_reg;
+ u16 r_reg;
+ u8 sw;
+} omap_pm_regs[3];
+#endif
+
+u16 snd_sidetone[6] = {
+ SIDETONE_18,
+ SIDETONE_12,
+ SIDETONE_9,
+ SIDETONE_6,
+ SIDETONE_0,
+ 0
+};
+
+/* Begin Bool Functions */
+
+static int snd_omap_info_bool(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+
+ return 0;
+}
+
+static int snd_omap_get_bool(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ int mic_index = (kcontrol->private_value >> 8) & 0x03;
+ u16 mask = (kcontrol->private_value >> 12) & 0xff;
+ int invert = (kcontrol->private_value >> 10) & 0x03;
+
+ if (invert)
+ ucontrol->value.integer.value[0] = (omap_regs[mic_index].l_reg & mask) ? 0 : 1;
+ else
+ ucontrol->value.integer.value[0] = (omap_regs[mic_index].l_reg & mask) ? 1 : 0;
+
+ return 0;
+}
+
+static int snd_omap_put_bool(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ int mic_index = (kcontrol->private_value >> 8) & 0x03;
+ u16 mask = (kcontrol->private_value >> 12) & 0xff;
+ u16 reg = kcontrol->private_value & 0xff;
+ int invert = (kcontrol->private_value >> 10) & 0x03;
+
+ int changed = 1;
+
+ if (ucontrol->value.integer.value[0]) /* XOR */
+ if (invert)
+ omap_regs[mic_index].l_reg &= ~mask;
+ else
+ omap_regs[mic_index].l_reg |= mask;
+ else
+ if (invert)
+ omap_regs[mic_index].l_reg |= mask;
+ else
+ omap_regs[mic_index].l_reg &= ~mask;
+
+ SND_OMAP_WRITE(reg, omap_regs[mic_index].l_reg);
+
+ return changed;
+}
+
+/* End Bool Functions */
+
+/* Begin Mux Functions */
+
+static int snd_omap_info_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+ /* Mic = 0
+ * Line = 1 */
+ static char *texts[2] = { "Mic", "Line" };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+
+ if (uinfo->value.enumerated.item > 1)
+ uinfo->value.enumerated.item = 1;
+
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+
+ return 0;
+}
+
+static int snd_omap_get_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ u16 mask = (kcontrol->private_value >> 10) & 0xff;
+ int mux_index = (kcontrol->private_value >> 8) & 0x03;
+
+ ucontrol->value.enumerated.item[0] = (omap_regs[mux_index].l_reg & mask) ? 0 /* Mic */ : 1 /* Line */;
+
+ return 0;
+}
+
+static int snd_omap_put_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ u16 reg = kcontrol->private_value & 0xff;
+ u16 mask = (kcontrol->private_value >> 10) & 0xff;
+ int mux_index = (kcontrol->private_value >> 8) & 0x03;
+
+ int changed = 1;
+
+ if (!ucontrol->value.integer.value[0])
+ omap_regs[mux_index].l_reg |= mask; /* AIC23: Mic */
+ else
+ omap_regs[mux_index].l_reg &= ~mask; /* AIC23: Line */
+
+ SND_OMAP_WRITE(reg, omap_regs[mux_index].l_reg);
+
+ return changed;
+}
+
+/* End Mux Functions */
+
+/* Begin Single Functions */
+
+static int snd_omap_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+ int mask = (kcontrol->private_value >> 18) & 0xff;
+ int reg_val = (kcontrol->private_value >> 8) & 0xff;
+
+ uinfo->type = mask ? SNDRV_CTL_ELEM_TYPE_INTEGER : SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = reg_val-1;
+
+ return 0;
+}
+
+static int snd_omap_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ u16 reg_val = (kcontrol->private_value >> 8) & 0xff;
+
+ ucontrol->value.integer.value[0] = snd_sidetone[reg_val];
+
+ return 0;
+}
+
+static int snd_omap_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ u16 reg_index = (kcontrol->private_value >> 16) & 0x03;
+ u16 mask = (kcontrol->private_value >> 18) & 0x1ff;
+ u16 reg = kcontrol->private_value & 0xff;
+ u16 reg_val = (kcontrol->private_value >> 8) & 0xff;
+
+ int changed = 0;
+
+ /* Volume */
+ if ((omap_regs[reg_index].l_reg != (ucontrol->value.integer.value[0] & mask)))
+ {
+ changed = 1;
+
+ omap_regs[reg_index].l_reg &= ~mask;
+ omap_regs[reg_index].l_reg |= snd_sidetone[ucontrol->value.integer.value[0]];
+
+ snd_sidetone[reg_val] = ucontrol->value.integer.value[0];
+ SND_OMAP_WRITE(reg, omap_regs[reg_index].l_reg);
+ }
+ else
+ changed = 0;
+
+ return changed;
+}
+
+/* End Single Functions */
+
+/* Begin Double Functions */
+
+static int snd_omap_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+ /* mask == 0 : Switch
+ * mask != 0 : Volume */
+ int mask = (kcontrol->private_value >> 18) & 0xff;
+
+ uinfo->type = mask ? SNDRV_CTL_ELEM_TYPE_INTEGER : SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = mask ? 2 : 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = mask ? mask : 1;
+
+ return 0;
+}
+
+static int snd_omap_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ /* mask == 0 : Switch
+ * mask != 0 : Volume */
+ int mask = (kcontrol->private_value >> 18) & 0xff;
+ int vol_index = (kcontrol->private_value >> 16) & 0x03;
+
+ if (!mask)
+ /* Switch */
+ ucontrol->value.integer.value[0] = omap_regs[vol_index].sw;
+ else
+ {
+ /* Volume */
+ ucontrol->value.integer.value[0] = omap_regs[vol_index].l_reg;
+ ucontrol->value.integer.value[1] = omap_regs[vol_index].r_reg;
+ }
+
+ return 0;
+}
+
+static int snd_omap_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ /* mask == 0 : Switch
+ * mask != 0 : Volume */
+ int vol_index = (kcontrol->private_value >> 16) & 0x03;
+ int mask = (kcontrol->private_value >> 18) & 0xff;
+ int left_reg = kcontrol->private_value & 0xff;
+ int right_reg = (kcontrol->private_value >> 8) & 0xff;
+
+ int changed = 0;
+
+ if (!mask)
+ {
+ /* Switch */
+ if (!ucontrol->value.integer.value[0])
+ {
+ SND_OMAP_WRITE(left_reg, 0x00);
+ SND_OMAP_WRITE(right_reg, 0x00);
+ }
+ else
+ {
+ SND_OMAP_WRITE(left_reg, omap_regs[vol_index].l_reg);
+ SND_OMAP_WRITE(right_reg, omap_regs[vol_index].r_reg);
+ }
+ changed = 1;
+ omap_regs[vol_index].sw = ucontrol->value.integer.value[0];
+ }
+ else
+ {
+ /* Volume */
+ if ((omap_regs[vol_index].l_reg != (ucontrol->value.integer.value[0] & mask)) ||
+ (omap_regs[vol_index].r_reg != (ucontrol->value.integer.value[1] & mask)))
+ {
+ changed = 1;
+
+ omap_regs[vol_index].l_reg &= ~mask;
+ omap_regs[vol_index].r_reg &= ~mask;
+ omap_regs[vol_index].l_reg |= (ucontrol->value.integer.value[0] & mask);
+ omap_regs[vol_index].r_reg |= (ucontrol->value.integer.value[1] & mask);
+ if (omap_regs[vol_index].sw)
+ {
+ /* write to registers only if sw is actived */
+ SND_OMAP_WRITE(left_reg, omap_regs[vol_index].l_reg);
+ SND_OMAP_WRITE(right_reg, omap_regs[vol_index].r_reg);
+ }
+ }
+ else
+ changed = 0;
+ }
+
+ return changed;
+}
+
+/* End Double Functions */
+
+static snd_kcontrol_new_t snd_omap_controls[] = {
+ OMAP_DOUBLE("PCM Playback Switch", 0, LEFT_CHANNEL_VOLUME_ADDR, RIGHT_CHANNEL_VOLUME_ADDR,
+ PCM_INDEX, 0x00),
+ OMAP_DOUBLE("PCM Playback Volume", 0, LEFT_CHANNEL_VOLUME_ADDR, RIGHT_CHANNEL_VOLUME_ADDR,
+ PCM_INDEX, OUTPUT_VOLUME_MASK),
+ OMAP_BOOL("Line Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, BYPASS_ON, 0),
+ OMAP_DOUBLE("Line Capture Switch", 0, LEFT_LINE_VOLUME_ADDR, RIGHT_LINE_VOLUME_ADDR,
+ LINE_INDEX, 0x00),
+ OMAP_DOUBLE("Line Capture Volume", 0, LEFT_LINE_VOLUME_ADDR, RIGHT_LINE_VOLUME_ADDR,
+ LINE_INDEX, INPUT_VOLUME_MASK),
+ OMAP_BOOL("Mic Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, STE_ENABLED, 0),
+ OMAP_SINGLE("Mic Playback Volume", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, 5, SIDETONE_MASK),
+ OMAP_BOOL("Mic Capture Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, MICM_MUTED, 1),
+ OMAP_BOOL("Mic Booster Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, MICB_20DB, 0),
+ OMAP_MUX("Capture Source", ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, INSEL_MIC),
+};
+
+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);
+}
+
+#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
+
+int snd_omap_mixer(struct snd_card_omap_aic23 *chip)
+{
+ snd_card_t *card;
+ unsigned int idx;
+ int err;
+
+ snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
+
+ card = chip->card;
+
+ strcpy(card->mixername, MIXER_NAME);
+
+ /* Registering alsa mixer controls */
+ for (idx = 0; idx < ARRAY_SIZE(snd_omap_controls); idx++)
+ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_omap_controls[idx], chip))) < 0)
+ return err;
+
+ return 0;
+}
+
#
# Prompt user for primary drivers.
+config SOUND_OMAP
+ tristate "OMAP Sound Driver"
+ depends on SOUND_PRIME!=n && SOUND && ARCH_OMAP
+ ---help---
+ OMAP Audio driver
+
+config SOUND_OMAP_TSC2101
+ tristate "TSC2101 Stereo Codec"
+ depends on SOUND_OMAP && ( MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4 || MACH_OMAP_APOLLON)
+ select OMAP_TSC2101 if ( MACH_OMAP_H2 || MACH_OMAP_H3 )
+ select OMAP_UWIRE if ARCH_OMAP1
+ ---help---
+ Tsc2101 Audio Codec Driver for OMAP will be enabled.
+ Will also Enable the following:
+ case OMAP1:
+ 1. uWire Driver based on Platform
+ 2. TSC2101 Glue driver
+ case OMAP2:
+ 1. McSPI Driver based on Platform
+ 2. TSC2101 Glue driver
+
+config SOUND_OMAP_AIC23
+ tristate "AIC23 Stereo Codec"
+ depends on SOUND_OMAP && ( MACH_OMAP_INNOVATOR || MACH_OMAP_OSK )
+ select SENSORS_TLV320AIC23 if ARCH_OMAP
+ ---help---
+ AIC23 Audio Codec Driver for OMAP will be enabled.
+ Additionally, AIC23 I2C support is enabled.
+
config OBSOLETE_OSS_DRIVER
bool "Obsolete OSS drivers"
depends on SOUND_PRIME
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
--- /dev/null
+/*
+ * 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 <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,
+ .sem = __SEMAPHORE_INIT(aic23_state.sem, 1),
+};
+
+/* This will be defined in the audio.h */
+static struct file_operations *omap_audio_fops;
+
+extern int tlv320aic23_write_value(u8 reg, u16 value);
+
+/* TLV320AIC23 is a write only device */
+static __inline__ void audio_aic23_write(u8 address, u16 data)
+{
+ tlv320aic23_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;
+
+ 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");
--- /dev/null
+/*
+ * 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/config.h>
+#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_omap1510())
+ 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_omap1510())
+ 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_omap1510() && 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_omap1510() || 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_omap1510() || 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_omap1510() || 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_omap1510())
+ 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);
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 <asm/semaphore.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,
+ .sem = __SEMAPHORE_INIT(tsc2101_state.sem, 1),
+};
+
+/* 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;
+
+ /* 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");
--- /dev/null
+/*
+ * 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/config.h>
+#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 <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/semaphore.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));
+ sema_init(&audio_state.sem, 1);
+
+ 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;
+ }
+
+ down(&state->sem);
+
+ /* 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:
+ up(&state->sem);
+ 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;
+
+ down(&state->sem);
+
+ 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);
+ }
+
+ up(&state->sem);
+
+ 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");
--- /dev/null
+/*
+ * 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 semaphore sem; /* 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 */